diff options
Diffstat (limited to 'source/gameengine')
544 files changed, 37656 insertions, 29106 deletions
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index 9fbdc3fa1c9..ae46f880711 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -61,62 +61,81 @@ #include "RAS_ListRasterizer.h" #include "NG_LoopBackNetworkDeviceInterface.h" -#include "SND_DeviceManager.h" #include "SYS_System.h" - /***/ +#include "GPU_extensions.h" +#include "Value.h" + + +#ifdef __cplusplus +extern "C" { +#endif + /***/ #include "DNA_view3d_types.h" #include "DNA_screen_types.h" +#include "DNA_windowmanager_types.h" #include "BKE_global.h" +#include "BKE_report.h" + #include "BKE_utildefines.h" -#include "BIF_screen.h" -#include "BIF_scrarea.h" +//XXX #include "BIF_screen.h" +//XXX #include "BIF_scrarea.h" -#include "BKE_main.h" +#include "BKE_main.h" #include "BLI_blenlib.h" #include "BLO_readfile.h" #include "DNA_scene_types.h" /***/ -#include "GPU_extensions.h" - -#ifdef __cplusplus -extern "C" { -#endif -#include "BSE_headerbuttons.h" -void update_for_newframe(); +//XXX #include "BSE_headerbuttons.h" +#include "BKE_context.h" +#include "../../blender/windowmanager/WM_types.h" +#include "../../blender/windowmanager/wm_window.h" +#include "../../blender/windowmanager/wm_event_system.h" #ifdef __cplusplus } #endif -static BlendFileData *load_game_data(char *filename) { - BlendReadError error; - BlendFileData *bfd= BLO_read_from_file(filename, &error); + +static BlendFileData *load_game_data(char *filename) +{ + ReportList reports; + BlendFileData *bfd; + + BKE_reports_init(&reports, RPT_STORE); + bfd= BLO_read_from_file(filename, &reports); + if (!bfd) { - printf("Loading %s failed: %s\n", filename, BLO_bre_as_string(error)); + printf("Loading %s failed: ", filename); + BKE_reports_print(&reports, RPT_ERROR); } + + BKE_reports_clear(&reports); + return bfd; } -extern "C" void StartKetsjiShell(struct ScrArea *area, - char* scenename, - struct Main* maggie1, - struct SpaceIpo *sipo, - int always_use_expand_framing) +extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, int always_use_expand_framing) { - int exitrequested = KX_EXIT_REQUEST_NO_REQUEST; + /* context values */ + struct wmWindow *win= CTX_wm_window(C); + struct Scene *scene= CTX_data_scene(C); + struct Main* maggie1= CTX_data_main(C); + + int exitrequested = KX_EXIT_REQUEST_NO_REQUEST; Main* blenderdata = maggie1; - char* startscenename = scenename; + char* startscenename = scene->id.name+2; char pathname[FILE_MAXDIR+FILE_MAXFILE], oldsce[FILE_MAXDIR+FILE_MAXFILE]; STR_String exitstring = ""; BlendFileData *bfd= NULL; BLI_strncpy(pathname, blenderdata->name, sizeof(pathname)); BLI_strncpy(oldsce, G.sce, sizeof(oldsce)); + resetGamePythonPath(); // need this so running a second time wont use an old blendfiles path setGamePythonPath(G.sce); // Acquire Python's GIL (global interpreter lock) @@ -129,7 +148,8 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, do { - View3D *v3d= (View3D*) area->spacedata.first; + View3D *v3d= CTX_wm_view3d(C); + RegionView3D *rv3d= CTX_wm_region_view3d(C); // get some preferences SYS_SystemHandle syshandle = SYS_GetSystem(); @@ -139,20 +159,21 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0); bool game2ipo = (SYS_GetCommandLineInt(syshandle, "game2ipo", 0) != 0); bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0); - + bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 0) != 0); + bool novertexarrays = (SYS_GetCommandLineInt(syshandle, "novertexarrays", 0) != 0); // create the canvas, rasterizer and rendertools - RAS_ICanvas* canvas = new KX_BlenderCanvas(area); + RAS_ICanvas* canvas = new KX_BlenderCanvas(win, ar); canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); RAS_IRenderTools* rendertools = new KX_BlenderRenderTools(); RAS_IRasterizer* rasterizer = NULL; if(displaylists) { - if (GLEW_VERSION_1_1) + if (GLEW_VERSION_1_1 && !novertexarrays) rasterizer = new RAS_ListRasterizer(canvas, true, true); else rasterizer = new RAS_ListRasterizer(canvas); } - else if (GLEW_VERSION_1_1) + else if (GLEW_VERSION_1_1 && !novertexarrays) rasterizer = new RAS_VAOpenGLRasterizer(canvas, false); else rasterizer = new RAS_OpenGLRasterizer(canvas); @@ -164,19 +185,8 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, // create a networkdevice NG_NetworkDeviceInterface* networkdevice = new NG_LoopBackNetworkDeviceInterface(); - - // - SYS_SystemHandle hSystem = SYS_GetSystem(); - bool noaudio = SYS_GetCommandLineInt(hSystem,"noaudio",0); - if (noaudio)/*(noaudio) intrr: disable game engine audio (openal) */ - SND_DeviceManager::SetDeviceType(snd_e_dummydevice); - - // get an audiodevice - SND_DeviceManager::Subscribe(); - SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance(); - audiodevice->UseCD(); - + // // create a ketsji/blendersystem (only needed for timing and stuff) KX_BlenderSystem* kxsystem = new KX_BlenderSystem(); @@ -191,40 +201,40 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, ketsjiengine->SetRenderTools(rendertools); ketsjiengine->SetRasterizer(rasterizer); ketsjiengine->SetNetworkDevice(networkdevice); - ketsjiengine->SetAudioDevice(audiodevice); ketsjiengine->SetUseFixedTime(usefixed); ketsjiengine->SetTimingDisplay(frameRate, profile, properties); + CValue::SetDeprecationWarnings(nodepwarnings); + //lock frame and camera enabled - storing global values - int tmp_lay= G.scene->lay; - Object *tmp_camera = G.scene->camera; + int tmp_lay= scene->lay; + Object *tmp_camera = scene->camera; - if (G.vd->scenelock==0){ - G.scene->lay= v3d->lay; - G.scene->camera= v3d->camera; + if (v3d->scenelock==0){ + scene->lay= v3d->lay; + scene->camera= v3d->camera; } - // some blender stuff MT_CmMatrix4x4 projmat; MT_CmMatrix4x4 viewmat; float camzoom; int i; - + for (i = 0; i < 16; i++) { - float *viewmat_linear= (float*) v3d->viewmat; + float *viewmat_linear= (float*) rv3d->viewmat; viewmat.setElem(i, viewmat_linear[i]); } for (i = 0; i < 16; i++) { - float *projmat_linear = (float*) area->winmat; + float *projmat_linear= (float*) rv3d->winmat; projmat.setElem(i, projmat_linear[i]); } - if(v3d->persp==V3D_CAMOB) { - camzoom = (1.41421 + (v3d->camzoom / 50.0)); + if(rv3d->persp==V3D_CAMOB) { + camzoom = (1.41421 + (rv3d->camzoom / 50.0)); camzoom *= camzoom; } else @@ -276,6 +286,7 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, if(blenderdata) { BLI_strncpy(G.sce, blenderdata->name, sizeof(G.sce)); BLI_strncpy(pathname, blenderdata->name, sizeof(pathname)); + setGamePythonPath(G.sce); } } // else forget it, we can't find it @@ -305,26 +316,28 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, { int startFrame = blscene->r.cfra; ketsjiengine->SetGame2IpoMode(game2ipo,startFrame); + + // Quad buffered needs a special window. + if(blscene->gm.stereoflag == STEREO_ENABLED){ + if (blscene->gm.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) + rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->gm.stereomode); + } } - - - // Quad buffered needs a special window. - if (blscene->r.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) - rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->r.stereomode); if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME) { - if (v3d->persp != V3D_CAMOB) + if (rv3d->persp != V3D_CAMOB) { ketsjiengine->EnableCameraOverride(startscenename); - ketsjiengine->SetCameraOverrideUseOrtho((v3d->persp == V3D_ORTHO)); + ketsjiengine->SetCameraOverrideUseOrtho((rv3d->persp == V3D_ORTHO)); ketsjiengine->SetCameraOverrideProjectionMatrix(projmat); ketsjiengine->SetCameraOverrideViewMatrix(viewmat); ketsjiengine->SetCameraOverrideClipping(v3d->near, v3d->far); + ketsjiengine->SetCameraOverrideLens(v3d->lens); } // create a scene converter, create and convert the startingscene - KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(blenderdata,sipo, ketsjiengine); + KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(blenderdata, ketsjiengine); ketsjiengine->SetSceneConverter(sceneconverter); sceneconverter->addInitFromFrame=false; if (always_use_expand_framing) @@ -337,23 +350,22 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, if(GPU_extensions_minimum_support()) useglslmat = true; - else if(G.fileflags & G_FILE_GAME_MAT_GLSL) + else if(blscene->gm.matmode == GAME_MAT_GLSL) usemat = false; - if(usemat && (G.fileflags & G_FILE_GAME_MAT)) + if(usemat && (blscene->gm.matmode != GAME_MAT_TEXFACE)) sceneconverter->SetMaterials(true); - if(useglslmat && (G.fileflags & G_FILE_GAME_MAT_GLSL)) + if(useglslmat && (blscene->gm.matmode == GAME_MAT_GLSL)) sceneconverter->SetGLSLMaterials(true); KX_Scene* startscene = new KX_Scene(keyboarddevice, mousedevice, networkdevice, - audiodevice, startscenename, blscene); // some python things - PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest); + PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest, blenderdata); ketsjiengine->SetPythonDictionary(dictionaryobject); initRasterizer(rasterizer, canvas); PyObject *gameLogic = initGameLogic(ketsjiengine, startscene); @@ -364,15 +376,22 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, initGameKeys(); initPythonConstraintBinding(); initMathutils(); + initGeometry(); + initBGL(); +#ifdef WITH_FFMPEG + initVideoTexture(); +#endif + + //initialize Dome Settings + if(blscene->gm.stereoflag == STEREO_DOME) + ketsjiengine->InitDome(blscene->gm.dome.res, blscene->gm.dome.mode, blscene->gm.dome.angle, blscene->gm.dome.resbuf, blscene->gm.dome.tilt, blscene->gm.dome.warptext); if (sceneconverter) { // convert and add scene sceneconverter->ConvertScene( - startscenename, startscene, dictionaryobject, - keyboarddevice, rendertools, canvas); ketsjiengine->AddScene(startscene); @@ -397,7 +416,7 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, exitrequested = ketsjiengine->GetExitCode(); // kick the engine - bool render = ketsjiengine->NextFrame(); + bool render = ketsjiengine->NextFrame(); // XXX 2.5 Bug, This is never true! FIXME- Campbell if (render) { @@ -405,26 +424,37 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, ketsjiengine->Render(); } + wm_window_process_events_nosleep(C); + // test for the ESC key - while (qtest()) + //XXX while (qtest()) + while(wmEvent *event= (wmEvent *)win->queue.first) { - short val; - unsigned short event = extern_qread(&val); + short val = 0; + //unsigned short event = 0; //XXX extern_qread(&val); - if (keyboarddevice->ConvertBlenderEvent(event,val)) + if (keyboarddevice->ConvertBlenderEvent(event->type,event->val)) exitrequested = KX_EXIT_REQUEST_BLENDER_ESC; /* Coordinate conversion... where * should this really be? */ - if (event==MOUSEX) { - val = val - scrarea_get_win_x(area); - } else if (event==MOUSEY) { - val = scrarea_get_win_height(area) - (val - scrarea_get_win_y(area)) - 1; + if (event->type==MOUSEMOVE) { + /* Note 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); } - mousedevice->ConvertBlenderEvent(event,val); + BLI_remlink(&win->queue, event); + wm_event_free(event); } + } printf("\nBlender Game Engine Finished\n\n"); exitstring = ketsjiengine->GetExitString(); @@ -466,17 +496,15 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, gameLogic_keys = NULL; } //lock frame and camera enabled - restoring global values - if (G.vd->scenelock==0){ - G.scene->lay= tmp_lay; - G.scene->camera= tmp_camera; + if (v3d->scenelock==0){ + scene->lay= tmp_lay; + scene->camera= tmp_camera; } // set the cursor back to normal canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); // clean up some stuff - audiodevice->StopCD(); - if (ketsjiengine) { delete ketsjiengine; @@ -516,11 +544,12 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, { delete canvas; canvas = NULL; - } - SND_DeviceManager::Unsubscribe(); + } } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME); - + + Py_DECREF(pyGlobalDict); + if (bfd) BLO_blendfiledata_free(bfd); BLI_strncpy(G.sce, oldsce, sizeof(G.sce)); @@ -529,10 +558,10 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, PyGILState_Release(gilstate); } -extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, +extern "C" void StartKetsjiShellSimulation(struct wmWindow *win, + struct ARegion *ar, char* scenename, struct Main* maggie, - struct SpaceIpo *sipo, int always_use_expand_framing) { int exitrequested = KX_EXIT_REQUEST_NO_REQUEST; @@ -556,16 +585,18 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, // get some preferences SYS_SystemHandle syshandle = SYS_GetSystem(); + /* bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0); bool usefixed = (SYS_GetCommandLineInt(syshandle, "fixedtime", 0) != 0); bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0); bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0); + */ bool game2ipo = true;//(SYS_GetCommandLineInt(syshandle, "game2ipo", 0) != 0); bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0); bool usemat = false; // create the canvas, rasterizer and rendertools - RAS_ICanvas* canvas = new KX_BlenderCanvas(area); + RAS_ICanvas* canvas = new KX_BlenderCanvas(win, ar); //canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); RAS_IRenderTools* rendertools = new KX_BlenderRenderTools(); RAS_IRasterizer* rasterizer = NULL; @@ -589,11 +620,6 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, NG_NetworkDeviceInterface* networkdevice = new NG_LoopBackNetworkDeviceInterface(); - // get an audiodevice - SND_DeviceManager::Subscribe(); - SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance(); - audiodevice->UseCD(); - // create a ketsji/blendersystem (only needed for timing and stuff) KX_BlenderSystem* kxsystem = new KX_BlenderSystem(); @@ -618,18 +644,20 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, cframe=blscene->r.cfra; startFrame = blscene->r.sfra; blscene->r.cfra=startFrame; - update_for_newframe(); + // update_for_newframe(); // XXX scene_update_for_newframe wont cut it! ketsjiengine->SetGame2IpoMode(game2ipo,startFrame); } // Quad buffered needs a special window. - if (blscene->r.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) - rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->r.stereomode); + if(blscene->gm.stereoflag == STEREO_ENABLED){ + if (blscene->gm.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) + rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->gm.stereomode); + } if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME) { // create a scene converter, create and convert the startingscene - KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(maggie,sipo, ketsjiengine); + KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(maggie, ketsjiengine); ketsjiengine->SetSceneConverter(sceneconverter); sceneconverter->addInitFromFrame=true; @@ -642,12 +670,11 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, KX_Scene* startscene = new KX_Scene(keyboarddevice, mousedevice, networkdevice, - audiodevice, startscenename, blscene); // some python things - PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest); + PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest, blenderdata); ketsjiengine->SetPythonDictionary(dictionaryobject); initRasterizer(rasterizer, canvas); PyObject *gameLogic = initGameLogic(ketsjiengine, startscene); @@ -655,15 +682,18 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, initGameKeys(); initPythonConstraintBinding(); initMathutils(); + initGeometry(); + initBGL(); +#ifdef WITH_FFMPEG + initVideoTexture(); +#endif if (sceneconverter) { // convert and add scene sceneconverter->ConvertScene( - startscenename, startscene, dictionaryobject, - keyboarddevice, rendertools, canvas); ketsjiengine->AddScene(startscene); @@ -687,7 +717,7 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, // kick the engine ketsjiengine->NextFrame(); blscene->r.cfra=blscene->r.cfra+1; - update_for_newframe(); + // update_for_newframe(); // XXX scene_update_for_newframe wont cut it } exitstring = ketsjiengine->GetExitString(); @@ -703,7 +733,6 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); // clean up some stuff - audiodevice->StopCD(); if (ketsjiengine) { delete ketsjiengine; @@ -729,7 +758,16 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, delete mousedevice; mousedevice = NULL; } - SND_DeviceManager::Unsubscribe(); + if (rasterizer) + { + delete rasterizer; + rasterizer = NULL; + } + if (rendertools) + { + delete rendertools; + rendertools = NULL; + } } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME); diff --git a/source/gameengine/BlenderRoutines/CMakeLists.txt b/source/gameengine/BlenderRoutines/CMakeLists.txt index 340a1ae310b..ee15fd99ed5 100644 --- a/source/gameengine/BlenderRoutines/CMakeLists.txt +++ b/source/gameengine/BlenderRoutines/CMakeLists.txt @@ -2,41 +2,44 @@ FILE(GLOB SRC *.cpp) SET(INC - . - ../../../source/kernel/gen_system - ../../../intern/string - ../../../intern/guardedalloc - ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../intern/bmfont - ../../../source/gameengine/Converter - ../../../source/blender/imbuf - ../../../intern/ghost/include - ../../../intern/moto/include - ../../../source/gameengine/Ketsji - ../../../source/blender/blenlib - ../../../source/blender/blenkernel - ../../../source/blender - ../../../source/blender/include - ../../../source/blender/makesdna - ../../../source/gameengine/Rasterizer - ../../../source/gameengine/GameLogic - ../../../source/gameengine/Expressions - ../../../source/gameengine/Network - ../../../source/gameengine/SceneGraph - ../../../source/gameengine/Physics/common - ../../../source/gameengine/Physics/Bullet - ../../../source/gameengine/Physics/Sumo - ../../../source/gameengine/Physics/Sumo/Fuzzics/include - ../../../source/gameengine/Network/LoopBackNetwork - ../../../intern/SoundSystem - ../../../source/blender/misc - ../../../source/blender/blenloader - ../../../source/blender/gpu - ../../../extern/bullet2/src - ../../../extern/solid - ../../../extern/glew/include - ${PYTHON_INC} + . + ../../../source/kernel/gen_system + ../../../intern/string + ../../../intern/guardedalloc + ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer + ../../../source/gameengine/Converter + ../../../source/blender/imbuf + ../../../intern/ghost/include + ../../../intern/moto/include + ../../../source/gameengine/Ketsji + ../../../source/blender/blenlib + ../../../source/blender/blenkernel + ../../../source/blender/blenfont + ../../../source/blender/editors/include + ../../../source/blender/windowmanager + ../../../source/blender + ../../../source/blender/include + ../../../source/blender/makesdna + ../../../source/blender/makesrna + ../../../source/gameengine/Rasterizer + ../../../source/gameengine/GameLogic + ../../../source/gameengine/Expressions + ../../../source/gameengine/Network + ../../../source/gameengine/SceneGraph + ../../../source/gameengine/Physics/common + ../../../source/gameengine/Physics/Bullet + ../../../source/gameengine/Network/LoopBackNetwork + ../../../source/blender/misc + ../../../source/blender/blenloader + ../../../source/blender/gpu + ../../../extern/bullet2/src + ../../../extern/glew/include + ${PYTHON_INC} ) +IF(WITH_FFMPEG) + ADD_DEFINITIONS(-DWITH_FFMPEG) +ENDIF(WITH_FFMPEG) + BLENDERLIB(bf_blroutines "${SRC}" "${INC}") #env.BlenderLib ( 'bf_bloutines', sources, Split(incs), [], libtype=['game', 'game2', 'player'], priority=[0, 0, 55] , compileflags=cxxflags) diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp index 1604dfe5cce..360794ceb33 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp @@ -26,15 +26,18 @@ * ***** END GPL LICENSE BLOCK ***** */ -#include "BIF_scrarea.h" #include "KX_BlenderCanvas.h" +#include "DNA_screen_types.h" +#include "stdio.h" #ifdef HAVE_CONFIG_H #include <config.h> #endif -KX_BlenderCanvas::KX_BlenderCanvas(struct ScrArea *area) : -m_area(area) + +KX_BlenderCanvas::KX_BlenderCanvas(struct wmWindow *win, ARegion *ar) : +m_win(win), +m_ar(ar) { } @@ -50,7 +53,7 @@ void KX_BlenderCanvas::Init() void KX_BlenderCanvas::SwapBuffers() { - BL_SwapBuffers(); + BL_SwapBuffers(m_win); } void KX_BlenderCanvas::BeginFrame() @@ -93,12 +96,12 @@ void KX_BlenderCanvas::ClearBuffer(int type) int KX_BlenderCanvas::GetWidth( ) const { - return scrarea_get_win_width(m_area); + return m_ar->winx; } int KX_BlenderCanvas::GetHeight( ) const { - return scrarea_get_win_height(m_area); + return m_ar->winy; } RAS_Rect & @@ -116,8 +119,8 @@ SetViewPort( ){ int vp_width = (x2 - x1) + 1; int vp_height = (y2 - y1) + 1; - int minx = scrarea_get_win_x(m_area); - int miny = scrarea_get_win_y(m_area); + int minx = m_ar->winrct.xmin; + int miny = m_ar->winrct.ymin; m_area_rect.SetLeft(minx + x1); m_area_rect.SetBottom(miny + y1); @@ -159,9 +162,9 @@ void KX_BlenderCanvas::SetMouseState(RAS_MouseState mousestate) // (0,0) is top left, (width,height) is bottom right void KX_BlenderCanvas::SetMousePosition(int x,int y) { - int winX = scrarea_get_win_x(m_area); - int winY = scrarea_get_win_y(m_area); - int winH = scrarea_get_win_height(m_area); + int winX = m_ar->winrct.xmin; + int winY = m_ar->winrct.ymin; + int winH = m_ar->winy; BL_warp_pointer(winX + x, winY + (winH-y-1)); } @@ -170,5 +173,5 @@ void KX_BlenderCanvas::SetMousePosition(int x,int y) void KX_BlenderCanvas::MakeScreenShot(const char* filename) { - BL_MakeScreenShot(m_area, filename); + BL_MakeScreenShot(m_ar, filename); } diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h index bc202a8558c..d49c877f610 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h @@ -40,7 +40,12 @@ #include "KX_BlenderGL.h" -struct ScrArea; +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + +struct ARegion; +struct wmWindow; /** * 2D Blender device context abstraction. @@ -57,9 +62,9 @@ private: public: /* Construct a new canvas. * - * @param area The Blender ScrArea to run the game within. + * @param area The Blender ARegion to run the game within. */ - KX_BlenderCanvas(struct ScrArea* area); + KX_BlenderCanvas(struct wmWindow* win, struct ARegion* ar); ~KX_BlenderCanvas(); void @@ -162,8 +167,16 @@ public: private: /** Blender area the game engine is running within */ - struct ScrArea* m_area; + struct ARegion* m_ar; + struct wmWindow* m_win; RAS_Rect m_area_rect; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_BlenderCanvas"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // __KX_BLENDERCANVAS diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp index 54d1eb7e011..dba6d1113c9 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp @@ -28,6 +28,14 @@ #include "KX_BlenderGL.h" +#ifdef __cplusplus +extern "C" { +#endif +#include "BLF_api.h" +#ifdef __cplusplus +} +#endif + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -42,9 +50,7 @@ #include <stdlib.h> #include <string.h> -#include "BMF_Api.h" - -#include "BIF_gl.h" +#include "GL/glew.h" #include "BL_Material.h" // MAXTEX @@ -59,17 +65,18 @@ #include "DNA_image_types.h" #include "DNA_view3d_types.h" #include "DNA_material_types.h" +#include "DNA_windowmanager_types.h" #include "BKE_global.h" #include "BKE_bmfont.h" #include "BKE_image.h" extern "C" { -#include "BDR_drawmesh.h" -#include "BIF_mywindow.h" -#include "BIF_toolbox.h" -#include "BIF_graphics.h" /* For CURSOR_NONE CURSOR_WAIT CURSOR_STD */ - +//XXX #include "BDR_drawmesh.h" +//XXX #include "BIF_mywindow.h" +//XXX #include "BIF_toolbox.h" +//XXX #include "BIF_graphics.h" /* For CURSOR_NONE CURSOR_WAIT CURSOR_STD */ +void wm_window_swap_buffers(wmWindow *win); // wm_window.h } /* end of blender block */ @@ -84,16 +91,20 @@ void spack(unsigned int ucol) void BL_warp_pointer(int x,int y) { - warp_pointer(x,y); + //XXX warp_pointer(x,y); } -void BL_SwapBuffers() +void BL_SwapBuffers(wmWindow *win) { - myswapbuffers(); + //wmWindow *window= CTX_wm_window(C); + wm_window_swap_buffers(win); + //XXX myswapbuffers(); } void DisableForText() { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); /* needed for texture fonts otherwise they render as wireframe */ + if(glIsEnabled(GL_BLEND)) glDisable(GL_BLEND); if(glIsEnabled(GL_ALPHA_TEST)) glDisable(GL_ALPHA_TEST); @@ -126,33 +137,25 @@ void DisableForText() } } -void BL_print_gamedebug_line(char* text, int xco, int yco, int width, int height) +void BL_print_gamedebug_line(const char* text, int xco, int yco, int width, int height) { /* gl prepping */ DisableForText(); - //glDisable(GL_TEXTURE_2D); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); - - glOrtho(0, width, - 0, height, 0, 1); - + + glOrtho(0, width, 0, height, -100, 100); + glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); - glMatrixMode(GL_TEXTURE); - glPushMatrix(); - glLoadIdentity(); /* the actual drawing */ glColor3ub(255, 255, 255); - glRasterPos2s(xco, height-yco); - BMF_DrawString(G.fonts, text); + BLF_draw_default(xco, height-yco, 0.0f, (char *)text); - glMatrixMode(GL_TEXTURE); - glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); @@ -160,38 +163,29 @@ void BL_print_gamedebug_line(char* text, int xco, int yco, int width, int height glEnable(GL_DEPTH_TEST); } -void BL_print_gamedebug_line_padded(char* text, int xco, int yco, int width, int height) +void BL_print_gamedebug_line_padded(const char* text, int xco, int yco, int width, int height) { /* This is a rather important line :( The gl-mode hasn't been left * behind quite as neatly as we'd have wanted to. I don't know * what cause it, though :/ .*/ DisableForText(); - //glDisable(GL_TEXTURE_2D); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); - glOrtho(0, width, - 0, height, 0, 1); + glOrtho(0, width, 0, height, -100, 100); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); - glMatrixMode(GL_TEXTURE); - glPushMatrix(); - glLoadIdentity(); /* draw in black first*/ glColor3ub(0, 0, 0); - glRasterPos2s(xco+1, height-yco-1); - BMF_DrawString(G.fonts, text); + BLF_draw_default(xco+2, height-yco-2, 0.0f, (char *)text); glColor3ub(255, 255, 255); - glRasterPos2s(xco, height-yco); - BMF_DrawString(G.fonts, text); + BLF_draw_default(xco, height-yco, 0.0f, (char *)text); - glMatrixMode(GL_TEXTURE); - glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); @@ -201,24 +195,24 @@ void BL_print_gamedebug_line_padded(char* text, int xco, int yco, int width, int void BL_HideMouse() { - set_cursor(CURSOR_NONE); + //XXX set_cursor(CURSOR_NONE); } void BL_WaitMouse() { - set_cursor(CURSOR_WAIT); + //XXX set_cursor(CURSOR_WAIT); } void BL_NormalMouse() { - set_cursor(CURSOR_STD); + //XXX set_cursor(CURSOR_STD); } #define MAX_FILE_LENGTH 512 -void BL_MakeScreenShot(struct ScrArea *area, const char* filename) +void BL_MakeScreenShot(struct ARegion *ar, const char* filename) { char copyfilename[MAX_FILE_LENGTH]; strcpy(copyfilename,filename); @@ -226,9 +220,9 @@ void BL_MakeScreenShot(struct ScrArea *area, const char* filename) // filename read - only /* XXX will need to change at some point */ - BIF_screendump(0); + //XXX BIF_screendump(0); // write+read filename - write_screendump((char*) copyfilename); + //XXX write_screendump((char*) copyfilename); } diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.h b/source/gameengine/BlenderRoutines/KX_BlenderGL.h index b891a7343c2..5c947ff630e 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderGL.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.h @@ -33,21 +33,22 @@ extern "C" { #endif //__cplusplus -struct ScrArea; +struct wmWindow; +struct ARegion; // special swapbuffers, that takes care of which area (viewport) needs to be swapped -void BL_SwapBuffers(); +void BL_SwapBuffers(struct wmWindow *win); void BL_warp_pointer(int x,int y); -void BL_MakeScreenShot(struct ScrArea *area, const char* filename); +void BL_MakeScreenShot(struct ARegion *ar, const char* filename); void BL_HideMouse(); void BL_NormalMouse(); void BL_WaitMouse(); -void BL_print_gamedebug_line(char* text, int xco, int yco, int width, int height); -void BL_print_gamedebug_line_padded(char* text, int xco, int yco, int width, int height); +void BL_print_gamedebug_line(const char* text, int xco, int yco, int width, int height); +void BL_print_gamedebug_line_padded(const char* text, int xco, int yco, int width, int height); diff --git a/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h b/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h index 8e5d508f8cb..d4dd9af3d4f 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h @@ -35,14 +35,14 @@ #include <map> -/* need to be here for conversion purposes */ -#ifdef FREE_WINDOWS -#undef HKEY -#endif - -#include "mydevice.h" +#include "wm_event_types.h" +#include "WM_types.h" #include "SCA_IInputDevice.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + /** Base Class for Blender specific inputdevices. Blender specific inputdevices are used when the gameengine is running in embedded mode instead of standalone mode. */ @@ -69,10 +69,10 @@ public: m_reverseKeyTranslateTable[TIMER0 ] = KX_TIMER0 ; m_reverseKeyTranslateTable[TIMER1 ] = KX_TIMER1 ; m_reverseKeyTranslateTable[TIMER2 ] = KX_TIMER2 ; - m_reverseKeyTranslateTable[TIMER3 ] = KX_TIMER3 ; - - // SYSTEM + // SYSTEM +#if 0 + /* **** XXX **** */ m_reverseKeyTranslateTable[KEYBD ] = KX_KEYBD ; m_reverseKeyTranslateTable[RAWKEYBD ] = KX_RAWKEYBD ; m_reverseKeyTranslateTable[REDRAW ] = KX_REDRAW ; @@ -83,7 +83,8 @@ public: m_reverseKeyTranslateTable[WINCLOSE ] = KX_WINCLOSE ; m_reverseKeyTranslateTable[WINQUIT ] = KX_WINQUIT ; m_reverseKeyTranslateTable[Q_FIRSTTIME ] = KX_Q_FIRSTTIME ; - + /* **** XXX **** */ +#endif // standard keyboard m_reverseKeyTranslateTable[AKEY ] = KX_AKEY ; @@ -93,7 +94,15 @@ public: m_reverseKeyTranslateTable[EKEY ] = KX_EKEY ; m_reverseKeyTranslateTable[FKEY ] = KX_FKEY ; m_reverseKeyTranslateTable[GKEY ] = KX_GKEY ; +//XXX clean up +#ifdef WIN32 +#define HKEY 'h' +#endif m_reverseKeyTranslateTable[HKEY ] = KX_HKEY ; +//XXX clean up +#ifdef WIN32 +#undef HKEY +#endif m_reverseKeyTranslateTable[IKEY ] = KX_IKEY ; m_reverseKeyTranslateTable[JKEY ] = KX_JKEY ; m_reverseKeyTranslateTable[KKEY ] = KX_KKEY ; @@ -215,6 +224,12 @@ public: // virtual const SCA_InputEvent& GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode)=0; virtual bool ConvertBlenderEvent(unsigned short incode,short val)=0; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_BlenderInputDevice"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_BLENDERINPUTDEVICE diff --git a/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp b/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp index 4b794380610..58af94854e6 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp @@ -74,7 +74,7 @@ void KX_BlenderKeyboardDevice::NextFrame() // now convert justpressed keyevents into regular (active) keyevents int previousTable = 1-m_currentTable; - for (int keyevent= KX_BEGINKEY; keyevent< KX_ENDKEY;keyevent++) + for (int keyevent= KX_BEGINKEY; keyevent<= KX_ENDKEY;keyevent++) { SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][keyevent]; if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED || @@ -100,11 +100,11 @@ bool KX_BlenderKeyboardDevice::ConvertBlenderEvent(unsigned short incode,short v KX_EnumInputs kxevent = this->ToNative(incode); // only process it, if it's a key - if (kxevent >= KX_BEGINKEY && kxevent < KX_ENDKEY) + if (kxevent >= KX_BEGINKEY && kxevent <= KX_ENDKEY) { int previousTable = 1-m_currentTable; - if (val > 0) + if (val == KM_PRESS) { if (kxevent == KX_ESCKEY && val != 0 && !m_hookesc) result = true; @@ -138,7 +138,7 @@ bool KX_BlenderKeyboardDevice::ConvertBlenderEvent(unsigned short incode,short v } } - } else + } else if (val == KM_RELEASE) { // blender eventval == 0 switch (m_eventStatusTables[previousTable][kxevent].m_status) diff --git a/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.h b/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.h index 5bf37acf236..c801322e787 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.h @@ -31,6 +31,10 @@ #include "KX_BlenderInputDevice.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class KX_BlenderKeyboardDevice : public BL_BlenderInputDevice { bool m_hookesc; @@ -43,6 +47,13 @@ public: virtual bool ConvertBlenderEvent(unsigned short incode,short val); virtual void NextFrame(); virtual void HookEscape(); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_BlenderKeyboardDevice"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_BLENDERKEYBOARDDEVICE diff --git a/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.h b/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.h index 2f9e956a1d8..92383e4b533 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.h @@ -31,6 +31,10 @@ #include "KX_BlenderInputDevice.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class KX_BlenderMouseDevice : public BL_BlenderInputDevice { public: @@ -41,6 +45,13 @@ public: // virtual const SCA_InputEvent& GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode); virtual bool ConvertBlenderEvent(unsigned short incode,short val); virtual void NextFrame(); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_BlenderMouseDevice"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_BLENDERMOUSEDEVICE diff --git a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp index 1797d6c1a0f..ee9dae14b9b 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp @@ -39,6 +39,7 @@ #include "KX_BlenderMaterial.h" #include "KX_RayCast.h" #include "KX_IPhysicsController.h" +#include "KX_Light.h" #include "PHY_IPhysicsEnvironment.h" @@ -66,7 +67,8 @@ void KX_BlenderRenderTools::BeginFrame(RAS_IRasterizer* rasty) { m_clientobject = NULL; m_lastlightlayer = -1; - m_lastlighting = false; + m_lastauxinfo = NULL; + m_lastlighting = true; /* force disable in DisableOpenGLLights() */ DisableOpenGLLights(); } @@ -80,33 +82,35 @@ void KX_BlenderRenderTools::EndFrame(RAS_IRasterizer* rasty) * has a maximum of 8 lights (simultaneous), so 20 * 8 lights are possible in * a scene. */ -void KX_BlenderRenderTools::ProcessLighting(int layer, const MT_Transform& viewmat) +void KX_BlenderRenderTools::ProcessLighting(RAS_IRasterizer *rasty, bool uselights, const MT_Transform& viewmat) { - if(m_lastlightlayer == layer) - return; + bool enable = false; + int layer= -1; - m_lastlightlayer = layer; + /* find the layer */ + if(uselights) { + if(m_clientobject) + layer = static_cast<KX_GameObject*>(m_clientobject)->GetLayer(); + } - bool enable = false; + /* avoid state switching */ + if(m_lastlightlayer == layer && m_lastauxinfo == m_auxilaryClientInfo) + return; - if (layer >= 0) - { - if (m_clientobject) - { - if (layer == RAS_LIGHT_OBJECT_LAYER) - layer = static_cast<KX_GameObject*>(m_clientobject)->GetLayer(); + m_lastlightlayer = layer; + m_lastauxinfo = m_auxilaryClientInfo; - enable = applyLights(layer, viewmat); - } - } + /* enable/disable lights as needed */ + if(layer >= 0) + enable = applyLights(layer, viewmat); if(enable) - EnableOpenGLLights(); + EnableOpenGLLights(rasty); else DisableOpenGLLights(); } -void KX_BlenderRenderTools::EnableOpenGLLights() +void KX_BlenderRenderTools::EnableOpenGLLights(RAS_IRasterizer *rasty) { if(m_lastlighting == true) return; @@ -115,7 +119,8 @@ void KX_BlenderRenderTools::EnableOpenGLLights() glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, true); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (rasty->GetCameraOrtho())? GL_FALSE: GL_TRUE); if (GLEW_EXT_separate_specular_color || GLEW_VERSION_1_2) glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); @@ -256,6 +261,12 @@ void KX_BlenderRenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmat // couldn't find something to cast the shadow on... glMultMatrixd(oglmatrix); } + else + { // we found the "ground", but the cast matrix doesn't take + // scaling in consideration, so we must apply the object scale + MT_Vector3 size = gameobj->GetSGNode()->GetLocalScale(); + glScalef(size[0], size[1], size[2]); + } } else { @@ -273,12 +284,10 @@ void KX_BlenderRenderTools::RenderText2D(RAS_TEXT_RENDER_MODE mode, int width, int height) { - STR_String tmpstr(text); - if(mode == RAS_IRenderTools::RAS_TEXT_PADDED) - BL_print_gamedebug_line_padded(tmpstr.Ptr(), xco, yco, width, height); + BL_print_gamedebug_line_padded(text, xco, yco, width, height); else - BL_print_gamedebug_line(tmpstr.Ptr(), xco, yco, width, height); + BL_print_gamedebug_line(text, xco, yco, width, height); } /* Render Text renders text into a (series of) polygon, using a texture font, @@ -289,7 +298,7 @@ void KX_BlenderRenderTools::RenderText( RAS_IPolyMaterial* polymat, float v1[3], float v2[3], float v3[3], float v4[3], int glattrib) { - STR_String mytext = ((CValue*)m_clientobject)->GetPropertyText("Text"); + const STR_String& mytext = ((CValue*)m_clientobject)->GetPropertyText("Text"); const unsigned int flag = polymat->GetFlag(); struct MTFace* tface = 0; @@ -323,17 +332,13 @@ void KX_BlenderRenderTools::PopMatrix() int KX_BlenderRenderTools::applyLights(int objectlayer, const MT_Transform& viewmat) { // taken from blender source, incompatibility between Blender Object / GameObject + KX_Scene* kxscene = (KX_Scene*)m_auxilaryClientInfo; float glviewmat[16]; unsigned int count; - float vec[4]; + std::vector<struct RAS_LightObject*>::iterator lit = m_lights.begin(); - vec[3]= 1.0; - for(count=0; count<m_numgllights; count++) glDisable((GLenum)(GL_LIGHT0+count)); - - //std::vector<struct RAS_LightObject*> m_lights; - std::vector<struct RAS_LightObject*>::iterator lit = m_lights.begin(); viewmat.getValue(glviewmat); @@ -342,76 +347,14 @@ int KX_BlenderRenderTools::applyLights(int objectlayer, const MT_Transform& view for (lit = m_lights.begin(), count = 0; !(lit==m_lights.end()) && count < m_numgllights; ++lit) { RAS_LightObject* lightdata = (*lit); - if (lightdata->m_layer & objectlayer) - { - vec[0] = (*(lightdata->m_worldmatrix))(0,3); - vec[1] = (*(lightdata->m_worldmatrix))(1,3); - vec[2] = (*(lightdata->m_worldmatrix))(2,3); - vec[3] = 1; - - if(lightdata->m_type==RAS_LightObject::LIGHT_SUN) { - - vec[0] = (*(lightdata->m_worldmatrix))(0,2); - vec[1] = (*(lightdata->m_worldmatrix))(1,2); - vec[2] = (*(lightdata->m_worldmatrix))(2,2); - //vec[0]= base->object->obmat[2][0]; - //vec[1]= base->object->obmat[2][1]; - //vec[2]= base->object->obmat[2][2]; - vec[3]= 0.0; - glLightfv((GLenum)(GL_LIGHT0+count), GL_POSITION, vec); - } - else { - //vec[3]= 1.0; - glLightfv((GLenum)(GL_LIGHT0+count), GL_POSITION, vec); - glLightf((GLenum)(GL_LIGHT0+count), GL_CONSTANT_ATTENUATION, 1.0); - glLightf((GLenum)(GL_LIGHT0+count), GL_LINEAR_ATTENUATION, lightdata->m_att1/lightdata->m_distance); - // without this next line it looks backward compatible. - //attennuation still is acceptable - glLightf((GLenum)(GL_LIGHT0+count), GL_QUADRATIC_ATTENUATION, lightdata->m_att2/(lightdata->m_distance*lightdata->m_distance)); - - if(lightdata->m_type==RAS_LightObject::LIGHT_SPOT) { - vec[0] = -(*(lightdata->m_worldmatrix))(0,2); - vec[1] = -(*(lightdata->m_worldmatrix))(1,2); - vec[2] = -(*(lightdata->m_worldmatrix))(2,2); - //vec[0]= -base->object->obmat[2][0]; - //vec[1]= -base->object->obmat[2][1]; - //vec[2]= -base->object->obmat[2][2]; - glLightfv((GLenum)(GL_LIGHT0+count), GL_SPOT_DIRECTION, vec); - glLightf((GLenum)(GL_LIGHT0+count), GL_SPOT_CUTOFF, lightdata->m_spotsize/2.0); - glLightf((GLenum)(GL_LIGHT0+count), GL_SPOT_EXPONENT, 128.0*lightdata->m_spotblend); - } - else glLightf((GLenum)(GL_LIGHT0+count), GL_SPOT_CUTOFF, 180.0); - } - - if (lightdata->m_nodiffuse) - { - vec[0] = vec[1] = vec[2] = vec[3] = 0.0; - } else { - vec[0]= lightdata->m_energy*lightdata->m_red; - vec[1]= lightdata->m_energy*lightdata->m_green; - vec[2]= lightdata->m_energy*lightdata->m_blue; - vec[3]= 1.0; - } - glLightfv((GLenum)(GL_LIGHT0+count), GL_DIFFUSE, vec); - if (lightdata->m_nospecular) - { - vec[0] = vec[1] = vec[2] = vec[3] = 0.0; - } else if (lightdata->m_nodiffuse) { - vec[0]= lightdata->m_energy*lightdata->m_red; - vec[1]= lightdata->m_energy*lightdata->m_green; - vec[2]= lightdata->m_energy*lightdata->m_blue; - vec[3]= 1.0; - } - glLightfv((GLenum)(GL_LIGHT0+count), GL_SPECULAR, vec); - glEnable((GLenum)(GL_LIGHT0+count)); + KX_LightObject *kxlight = (KX_LightObject*)lightdata->m_light; + if(kxlight->ApplyLight(kxscene, objectlayer, count)) count++; - } } glPopMatrix(); return count; - } void KX_BlenderRenderTools::MotionBlur(RAS_IRasterizer* rasterizer) @@ -446,4 +389,3 @@ void KX_BlenderRenderTools::Render2DFilters(RAS_ICanvas* canvas) { m_filtermanager.RenderFilters(canvas); } - diff --git a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h index a7618462c9b..70672b8350b 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h @@ -37,6 +37,10 @@ #include "RAS_IRenderTools.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + struct KX_ClientObjectInfo; class KX_RayCast; @@ -51,6 +55,7 @@ class KX_BlenderRenderTools : public RAS_IRenderTools { int m_lastlightlayer; bool m_lastlighting; + void *m_lastauxinfo; static unsigned int m_numgllights; public: @@ -60,9 +65,9 @@ public: void EndFrame(RAS_IRasterizer* rasty); void BeginFrame(RAS_IRasterizer* rasty); - void EnableOpenGLLights(); + void EnableOpenGLLights(RAS_IRasterizer *rasty); void DisableOpenGLLights(); - void ProcessLighting(int layer, const MT_Transform& viewmat); + void ProcessLighting(RAS_IRasterizer *rasty, bool uselights, const MT_Transform& viewmat); void RenderText2D(RAS_TEXT_RENDER_MODE mode, const char* text, @@ -94,6 +99,13 @@ public: virtual void Render2DFilters(RAS_ICanvas* canvas); virtual void SetClientObject(RAS_IRasterizer *rasty, void* obj); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_BlenderRenderTools"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_BLENDERRENDERTOOLS diff --git a/source/gameengine/BlenderRoutines/KX_BlenderSystem.h b/source/gameengine/BlenderRoutines/KX_BlenderSystem.h index d99bb9b14a8..b6b2841e81c 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderSystem.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderSystem.h @@ -34,6 +34,10 @@ */ #include "KX_ISystem.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class KX_BlenderSystem : public KX_ISystem { double m_starttime; @@ -42,6 +46,14 @@ public: KX_BlenderSystem(); virtual ~KX_BlenderSystem() {}; virtual double GetTimeInSeconds(); + + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_BlenderSystem"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_BLENDERSYSTEM diff --git a/source/gameengine/BlenderRoutines/Makefile b/source/gameengine/BlenderRoutines/Makefile index 4b9a2a3af17..4b65da667ef 100644 --- a/source/gameengine/BlenderRoutines/Makefile +++ b/source/gameengine/BlenderRoutines/Makefile @@ -35,26 +35,24 @@ include nan_compile.mk CCFLAGS += $(LEVEL_1_CPP_WARNINGS) -CPPFLAGS += -I$(NAN_SUMO)/include -I$(NAN_SOLID)/include -CPPFLAGS += -I$(NAN_SOLID) +CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include -CPPFLAGS += -I$(NAN_BMFONT)/include -CPPFLAGS += -I$(NAN_FUZZICS)/include -CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) # because of kernel dependency on makesdna CPPFLAGS += -I../../blender/makesdna -CPPFLAGS += -I../../blender/include +CPPFLAGS += -I../../blender/editors/include # because of kernel dependency on imbuf +CPPFLAGS += -I../../blender/windowmanager CPPFLAGS += -I../../blender/imbuf CPPFLAGS += -I../../blender/blenlib CPPFLAGS += -I../../blender/blenkernel CPPFLAGS += -I../../blender/render/extern/include CPPFLAGS += -I../../blender/blenloader -CPPFLAGS += -I../../blender/blenkernel +CPPFLAGS += -I../../blender/blenfont CPPFLAGS += -I../../blender/gpu +CPPFLAGS += -I../../blender/makesrna CPPFLAGS += -I../Converter CPPFLAGS += -I../Expressions CPPFLAGS += -I../GameLogic @@ -66,7 +64,6 @@ CPPFLAGS += -I../../kernel/gen_system CPPFLAGS += -I../Network CPPFLAGS += -I../Network/LoopBackNetwork CPPFLAGS += -I../Physics/common -CPPFLAGS += -I../Physics/Sumo CPPFLAGS += -I. ifeq ($(OS),windows) @@ -75,3 +72,6 @@ endif CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) +ifeq ($(WITH_FFMPEG), true) + CPPFLAGS += -DWITH_FFMPEG +endif diff --git a/source/gameengine/BlenderRoutines/SConscript b/source/gameengine/BlenderRoutines/SConscript index 78adbc83d9b..ad6f9f23fce 100644 --- a/source/gameengine/BlenderRoutines/SConscript +++ b/source/gameengine/BlenderRoutines/SConscript @@ -2,28 +2,30 @@ Import ('env') sources = env.Glob('*.cpp') +defs = [] incs = '. #source/kernel/gen_system #intern/string #intern/guardedalloc' -incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer #intern/bmfont' +incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer' incs += ' #source/gameengine/Converter #source/blender/imbuf' incs += ' #intern/ghost/include' incs += ' #intern/moto/include #source/gameengine/Ketsji #source/blender/blenlib' -incs += ' #source/blender/blenkernel #source/blender #source/blender/include' -incs += ' #source/blender/makesdna #source/gameengine/Rasterizer #source/gameengine/GameLogic' +incs += ' #source/blender/blenkernel #source/blender' +incs += ' #source/blender/blenfont #source/blender/editors/include' +incs += ' #source/blender/makesdna #source/blender/makesrna' +incs += ' #source/gameengine/Rasterizer #source/gameengine/GameLogic' incs += ' #source/gameengine/Expressions #source/gameengine/Network' incs += ' #source/gameengine/SceneGraph #source/gameengine/Physics/common' -incs += ' #source/gameengine/Physics/Bullet #source/gameengine/Physics/Sumo' -incs += ' #source/gameengine/Physics/Sumo/Fuzzics/include #source/gameengine/Network/LoopBackNetwork' -incs += ' #intern/SoundSystem #source/blender/misc #source/blender/blenloader' +incs += ' #source/gameengine/Physics/Bullet' +incs += ' #source/gameengine/Network/LoopBackNetwork' +incs += ' #source/blender/misc #source/blender/blenloader' incs += ' #extern/glew/include #source/blender/gpu' +incs += ' #source/blender/windowmanager' + +if env['WITH_BF_FFMPEG']: + defs.append('WITH_FFMPEG') incs += ' ' + env['BF_PYTHON_INC'] -incs += ' ' + env['BF_SOLID_INC'] incs += ' ' + env['BF_BULLET_INC'] incs += ' ' + env['BF_OPENGL_INC'] -cxxflags = [] -if env['OURPLATFORM']=='win32-vc': - cxxflags.append ('/GR') - -env.BlenderLib ( 'bf_bloutines', sources, Split(incs), [], libtype=['game', 'game2', 'player'], priority=[0, 0, 55] , compileflags=cxxflags) +env.BlenderLib ( 'bf_bloutines', sources, Split(incs), defs, libtype=['core','player'], priority=[300,35] , cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/CMakeLists.txt b/source/gameengine/CMakeLists.txt index 93de588ba00..5a1887bd6c3 100644 --- a/source/gameengine/CMakeLists.txt +++ b/source/gameengine/CMakeLists.txt @@ -24,24 +24,22 @@ # # ***** END GPL LICENSE BLOCK ***** -SUBDIRS( - BlenderRoutines - Converter - Expressions - GameLogic - Ketsji - Ketsji/KXNetwork - Network - Network/LoopBackNetwork - Physics/common - Physics/Dummy - Rasterizer - Rasterizer/RAS_OpenGLRasterizer - SceneGraph - Physics/Bullet - Physics/Sumo -) +ADD_SUBDIRECTORY(BlenderRoutines) +ADD_SUBDIRECTORY(Converter) +ADD_SUBDIRECTORY(Expressions) +ADD_SUBDIRECTORY(GameLogic) +ADD_SUBDIRECTORY(Ketsji) +ADD_SUBDIRECTORY(Ketsji/KXNetwork) +ADD_SUBDIRECTORY(Network) +ADD_SUBDIRECTORY(Network/LoopBackNetwork) +ADD_SUBDIRECTORY(Physics/common) +ADD_SUBDIRECTORY(Physics/Dummy) +ADD_SUBDIRECTORY(Rasterizer) +ADD_SUBDIRECTORY(Rasterizer/RAS_OpenGLRasterizer) +ADD_SUBDIRECTORY(SceneGraph) +ADD_SUBDIRECTORY(Physics/Bullet) +ADD_SUBDIRECTORY(VideoTexture) IF(WITH_PLAYER) - SUBDIRS(GamePlayer) + ADD_SUBDIRECTORY(GamePlayer) ENDIF(WITH_PLAYER) diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index 4d748948c27..ca4290703e1 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -39,11 +39,11 @@ #include "BL_SkinDeformer.h" #include "KX_GameObject.h" #include "STR_HashedString.h" -#include "DNA_action_types.h" #include "DNA_nla_types.h" -#include "DNA_actuator_types.h" #include "BKE_action.h" +#include "DNA_action_types.h" #include "DNA_armature_types.h" +#include "DNA_scene_types.h" #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" @@ -51,11 +51,19 @@ #include "BKE_utildefines.h" #include "FloatValue.h" #include "PyObjectPlus.h" +#include "KX_PyMath.h" #ifdef HAVE_CONFIG_H #include <config.h> #endif +extern "C" { +#include "BKE_animsys.h" +#include "BKE_action.h" +#include "RNA_access.h" +#include "RNA_define.h" +} + BL_ActionActuator::~BL_ActionActuator() { if (m_pose) @@ -66,9 +74,9 @@ BL_ActionActuator::~BL_ActionActuator() game_free_pose(m_blendpose); } -void BL_ActionActuator::ProcessReplica(){ -// bPose *oldpose = m_pose; -// bPose *oldbpose = m_blendpose; +void BL_ActionActuator::ProcessReplica() +{ + SCA_IActuator::ProcessReplica(); m_pose = NULL; m_blendpose = NULL; @@ -84,9 +92,6 @@ void BL_ActionActuator::SetBlendTime (float newtime){ CValue* BL_ActionActuator::GetReplica() { BL_ActionActuator* replica = new BL_ActionActuator(*this);//m_float,GetName()); replica->ProcessReplica(); - - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; } @@ -159,16 +164,9 @@ bool BL_ActionActuator::Update(double curtime, bool frame) // maybe there are events for us in the queue ! if (frame) { - for (vector<CValue*>::iterator i=m_events.begin(); !(i==m_events.end());i++) - { - if ((*i)->GetNumber() == 0.0f) - bNegativeEvent = true; - else - bPositiveEvent= true; - (*i)->Release(); - - } - m_events.clear(); + bNegativeEvent = m_negevent; + bPositiveEvent = m_posevent; + RemoveAllEvents(); if (bPositiveEvent) m_flag |= ACT_FLAG_ACTIVE; @@ -369,15 +367,35 @@ bool BL_ActionActuator::Update(double curtime, bool frame) /* Get the underlying pose from the armature */ obj->GetPose(&m_pose); - + +// 2.4x function, /* Override the necessary channels with ones from the action */ - extract_pose_from_action(m_pose, m_action, m_localtime); + // XXX extract_pose_from_action(m_pose, m_action, m_localtime); + + +// 2.5x - replacement for extract_pose_from_action(...) above. + { + struct PointerRNA id_ptr; + Object *arm= obj->GetArmatureObject(); + bPose *pose_back= arm->pose; + + arm->pose= m_pose; + RNA_id_pointer_create((ID *)arm, &id_ptr); + animsys_evaluate_action(&id_ptr, m_action, NULL, m_localtime); + + arm->pose= pose_back; + +// 2.5x - could also do this but looks too high level, constraints use this, it works ok. +// Object workob; /* evaluate using workob */ +// what_does_obaction((Scene *)obj->GetScene(), obj->GetArmatureObject(), &workob, m_pose, m_action, NULL, m_localtime); + } + // done getting the pose from the action + /* Perform the user override (if any) */ if (m_userpose){ extract_pose_from_pose(m_pose, m_userpose); -// clear_pose(m_userpose); - MEM_freeN(m_userpose); + game_free_pose(m_userpose); //cant use MEM_freeN(m_userpose) because the channels need freeing too. m_userpose = NULL; } #if 1 @@ -391,7 +409,7 @@ bool BL_ActionActuator::Update(double curtime, bool frame) /* Find percentages */ newweight = (m_blendframe/(float)m_blendin); - blend_poses(m_pose, m_blendpose, 1.0 - newweight, ACTSTRIPMODE_BLEND); + game_blend_poses(m_pose, m_blendpose, 1.0 - newweight); /* Increment current blending percentage */ m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate(); @@ -418,566 +436,244 @@ bool BL_ActionActuator::Update(double curtime, bool frame) /* Python functions */ /* ------------------------------------------------------------------------- */ -/* Integration hooks ------------------------------------------------------- */ - -PyTypeObject BL_ActionActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "BL_ActionActuator", - sizeof(BL_ActionActuator), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 -}; - -PyParentObject BL_ActionActuator::Parents[] = { - &BL_ActionActuator::Type, - &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL -}; - -PyMethodDef BL_ActionActuator::Methods[] = { - {"setAction", (PyCFunction) BL_ActionActuator::sPySetAction, METH_VARARGS, (PY_METHODCHAR)SetAction_doc}, - {"setStart", (PyCFunction) BL_ActionActuator::sPySetStart, METH_VARARGS, (PY_METHODCHAR)SetStart_doc}, - {"setEnd", (PyCFunction) BL_ActionActuator::sPySetEnd, METH_VARARGS, (PY_METHODCHAR)SetEnd_doc}, - {"setBlendin", (PyCFunction) BL_ActionActuator::sPySetBlendin, METH_VARARGS, (PY_METHODCHAR)SetBlendin_doc}, - {"setPriority", (PyCFunction) BL_ActionActuator::sPySetPriority, METH_VARARGS, (PY_METHODCHAR)SetPriority_doc}, - {"setFrame", (PyCFunction) BL_ActionActuator::sPySetFrame, METH_VARARGS, (PY_METHODCHAR)SetFrame_doc}, - {"setProperty", (PyCFunction) BL_ActionActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, - {"setFrameProperty", (PyCFunction) BL_ActionActuator::sPySetFrameProperty, METH_VARARGS, (PY_METHODCHAR)SetFrameProperty_doc}, - {"setBlendtime", (PyCFunction) BL_ActionActuator::sPySetBlendtime, METH_VARARGS, (PY_METHODCHAR)SetBlendtime_doc}, - - {"getAction", (PyCFunction) BL_ActionActuator::sPyGetAction, METH_VARARGS, (PY_METHODCHAR)GetAction_doc}, - {"getStart", (PyCFunction) BL_ActionActuator::sPyGetStart, METH_VARARGS, (PY_METHODCHAR)GetStart_doc}, - {"getEnd", (PyCFunction) BL_ActionActuator::sPyGetEnd, METH_VARARGS, (PY_METHODCHAR)GetEnd_doc}, - {"getBlendin", (PyCFunction) BL_ActionActuator::sPyGetBlendin, METH_VARARGS, (PY_METHODCHAR)GetBlendin_doc}, - {"getPriority", (PyCFunction) BL_ActionActuator::sPyGetPriority, METH_VARARGS, (PY_METHODCHAR)GetPriority_doc}, - {"getFrame", (PyCFunction) BL_ActionActuator::sPyGetFrame, METH_VARARGS, (PY_METHODCHAR)GetFrame_doc}, - {"getProperty", (PyCFunction) BL_ActionActuator::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, - {"getFrameProperty", (PyCFunction) BL_ActionActuator::sPyGetFrameProperty, METH_VARARGS, (PY_METHODCHAR)GetFrameProperty_doc}, - {"setChannel", (PyCFunction) BL_ActionActuator::sPySetChannel, METH_VARARGS, (PY_METHODCHAR)SetChannel_doc}, -// {"getChannel", (PyCFunction) BL_ActionActuator::sPyGetChannel, METH_VARARGS}, - {"getType", (PyCFunction) BL_ActionActuator::sPyGetType, METH_VARARGS, (PY_METHODCHAR)GetType_doc}, - {"setType", (PyCFunction) BL_ActionActuator::sPySetType, METH_VARARGS, (PY_METHODCHAR)SetType_doc}, - {"getContinue", (PyCFunction) BL_ActionActuator::sPyGetContinue, METH_NOARGS, 0}, - {"setContinue", (PyCFunction) BL_ActionActuator::sPySetContinue, METH_O, 0}, - {NULL,NULL} //Sentinel -}; - -PyObject* BL_ActionActuator::_getattr(const STR_String& attr) { - _getattr_up(SCA_IActuator); -} - -/* setStart */ -const char BL_ActionActuator::GetAction_doc[] = -"getAction()\n" -"\tReturns a string containing the name of the current action.\n"; - -PyObject* BL_ActionActuator::PyGetAction(PyObject* self, - PyObject* args, - PyObject* kwds) { - if (m_action){ - return PyString_FromString(m_action->id.name+2); - } - Py_RETURN_NONE; -} - -/* getProperty */ -const char BL_ActionActuator::GetProperty_doc[] = -"getProperty()\n" -"\tReturns the name of the property to be used in FromProp mode.\n"; - -PyObject* BL_ActionActuator::PyGetProperty(PyObject* self, - PyObject* args, - PyObject* kwds) { - PyObject *result; - - result = Py_BuildValue("s", (const char *)m_propname); - - return result; -} - -/* getProperty */ -const char BL_ActionActuator::GetFrameProperty_doc[] = -"getFrameProperty()\n" -"\tReturns the name of the property, that is set to the current frame number.\n"; - -PyObject* BL_ActionActuator::PyGetFrameProperty(PyObject* self, - PyObject* args, - PyObject* kwds) { - PyObject *result; - - result = Py_BuildValue("s", (const char *)m_framepropname); - - return result; -} - -/* getFrame */ -const char BL_ActionActuator::GetFrame_doc[] = -"getFrame()\n" -"\tReturns the current frame number.\n"; - -PyObject* BL_ActionActuator::PyGetFrame(PyObject* self, - PyObject* args, - PyObject* kwds) { - PyObject *result; - - result = Py_BuildValue("f", m_localtime); - - return result; -} - -/* getEnd */ -const char BL_ActionActuator::GetEnd_doc[] = -"getEnd()\n" -"\tReturns the last frame of the action.\n"; - -PyObject* BL_ActionActuator::PyGetEnd(PyObject* self, - PyObject* args, - PyObject* kwds) { - PyObject *result; - - result = Py_BuildValue("f", m_endframe); - - return result; -} - -/* getStart */ -const char BL_ActionActuator::GetStart_doc[] = -"getStart()\n" -"\tReturns the starting frame of the action.\n"; - -PyObject* BL_ActionActuator::PyGetStart(PyObject* self, - PyObject* args, - PyObject* kwds) { - PyObject *result; - - result = Py_BuildValue("f", m_startframe); +PyObject* BL_ActionActuator::PyGetChannel(PyObject* value) { + char *string= _PyUnicode_AsString(value); - return result; -} - -/* getBlendin */ -const char BL_ActionActuator::GetBlendin_doc[] = -"getBlendin()\n" -"\tReturns the number of interpolation animation frames to be\n" -"\tgenerated when this actuator is triggered.\n"; - -PyObject* BL_ActionActuator::PyGetBlendin(PyObject* self, - PyObject* args, - PyObject* kwds) { - PyObject *result; - - result = Py_BuildValue("f", m_blendin); - - return result; -} - -/* getPriority */ -const char BL_ActionActuator::GetPriority_doc[] = -"getPriority()\n" -"\tReturns the priority for this actuator. Actuators with lower\n" -"\tPriority numbers will override actuators with higher numbers.\n"; - -PyObject* BL_ActionActuator::PyGetPriority(PyObject* self, - PyObject* args, - PyObject* kwds) { - PyObject *result; - - result = Py_BuildValue("i", m_priority); - - return result; -} - -/* setAction */ -const char BL_ActionActuator::SetAction_doc[] = -"setAction(action, (reset))\n" -"\t - action : The name of the action to set as the current action.\n" -"\t - reset : Optional parameter indicating whether to reset the\n" -"\t blend timer or not. A value of 1 indicates that the\n" -"\t timer should be reset. A value of 0 will leave it\n" -"\t unchanged. If reset is not specified, the timer will" -"\t be reset.\n"; - -PyObject* BL_ActionActuator::PySetAction(PyObject* self, - PyObject* args, - PyObject* kwds) { - char *string; - int reset = 1; - - if (PyArg_ParseTuple(args,"s|i",&string, &reset)) - { - bAction *action; - - action = (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(STR_String(string)); - - if (!action){ - /* NOTE! Throw an exception or something */ - // printf ("setAction failed: Action not found\n", string); - } - else{ - m_action=action; - if (reset) - m_blendframe = 0; - } - } - else { + if (!string) { + PyErr_SetString(PyExc_TypeError, "expected a single string"); return NULL; } - Py_RETURN_NONE; -} - -/* setStart */ -const char BL_ActionActuator::SetStart_doc[] = -"setStart(start)\n" -"\t - start : Specifies the starting frame of the animation.\n"; - -PyObject* BL_ActionActuator::PySetStart(PyObject* self, - PyObject* args, - PyObject* kwds) { - float start; + bPoseChannel *pchan; - if (PyArg_ParseTuple(args,"f",&start)) - { - m_startframe = start; - } - else { - return NULL; + if(m_userpose==NULL && m_pose==NULL) { + BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); + obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ } - Py_RETURN_NONE; -} - -/* setEnd */ -const char BL_ActionActuator::SetEnd_doc[] = -"setEnd(end)\n" -"\t - end : Specifies the ending frame of the animation.\n"; - -PyObject* BL_ActionActuator::PySetEnd(PyObject* self, - PyObject* args, - PyObject* kwds) { - float end; - - if (PyArg_ParseTuple(args,"f",&end)) + // get_pose_channel accounts for NULL pose, run on both incase one exists but + // the channel doesnt + if( !(pchan=get_pose_channel(m_userpose, string)) && + !(pchan=get_pose_channel(m_pose, string)) ) { - m_endframe = end; - } - else { + PyErr_SetString(PyExc_ValueError, "channel doesnt exist"); return NULL; } - - Py_RETURN_NONE; -} - -/* setBlendin */ -const char BL_ActionActuator::SetBlendin_doc[] = -"setBlendin(blendin)\n" -"\t - blendin : Specifies the number of frames of animation to generate\n" -"\t when making transitions between actions.\n"; -PyObject* BL_ActionActuator::PySetBlendin(PyObject* self, - PyObject* args, - PyObject* kwds) { - float blendin; + PyObject *ret = PyTuple_New(3); - if (PyArg_ParseTuple(args,"f",&blendin)) - { - m_blendin = blendin; - } - else { - return NULL; - } + PyObject *list = PyList_New(3); + PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->loc[0])); + PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->loc[1])); + PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->loc[2])); + PyTuple_SET_ITEM(ret, 0, list); - Py_RETURN_NONE; -} + list = PyList_New(3); + PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->size[0])); + PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->size[1])); + PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->size[2])); + PyTuple_SET_ITEM(ret, 1, list); + + list = PyList_New(4); + PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->quat[0])); + PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->quat[1])); + PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->quat[2])); + PyList_SET_ITEM(list, 3, PyFloat_FromDouble(pchan->quat[3])); + PyTuple_SET_ITEM(ret, 2, list); -/* setBlendtime */ -const char BL_ActionActuator::SetBlendtime_doc[] = -"setBlendtime(blendtime)\n" -"\t - blendtime : Allows the script to directly modify the internal timer\n" -"\t used when generating transitions between actions. This\n" -"\t parameter must be in the range from 0.0 to 1.0.\n"; + return ret; +/* + return Py_BuildValue("([fff][fff][ffff])", + pchan->loc[0], pchan->loc[1], pchan->loc[2], + pchan->size[0], pchan->size[1], pchan->size[2], + pchan->quat[0], pchan->quat[1], pchan->quat[2], pchan->quat[3] ); +*/ +} -PyObject* BL_ActionActuator::PySetBlendtime(PyObject* self, - PyObject* args, - PyObject* kwds) { - float blendframe; +/* setChannel */ +KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel, +"setChannel(channel, matrix)\n" +"\t - channel : A string specifying the name of the bone channel.\n" +"\t - matrix : A 4x4 matrix specifying the overriding transformation\n" +"\t as an offset from the bone's rest position.\n") +{ + BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); + char *string; + PyObject *pymat= NULL; + PyObject *pyloc= NULL, *pysize= NULL, *pyquat= NULL; + bPoseChannel *pchan; - if (PyArg_ParseTuple(args,"f",&blendframe)) - { - m_blendframe = blendframe * m_blendin; - if (m_blendframe<0) - m_blendframe = 0; - if (m_blendframe>m_blendin) - m_blendframe = m_blendin; + if(PyTuple_Size(args)==2) { + if (!PyArg_ParseTuple(args,"sO:setChannel", &string, &pymat)) // matrix + return NULL; + } + else if(PyTuple_Size(args)==4) { + if (!PyArg_ParseTuple(args,"sOOO:setChannel", &string, &pyloc, &pysize, &pyquat)) // loc/size/quat + return NULL; } else { + PyErr_SetString(PyExc_ValueError, "Expected a string and a 4x4 matrix (2 args) or a string and loc/size/quat sequences (4 args)"); return NULL; } - Py_RETURN_NONE; -} - -/* setPriority */ -const char BL_ActionActuator::SetPriority_doc[] = -"setPriority(priority)\n" -"\t - priority : Specifies the new priority. Actuators will lower\n" -"\t priority numbers will override actuators with higher\n" -"\t numbers.\n"; - -PyObject* BL_ActionActuator::PySetPriority(PyObject* self, - PyObject* args, - PyObject* kwds) { - int priority; - - if (PyArg_ParseTuple(args,"i",&priority)) - { - m_priority = priority; + if(pymat) { + float matrix[4][4]; + MT_Matrix4x4 mat; + + if(!PyMatTo(pymat, mat)) + return NULL; + + mat.setValue((const float *)matrix); + + BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); + obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ + + if (!m_userpose) { + if(!m_pose) + obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ + game_copy_pose(&m_userpose, m_pose); + } + // pchan= verify_pose_channel(m_userpose, string); // adds the channel if its not there. + pchan= get_pose_channel(m_userpose, string); // adds the channel if its not there. + + if(pchan) { + VECCOPY (pchan->loc, matrix[3]); + Mat4ToSize(matrix, pchan->size); + Mat4ToQuat(matrix, pchan->quat); + } } else { - return NULL; + MT_Vector3 loc; + MT_Vector3 size; + MT_Quaternion quat; + + if (!PyVecTo(pyloc, loc) || !PyVecTo(pysize, size) || !PyQuatTo(pyquat, quat)) + return NULL; + + // same as above + if (!m_userpose) { + if(!m_pose) + obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ + game_copy_pose(&m_userpose, m_pose); + } + // pchan= verify_pose_channel(m_userpose, string); + pchan= get_pose_channel(m_userpose, string); // adds the channel if its not there. + + // for some reason loc.setValue(pchan->loc) fails + if(pchan) { + pchan->loc[0]= loc[0]; pchan->loc[1]= loc[1]; pchan->loc[2]= loc[2]; + pchan->size[0]= size[0]; pchan->size[1]= size[1]; pchan->size[2]= size[2]; + pchan->quat[0]= quat[3]; pchan->quat[1]= quat[0]; pchan->quat[2]= quat[1]; pchan->quat[3]= quat[2]; /* notice xyzw -> wxyz is intentional */ + } } - Py_RETURN_NONE; -} - -/* setFrame */ -const char BL_ActionActuator::SetFrame_doc[] = -"setFrame(frame)\n" -"\t - frame : Specifies the new current frame for the animation\n"; - -PyObject* BL_ActionActuator::PySetFrame(PyObject* self, - PyObject* args, - PyObject* kwds) { - float frame; - - if (PyArg_ParseTuple(args,"f",&frame)) - { - m_localtime = frame; - if (m_localtime<m_startframe) - m_localtime=m_startframe; - else if (m_localtime>m_endframe) - m_localtime=m_endframe; - } - else { + if(pchan==NULL) { + PyErr_SetString(PyExc_ValueError, "Channel could not be found, use the 'channelNames' attribute to get a list of valid channels"); return NULL; } + pchan->flag |= POSE_ROT|POSE_LOC|POSE_SIZE; Py_RETURN_NONE; } -/* setProperty */ -const char BL_ActionActuator::SetProperty_doc[] = -"setProperty(prop)\n" -"\t - prop : A string specifying the property name to be used in\n" -"\t FromProp playback mode.\n"; +/* ------------------------------------------------------------------------- */ +/* Python Integration Hooks */ +/* ------------------------------------------------------------------------- */ -PyObject* BL_ActionActuator::PySetProperty(PyObject* self, - PyObject* args, - PyObject* kwds) { - char *string; - - if (PyArg_ParseTuple(args,"s",&string)) - { - m_propname = string; - } - else { - return NULL; - } - - Py_RETURN_NONE; -} +PyTypeObject BL_ActionActuator::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "BL_ActionActuator", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_IActuator::Type, + 0,0,0,0,0,0, + py_base_new +}; -/* setFrameProperty */ -const char BL_ActionActuator::SetFrameProperty_doc[] = -"setFrameProperty(prop)\n" -"\t - prop : A string specifying the property of the frame set up update.\n"; +PyMethodDef BL_ActionActuator::Methods[] = { + {"getChannel", (PyCFunction) BL_ActionActuator::sPyGetChannel, METH_O}, + KX_PYMETHODTABLE(BL_ActionActuator, setChannel), + {NULL,NULL} //Sentinel +}; -PyObject* BL_ActionActuator::PySetFrameProperty(PyObject* self, - PyObject* args, - PyObject* kwds) { - char *string; - - if (PyArg_ParseTuple(args,"s",&string)) - { - m_framepropname = string; - } - else { - return NULL; - } - - Py_RETURN_NONE; -} +PyAttributeDef BL_ActionActuator::Attributes[] = { + KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ActionActuator, m_startframe), + KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ActionActuator, m_endframe), + KX_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ActionActuator, m_blendin), + KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ActionActuator, pyattr_get_action, pyattr_set_action), + KX_PYATTRIBUTE_RO_FUNCTION("channelNames", BL_ActionActuator, pyattr_get_channel_names), + KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ActionActuator, m_priority), + KX_PYATTRIBUTE_FLOAT_RW_CHECK("frame", 0, MAXFRAMEF, BL_ActionActuator, m_localtime, CheckFrame), + KX_PYATTRIBUTE_STRING_RW("propName", 0, 31, false, BL_ActionActuator, m_propname), + KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 31, false, BL_ActionActuator, m_framepropname), + KX_PYATTRIBUTE_BOOL_RW("useContinue", BL_ActionActuator, m_end_reset), + KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ActionActuator, m_blendframe, CheckBlendTime), + KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ActionActuator,m_playtype,CheckType), + { NULL } //Sentinel +}; -/* -PyObject* BL_ActionActuator::PyGetChannel(PyObject* self, - PyObject* args, - PyObject* kwds) { - char *string; - - if (PyArg_ParseTuple(args,"s",&string)) - { - m_propname = string; - } - else { - return NULL; - } - - Py_RETURN_NONE; +PyObject* BL_ActionActuator::pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v); + return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name+2 : ""); } -*/ - -/* setChannel */ -const char BL_ActionActuator::SetChannel_doc[] = -"setChannel(channel, matrix)\n" -"\t - channel : A string specifying the name of the bone channel.\n" -"\t - matrix : A 4x4 matrix specifying the overriding transformation\n" -"\t as an offset from the bone's rest position.\n"; -PyObject* BL_ActionActuator::PySetChannel(PyObject* self, - PyObject* args, - PyObject* kwds) +int BL_ActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - float matrix[4][4]; - char *string; - PyObject* pylist; - bool error = false; - int row,col; - int mode = 0; /* 0 for bone space, 1 for armature/world space */ - - if (!PyArg_ParseTuple(args,"sO|i", &string, &pylist, &mode)) - return NULL; + BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v); - if (pylist->ob_type == &CListValue::Type) + if (!PyUnicode_Check(value)) { - CListValue* listval = (CListValue*) pylist; - if (listval->GetCount() == 4) - { - for (row=0;row<4;row++) // each row has a 4-vector [x,y,z, w] - { - CListValue* vecval = (CListValue*)listval->GetValue(row); - for (col=0;col<4;col++) - { - matrix[row][col] = vecval->GetValue(col)->GetNumber(); - - } - } - } - else - { - error = true; - } + PyErr_SetString(PyExc_ValueError, "actuator.action = val: Action Actuator, expected the string name of the action"); + return PY_SET_ATTR_FAIL; } - else + + bAction *action= NULL; + STR_String val = _PyUnicode_AsString(value); + + if (val != "") { - // assert the list is long enough... - int numitems = PyList_Size(pylist); - if (numitems == 4) - { - for (row=0;row<4;row++) // each row has a 4-vector [x,y,z, w] - { - - PyObject* veclist = PyList_GetItem(pylist,row); // here we have a vector4 list - for (col=0;col<4;col++) - { - matrix[row][col] = PyFloat_AsDouble(PyList_GetItem(veclist,col)); - - } - } - } - else + action= (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(val); + if (!action) { - error = true; + PyErr_SetString(PyExc_ValueError, "actuator.action = val: Action Actuator, action not found!"); + return PY_SET_ATTR_FAIL; } } - if (!error) - { + self->SetAction(action); + return PY_SET_ATTR_SUCCESS; -/* DO IT HERE */ - bPoseChannel *pchan= verify_pose_channel(m_userpose, string); - - Mat4ToQuat(matrix, pchan->quat); - Mat4ToSize(matrix, pchan->size); - VECCOPY (pchan->loc, matrix[3]); - - pchan->flag |= POSE_ROT|POSE_LOC|POSE_SIZE; +} - if (!m_userpose){ - m_userpose = (bPose*)MEM_callocN(sizeof(bPose), "userPose"); +PyObject* BL_ActionActuator::pyattr_get_channel_names(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v); + PyObject *ret= PyList_New(0); + PyObject *item; + + bPose *pose= ((BL_ArmatureObject*)self->GetParent())->GetOrigPose(); + + if(pose) { + bPoseChannel *pchan; + for(pchan= (bPoseChannel *)pose->chanbase.first; pchan; pchan= (bPoseChannel *)pchan->next) { + item= PyUnicode_FromString(pchan->name); + PyList_Append(ret, item); + Py_DECREF(item); } } - Py_RETURN_NONE; + return ret; } - -/* getType */ -const char BL_ActionActuator::GetType_doc[] = -"getType()\n" -"\tReturns the operation mode of the actuator.\n"; -PyObject* BL_ActionActuator::PyGetType(PyObject* self, - PyObject* args, - PyObject* kwds) { - return Py_BuildValue("h", m_playtype); -} - -/* setType */ -const char BL_ActionActuator::SetType_doc[] = -"setType(mode)\n" -"\t - mode: Play (0), Flipper (2), LoopStop (3), LoopEnd (4) or Property (6)\n" -"\tSet the operation mode of the actuator.\n"; -PyObject* BL_ActionActuator::PySetType(PyObject* self, - PyObject* args, - PyObject* kwds) { - short typeArg; - - if (!PyArg_ParseTuple(args, "h", &typeArg)) { - return NULL; - } - - switch (typeArg) { - case KX_ACT_ACTION_PLAY: - case KX_ACT_ACTION_FLIPPER: - case KX_ACT_ACTION_LOOPSTOP: - case KX_ACT_ACTION_LOOPEND: - case KX_ACT_ACTION_PROPERTY: - m_playtype = typeArg; - break; - default: - printf("Invalid type for action actuator: %d\n", typeArg); /* error */ - } - Py_RETURN_NONE; -} - -PyObject* BL_ActionActuator::PyGetContinue(PyObject* self) { - return PyInt_FromLong((long)(m_end_reset==0)); -} - -PyObject* BL_ActionActuator::PySetContinue(PyObject* self, PyObject* value) { - int param = PyObject_IsTrue( value ); - - if( param == -1 ) { - PyErr_SetString( PyExc_TypeError, "expected True/False or 0/1" ); - return NULL; - } - - if (param) { - m_end_reset = 0; - } else { - m_end_reset = 1; - } - Py_RETURN_NONE; -} - diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h index a67b6d29b74..a6b4c4a055d 100644 --- a/source/gameengine/Converter/BL_ActionActuator.h +++ b/source/gameengine/Converter/BL_ActionActuator.h @@ -32,6 +32,7 @@ #include "GEN_HashedPtr.h" #include "SCA_IActuator.h" +#include "DNA_actuator_types.h" #include "MT_Point3.h" class BL_ActionActuator : public SCA_IActuator @@ -48,9 +49,8 @@ public: short blendin, short priority, short end_reset, - float stride, - PyTypeObject* T=&Type) - : SCA_IActuator(gameobj,T), + float stride) + : SCA_IActuator(gameobj), m_lastpos(0, 0, 0), m_blendframe(0), @@ -80,43 +80,56 @@ public: virtual void ProcessReplica(); void SetBlendTime (float newtime); + + bAction* GetAction() { return m_action; } + void SetAction(bAction* act) { m_action= act; } + + KX_PYMETHOD_O(BL_ActionActuator,GetChannel); + KX_PYMETHOD_DOC(BL_ActionActuator,setChannel); - KX_PYMETHOD_DOC(BL_ActionActuator,SetAction); - KX_PYMETHOD_DOC(BL_ActionActuator,SetBlendin); - KX_PYMETHOD_DOC(BL_ActionActuator,SetPriority); - KX_PYMETHOD_DOC(BL_ActionActuator,SetStart); - KX_PYMETHOD_DOC(BL_ActionActuator,SetEnd); - KX_PYMETHOD_DOC(BL_ActionActuator,SetFrame); - KX_PYMETHOD_DOC(BL_ActionActuator,SetProperty); - KX_PYMETHOD_DOC(BL_ActionActuator,SetFrameProperty); - KX_PYMETHOD_DOC(BL_ActionActuator,SetBlendtime); - KX_PYMETHOD_DOC(BL_ActionActuator,SetChannel); - - KX_PYMETHOD_DOC(BL_ActionActuator,GetAction); - KX_PYMETHOD_DOC(BL_ActionActuator,GetBlendin); - KX_PYMETHOD_DOC(BL_ActionActuator,GetPriority); - KX_PYMETHOD_DOC(BL_ActionActuator,GetStart); - KX_PYMETHOD_DOC(BL_ActionActuator,GetEnd); - KX_PYMETHOD_DOC(BL_ActionActuator,GetFrame); - KX_PYMETHOD_DOC(BL_ActionActuator,GetProperty); - KX_PYMETHOD_DOC(BL_ActionActuator,GetFrameProperty); -// KX_PYMETHOD(BL_ActionActuator,GetChannel); - KX_PYMETHOD_DOC(BL_ActionActuator,GetType); - KX_PYMETHOD_DOC(BL_ActionActuator,SetType); - KX_PYMETHOD_NOARGS(BL_ActionActuator,GetContinue); - KX_PYMETHOD_O(BL_ActionActuator,SetContinue); - - virtual PyObject* _getattr(const STR_String& attr); - - enum ActionActType + static PyObject* pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_channel_names(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + /* attribute check */ + static int CheckFrame(void *self, const PyAttributeDef*) { - KX_ACT_ACTION_PLAY = 0, - KX_ACT_ACTION_FLIPPER = 2, - KX_ACT_ACTION_LOOPSTOP, - KX_ACT_ACTION_LOOPEND, - KX_ACT_ACTION_PROPERTY = 6 - }; + BL_ActionActuator* act = reinterpret_cast<BL_ActionActuator*>(self); + + if (act->m_localtime < act->m_startframe) + act->m_localtime = act->m_startframe; + else if (act->m_localtime > act->m_endframe) + act->m_localtime = act->m_endframe; + + return 0; + } + + static int CheckBlendTime(void *self, const PyAttributeDef*) + { + BL_ActionActuator* act = reinterpret_cast<BL_ActionActuator*>(self); + + if (act->m_blendframe > act->m_blendin) + act->m_blendframe = act->m_blendin; + + return 0; + } + static int CheckType(void *self, const PyAttributeDef*) + { + BL_ActionActuator* act = reinterpret_cast<BL_ActionActuator*>(self); + + switch (act->m_playtype) { + case ACT_ACTION_PLAY: + case ACT_ACTION_FLIPPER: + case ACT_ACTION_LOOP_STOP: + case ACT_ACTION_LOOP_END: + case ACT_ACTION_FROM_PROP: + return 0; + default: + PyErr_SetString(PyExc_ValueError, "Action Actuator, invalid play type supplied"); + return 1; + } + } + protected: void SetStartTime(float curtime); @@ -141,7 +154,7 @@ protected: float m_stridelength; short m_playtype; short m_priority; - short m_end_reset; + bool m_end_reset; struct bPose* m_pose; struct bPose* m_blendpose; struct bPose* m_userpose; diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index d2001212f7d..cfd90813a16 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -38,6 +38,7 @@ #include "DNA_action_types.h" #include "DNA_armature_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "MT_Matrix4x4.h" @@ -48,17 +49,19 @@ BL_ArmatureObject::BL_ArmatureObject( void* sgReplicationInfo, SG_Callbacks callbacks, - Object *armature ) + Object *armature, + Scene *scene) : KX_GameObject(sgReplicationInfo,callbacks), m_objArma(armature), m_framePose(NULL), + m_scene(scene), // maybe remove later. needed for where_is_pose m_lastframe(0.0), m_activeAct(NULL), m_activePriority(999), m_lastapplyframe(0.0) { - m_armature = get_armature(m_objArma); + m_armature = (bArmature *)armature->data; /* we make a copy of blender object's pose, and then always swap it with * the original pose before calling into blender functions, to deal with @@ -70,20 +73,17 @@ BL_ArmatureObject::BL_ArmatureObject( CValue* BL_ArmatureObject::GetReplica() { BL_ArmatureObject* replica = new BL_ArmatureObject(*this); - - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - - ProcessReplica(replica); + replica->ProcessReplica(); return replica; } -void BL_ArmatureObject::ProcessReplica(BL_ArmatureObject *replica) +void BL_ArmatureObject::ProcessReplica() { - KX_GameObject::ProcessReplica(replica); + bPose *pose= m_pose; + KX_GameObject::ProcessReplica(); - replica->m_pose = NULL; - game_copy_pose(&replica->m_pose, m_pose); + m_pose = NULL; + game_copy_pose(&m_pose, pose); } BL_ArmatureObject::~BL_ArmatureObject() @@ -96,9 +96,9 @@ void BL_ArmatureObject::ApplyPose() { m_armpose = m_objArma->pose; m_objArma->pose = m_pose; - + //m_scene->r.cfra++; if(m_lastapplyframe != m_lastframe) { - where_is_pose(m_objArma); + where_is_pose(m_scene, m_objArma); // XXX m_lastapplyframe = m_lastframe; } } diff --git a/source/gameengine/Converter/BL_ArmatureObject.h b/source/gameengine/Converter/BL_ArmatureObject.h index d68e37d9e37..af0b7dc201c 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.h +++ b/source/gameengine/Converter/BL_ArmatureObject.h @@ -45,13 +45,14 @@ class BL_ArmatureObject : public KX_GameObject public: double GetLastFrame (); short GetActivePriority(); - virtual void ProcessReplica(BL_ArmatureObject *replica); + virtual void ProcessReplica(); class BL_ActionActuator * GetActiveAction(); BL_ArmatureObject( void* sgReplicationInfo, SG_Callbacks callbacks, - Object *armature + Object *armature, + Scene *scene ); virtual ~BL_ArmatureObject(); @@ -59,6 +60,7 @@ public: void GetMRDPose(struct bPose **pose); void GetPose(struct bPose **pose); void SetPose (struct bPose *pose); + struct bPose *GetOrigPose() {return m_pose;} // never edit this, only for accessing names void ApplyPose(); void RestorePose(); @@ -67,6 +69,7 @@ public: struct bArmature * GetArmature() { return m_armature; } const struct bArmature * GetArmature() const { return m_armature; } + const struct Scene * GetScene() const { return m_scene; } Object* GetArmatureObject() {return m_objArma;} @@ -84,11 +87,19 @@ protected: struct bPose *m_pose; struct bPose *m_armpose; struct bPose *m_framePose; + struct Scene *m_scene; // need for where_is_pose double m_lastframe; class BL_ActionActuator *m_activeAct; short m_activePriority; double m_lastapplyframe; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_ArmatureObject"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 9c699b67b28..230820719aa 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -90,6 +90,7 @@ #include "BKE_object.h" #include "BKE_scene.h" #include "BL_SkinMeshObject.h" +#include "BL_ModifierDeformer.h" #include "BL_ShapeDeformer.h" #include "BL_SkinDeformer.h" #include "BL_MeshDeformer.h" @@ -100,9 +101,6 @@ #include "KX_KetsjiEngine.h" #include "KX_BlenderSceneConverter.h" -#include"SND_Scene.h" -#include "SND_SoundListener.h" - /* This little block needed for linking to Blender... */ #ifdef WIN32 #include "BLI_winstuff.h" @@ -162,9 +160,12 @@ extern "C" { #include "SG_BBox.h" #include "SG_Tree.h" -// defines USE_ODE to choose physics engine #include "KX_ConvertPhysicsObject.h" - +#ifdef USE_BULLET +#include "CcdPhysicsEnvironment.h" +#include "CcdGraphicController.h" +#endif +#include "KX_MotionState.h" // This file defines relationships between parents and children // in the game engine. @@ -178,8 +179,8 @@ extern "C" { #ifdef __cplusplus extern "C" { #endif -#include "BSE_headerbuttons.h" -void update_for_newframe(); +//XXX #include "BSE_headerbuttons.h" +//XXX void update_for_newframe(); //void scene_update_for_newframe(struct Scene *sce, unsigned int lay); //#include "BKE_ipo.h" //void do_all_data_ipos(void); @@ -313,20 +314,17 @@ typedef struct MTF_localLayer }MTF_localLayer; // ------------------------------------ -BL_Material* ConvertMaterial( +bool ConvertMaterial( + BL_Material *material, Material *mat, MTFace* tface, const char *tfaceName, MFace* mface, - MCol* mmcol, - int lightlayer, - Object* blenderobj, + MCol* mmcol, MTF_localLayer *layers, bool glslmat) { - //this needs some type of manager - BL_Material *material = new BL_Material(); - + material->Initialize(); int numchan = -1, texalpha = 0; bool validmat = (mat!=0); bool validface = (tface!=0); @@ -337,6 +335,7 @@ BL_Material* ConvertMaterial( material->IdMode = DEFAULT_BLENDER; material->glslmat = (validmat)? glslmat: false; + material->materialindex = mface->mat_nr; // -------------------------------- if(validmat) { @@ -361,7 +360,7 @@ BL_Material* ConvertMaterial( facetex = true; if(validface && mat->mtex[0]) { MTex *tmp = mat->mtex[0]; - if(!tmp->tex || tmp->tex && !tmp->tex->ima ) + if(!tmp->tex || (tmp->tex && !tmp->tex->ima)) facetex = true; } numchan = numchan>MAXTEX?MAXTEX:numchan; @@ -555,7 +554,7 @@ BL_Material* ConvertMaterial( material->ref = mat->ref; material->amb = mat->amb; - material->ras_mode |= (mat->mode & MA_WIRE)? WIRE: 0; + material->ras_mode |= (mat->material_type == MA_TYPE_WIRE)? WIRE: 0; } else { int valid = 0; @@ -593,26 +592,23 @@ BL_Material* ConvertMaterial( MT_Point2 uv2[4]; const char *uvName = "", *uv2Name = ""; - uv[0]= uv[1]= uv[2]= uv[3]= MT_Point2(0.0f, 0.0f); + uv2[0]= uv2[1]= uv2[2]= uv2[3]= MT_Point2(0.0f, 0.0f); if( validface ) { - material->ras_mode |= !( - (mface->flag & ME_HIDE) || - (tface->mode & TF_INVISIBLE) - )?POLY_VIS:0; + material->ras_mode |= (tface->mode & TF_INVISIBLE)?0:POLY_VIS; material->transp = tface->transp; material->tile = tface->tile; material->mode = tface->mode; - uv[0] = MT_Point2(tface->uv[0]); - uv[1] = MT_Point2(tface->uv[1]); - uv[2] = MT_Point2(tface->uv[2]); + uv[0].setValue(tface->uv[0]); + uv[1].setValue(tface->uv[1]); + uv[2].setValue(tface->uv[2]); if (mface->v4) - uv[3] = MT_Point2(tface->uv[3]); + uv[3].setValue(tface->uv[3]); uvName = tfaceName; } @@ -622,10 +618,12 @@ BL_Material* ConvertMaterial( material->mode = default_face_mode; material->transp = TF_SOLID; material->tile = 0; + + uv[0]= uv[1]= uv[2]= uv[3]= MT_Point2(0.0f, 0.0f); } // with ztransp enabled, enforce alpha blending mode - if(validmat && (mat->mode & MA_ZTRA) && (material->transp == TF_SOLID)) + if(validmat && (mat->mode & MA_TRANSP) && (mat->mode & MA_ZTRANSP) && (material->transp == TF_SOLID)) material->transp = TF_ALPHA; // always zsort alpha + add @@ -665,14 +663,14 @@ BL_Material* ConvertMaterial( { MT_Point2 uvSet[4]; - uvSet[0] = MT_Point2(layer.face->uv[0]); - uvSet[1] = MT_Point2(layer.face->uv[1]); - uvSet[2] = MT_Point2(layer.face->uv[2]); + uvSet[0].setValue(layer.face->uv[0]); + uvSet[1].setValue(layer.face->uv[1]); + uvSet[2].setValue(layer.face->uv[2]); if (mface->v4) - uvSet[3] = MT_Point2(layer.face->uv[3]); + uvSet[3].setValue(layer.face->uv[3]); else - uvSet[3] = MT_Point2(0.0f, 0.0f); + uvSet[3].setValue(0.0f, 0.0f); if (isFirstSet) { @@ -715,16 +713,18 @@ BL_Material* ConvertMaterial( material->tface = tface; material->material = mat; - return material; + return true; } - -RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* rendertools, KX_Scene* scene, KX_BlenderSceneConverter *converter) +/* blenderobj can be NULL, make sure its checked for */ +RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene, KX_BlenderSceneConverter *converter) { RAS_MeshObject *meshobj; bool skinMesh = false; - int lightlayer = blenderobj->lay; + int lightlayer = blenderobj ? blenderobj->lay:(1<<20)-1; // all layers if no object. + if ((meshobj = converter->FindGameMesh(mesh/*, ob->lay*/)) != NULL) + return meshobj; // Get DerivedMesh data DerivedMesh *dm = CDDM_from_mesh(mesh, blenderobj); @@ -744,13 +744,13 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* } // Determine if we need to make a skinned mesh - if (mesh->dvert || mesh->key || ((blenderobj->gameflag & OB_SOFT_BODY) != 0)) + if (blenderobj && (mesh->dvert || mesh->key || ((blenderobj->gameflag & OB_SOFT_BODY) != 0) || BL_ModifierDeformer::HasCompatibleDeformer(blenderobj))) { - meshobj = new BL_SkinMeshObject(mesh, lightlayer); + meshobj = new BL_SkinMeshObject(mesh); skinMesh = true; } else - meshobj = new RAS_MeshObject(mesh, lightlayer); + meshobj = new RAS_MeshObject(mesh); // Extract avaiable layers MTF_localLayer *layers = new MTF_localLayer[MAX_MTFACE]; @@ -776,6 +776,13 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* meshobj->SetName(mesh->id.name); meshobj->m_sharedvertex_map.resize(totvert); + RAS_IPolyMaterial* polymat = NULL; + STR_String imastr; + // These pointers will hold persistent material structure during the conversion + // to avoid countless allocation/deallocation of memory. + BL_Material* bl_mat = NULL; + KX_BlenderMaterial* kx_blmat = NULL; + KX_PolygonMaterial* kx_polymat = NULL; for (int f=0;f<totface;f++,mface++) { @@ -790,10 +797,10 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* MT_Vector4 tan0(0,0,0,0), tan1(0,0,0,0), tan2(0,0,0,0), tan3(0,0,0,0); /* get coordinates, normals and tangents */ - pt0 = MT_Point3(mvert[mface->v1].co); - pt1 = MT_Point3(mvert[mface->v2].co); - pt2 = MT_Point3(mvert[mface->v3].co); - pt3 = (mface->v4)? MT_Point3(mvert[mface->v4].co): MT_Point3(0.0, 0.0, 0.0); + pt0.setValue(mvert[mface->v1].co); + pt1.setValue(mvert[mface->v2].co); + pt2.setValue(mvert[mface->v3].co); + if (mface->v4) pt3.setValue(mvert[mface->v4].co); if(mface->flag & ME_SMOOTH) { float n0[3], n1[3], n2[3], n3[3]; @@ -832,13 +839,11 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* tan3 = tangent[f*4 + 3]; } - /* get material */ - ma = give_current_material(blenderobj, mface->mat_nr+1); - + ma = give_current_material(blenderobj, mface->mat_nr+1); + { bool visible = true; - RAS_IPolyMaterial* polymat = NULL; - BL_Material *bl_mat = NULL; + bool twoside = false; if(converter->GetMaterials()) { /* do Blender Multitexture and Blender GLSL materials */ @@ -846,13 +851,14 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* MT_Point2 uv[4]; /* first is the BL_Material */ - bl_mat = ConvertMaterial(ma, tface, tfaceName, mface, mcol, - lightlayer, blenderobj, layers, converter->GetGLSLMaterials()); - - bl_mat->material_index = (int)mface->mat_nr; + if (!bl_mat) + bl_mat = new BL_Material(); + ConvertMaterial(bl_mat, ma, tface, tfaceName, mface, mcol, + layers, converter->GetGLSLMaterials()); visible = ((bl_mat->ras_mode & POLY_VIS)!=0); collider = ((bl_mat->ras_mode & COLLIDER)!=0); + twoside = ((bl_mat->mode & TF_TWOSIDE)!=0); /* vertex colors and uv's were stored in bl_mat temporarily */ bl_mat->GetConversionRGB(rgb); @@ -868,12 +874,16 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* uv22 = uv[2]; uv23 = uv[3]; /* then the KX_BlenderMaterial */ - polymat = new KX_BlenderMaterial(scene, bl_mat, skinMesh, lightlayer); + if (kx_blmat == NULL) + kx_blmat = new KX_BlenderMaterial(); + + kx_blmat->Initialize(scene, bl_mat, skinMesh); + polymat = static_cast<RAS_IPolyMaterial*>(kx_blmat); } else { /* do Texture Face materials */ Image* bima = (tface)? (Image*)tface->tpage: NULL; - STR_String imastr = (tface)? (bima? (bima)->id.name : "" ) : ""; + imastr = (tface)? (bima? (bima)->id.name : "" ) : ""; char transp=0; short mode=0, tile=0; @@ -892,14 +902,15 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* tile = tface->tile; mode = tface->mode; - visible = !((mface->flag & ME_HIDE)||(tface->mode & TF_INVISIBLE)); + visible = !(tface->mode & TF_INVISIBLE); + twoside = ((tface->mode & TF_TWOSIDE)!=0); - uv0 = MT_Point2(tface->uv[0]); - uv1 = MT_Point2(tface->uv[1]); - uv2 = MT_Point2(tface->uv[2]); + uv0.setValue(tface->uv[0]); + uv1.setValue(tface->uv[1]); + uv2.setValue(tface->uv[2]); if (mface->v4) - uv3 = MT_Point2(tface->uv[3]); + uv3.setValue(tface->uv[3]); } else { /* no texfaces, set COLLSION true and everything else FALSE */ @@ -950,9 +961,12 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* bool alpha = (transp == TF_ALPHA || transp == TF_ADD); bool zsort = (mode & TF_ALPHASORT)? alpha: 0; - polymat = new KX_PolygonMaterial(imastr, ma, + if (kx_polymat == NULL) + kx_polymat = new KX_PolygonMaterial(); + kx_polymat->Initialize(imastr, ma, (int)mface->mat_nr, tile, tilexrep, tileyrep, mode, transp, alpha, zsort, lightlayer, tface, (unsigned int*)mcol); + polymat = static_cast<RAS_IPolyMaterial*>(kx_polymat); if (ma) { polymat->m_specular = MT_Vector3(ma->specr, ma->specg, ma->specb)*ma->spec; @@ -960,7 +974,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* polymat->m_diffuse = MT_Vector3(ma->r, ma->g, ma->b)*(ma->emit + ma->ref); } else { - polymat->m_specular = MT_Vector3(0.0f,0.0f,0.0f); + polymat->m_specular.setValue(0.0f,0.0f,0.0f); polymat->m_shininess = 35.0; } } @@ -977,15 +991,17 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* converter->RegisterPolyMaterial(polymat); if(converter->GetMaterials()) { converter->RegisterBlenderMaterial(bl_mat); + // the poly material has been stored in the bucket, next time we must create a new one + bl_mat = NULL; + kx_blmat = NULL; + } else { + // the poly material has been stored in the bucket, next time we must create a new one + kx_polymat = NULL; } } else { - // delete the material objects since they are no longer needed // from now on, use the polygon material from the material bucket - delete polymat; - if(converter->GetMaterials()) { - delete bl_mat; - } polymat = bucket->GetPolyMaterial(); + // keep the material pointers, they will be reused for next face } int nverts = (mface->v4)? 4: 3; @@ -993,6 +1009,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* poly->SetVisible(visible); poly->SetCollider(collider); + poly->SetTwoside(twoside); //poly->SetEdgeCode(mface->edcode); meshobj->AddVertex(poly,0,pt0,uv0,uv20,tan0,rgb0,no0,flat,mface->v1); @@ -1016,26 +1033,35 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* layer.face++; } } - meshobj->m_sharedvertex_map.clear(); + // keep meshobj->m_sharedvertex_map for reinstance phys mesh. + // 2.49a and before it did: meshobj->m_sharedvertex_map.clear(); + // but this didnt save much ram. - Campbell + meshobj->EndConversion(); // pre calculate texture generation for(list<RAS_MeshMaterial>::iterator mit = meshobj->GetFirstMaterial(); mit != meshobj->GetLastMaterial(); ++ mit) { - mit->m_bucket->GetPolyMaterial()->OnConstruction(); + mit->m_bucket->GetPolyMaterial()->OnConstruction(lightlayer); } if (layers) delete []layers; dm->release(dm); - + // cleanup material + if (bl_mat) + delete bl_mat; + if (kx_blmat) + delete kx_blmat; + if (kx_polymat) + delete kx_polymat; + converter->RegisterGameMesh(meshobj, mesh); return meshobj; } -static PHY_MaterialProps *CreateMaterialFromBlenderObject(struct Object* blenderobject, - KX_Scene *kxscene) +static PHY_MaterialProps *CreateMaterialFromBlenderObject(struct Object* blenderobject) { PHY_MaterialProps *materialProps = new PHY_MaterialProps; @@ -1068,8 +1094,7 @@ static PHY_MaterialProps *CreateMaterialFromBlenderObject(struct Object* blender return materialProps; } -static PHY_ShapeProps *CreateShapePropsFromBlenderObject(struct Object* blenderobject, - KX_Scene *kxscene) +static PHY_ShapeProps *CreateShapePropsFromBlenderObject(struct Object* blenderobject) { PHY_ShapeProps *shapeProps = new PHY_ShapeProps; @@ -1097,6 +1122,10 @@ static PHY_ShapeProps *CreateShapePropsFromBlenderObject(struct Object* blendero shapeProps->m_do_fh = (blenderobject->gameflag & OB_DO_FH) != 0; shapeProps->m_do_rot_fh = (blenderobject->gameflag & OB_ROT_FH) != 0; +// velocity clamping XXX + shapeProps->m_clamp_vel_min = blenderobject->min_vel; + shapeProps->m_clamp_vel_max = blenderobject->max_vel; + return shapeProps; } @@ -1114,6 +1143,7 @@ static float my_boundbox_mesh(Mesh *me, float *loc, float *size) BoundBox *bb; MT_Point3 min, max; float mloc[3], msize[3]; + float radius=0.0f, vert_radius, *co; int a; if(me->bb==0) me->bb= (struct BoundBox *)MEM_callocN(sizeof(BoundBox), "boundbox"); @@ -1126,7 +1156,15 @@ static float my_boundbox_mesh(Mesh *me, float *loc, float *size) mvert= me->mvert; for(a=0; a<me->totvert; a++, mvert++) { - DO_MINMAX(mvert->co, min, max); + co= mvert->co; + + /* bounds */ + DO_MINMAX(co, min, max); + + /* radius */ + vert_radius= co[0]*co[0] + co[1]*co[1] + co[2]*co[2]; + if (vert_radius > radius) + radius= vert_radius; } if(me->totvert) { @@ -1152,13 +1190,6 @@ static float my_boundbox_mesh(Mesh *me, float *loc, float *size) bb->vec[0][2]=bb->vec[3][2]=bb->vec[4][2]=bb->vec[7][2]= loc[2]-size[2]; bb->vec[1][2]=bb->vec[2][2]=bb->vec[5][2]=bb->vec[6][2]= loc[2]+size[2]; - float radius = 0; - for (a=0, mvert = me->mvert; a < me->totvert; a++, mvert++) - { - float vert_radius = MT_Vector3(mvert->co).length2(); - if (vert_radius > radius) - radius = vert_radius; - } return sqrt(radius); } @@ -1215,18 +1246,34 @@ static void my_tex_space_mesh(Mesh *me) } -static void my_get_local_bounds(Object *ob, float *center, float *size) +static void my_get_local_bounds(Object *ob, DerivedMesh *dm, float *center, float *size) { BoundBox *bb= NULL; /* uses boundbox, function used by Ketsji */ switch (ob->type) { case OB_MESH: - bb= ( (Mesh *)ob->data )->bb; - if(bb==0) + if (dm) + { + float min_r[3], max_r[3]; + INIT_MINMAX(min_r, max_r); + dm->getMinMax(dm, min_r, max_r); + size[0]= 0.5*fabs(max_r[0] - min_r[0]); + size[1]= 0.5*fabs(max_r[1] - min_r[1]); + size[2]= 0.5*fabs(max_r[2] - min_r[2]); + + center[0]= 0.5*(max_r[0] + min_r[0]); + center[1]= 0.5*(max_r[1] + min_r[1]); + center[2]= 0.5*(max_r[2] + min_r[2]); + return; + } else { - my_tex_space_mesh((struct Mesh *)ob->data); bb= ( (Mesh *)ob->data )->bb; + if(bb==0) + { + my_tex_space_mesh((struct Mesh *)ob->data); + bb= ( (Mesh *)ob->data )->bb; + } } break; case OB_CURVE: @@ -1263,8 +1310,44 @@ static void my_get_local_bounds(Object *ob, float *center, float *size) ////////////////////////////////////////////////////// - - +void BL_CreateGraphicObjectNew(KX_GameObject* gameobj, + const MT_Point3& localAabbMin, + const MT_Point3& localAabbMax, + KX_Scene* kxscene, + bool isActive, + e_PhysicsEngine physics_engine) +{ + if (gameobj->GetMeshCount() > 0) + { + switch (physics_engine) + { +#ifdef USE_BULLET + case UseBullet: + { + CcdPhysicsEnvironment* env = (CcdPhysicsEnvironment*)kxscene->GetPhysicsEnvironment(); + assert(env); + PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode()); + CcdGraphicController* ctrl = new CcdGraphicController(env, motionstate); + gameobj->SetGraphicController(ctrl); + ctrl->setNewClientInfo(gameobj->getClientInfo()); + ctrl->setLocalAabb(localAabbMin, localAabbMax); + if (isActive) { + // add first, this will create the proxy handle, only if the object is visible + if (gameobj->GetVisible()) + env->addCcdGraphicController(ctrl); + // update the mesh if there is a deformer, this will also update the bounding box for modifiers + RAS_Deformer* deformer = gameobj->GetDeformer(); + if (deformer) + deformer->UpdateBuckets(); + } + } + break; +#endif + default: + break; + } + } +} void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, struct Object* blenderobject, @@ -1292,10 +1375,13 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, } bool isCompoundChild = false; + bool hasCompoundChildren = !parent && (blenderobject->gameflag & OB_CHILD); - if (parent && (parent->gameflag & OB_DYNAMIC)) { + /* When the parent is not OB_DYNAMIC and has no OB_COLLISION then it gets no bullet controller + * and cant be apart of the parents compound shape */ + if (parent && (parent->gameflag & (OB_DYNAMIC | OB_COLLISION))) { - if ((parent->gameflag & OB_CHILD) != 0) + if ((parent->gameflag & OB_CHILD) != 0 && (blenderobject->gameflag & OB_CHILD)) { isCompoundChild = true; } @@ -1305,24 +1391,41 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, PHY_ShapeProps* shapeprops = - CreateShapePropsFromBlenderObject(blenderobject, - kxscene); + CreateShapePropsFromBlenderObject(blenderobject); PHY_MaterialProps* smmaterial = - CreateMaterialFromBlenderObject(blenderobject, kxscene); + CreateMaterialFromBlenderObject(blenderobject); KX_ObjectProperties objprop; + objprop.m_lockXaxis = (blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_X_AXIS) !=0; + objprop.m_lockYaxis = (blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Y_AXIS) !=0; + objprop.m_lockZaxis = (blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Z_AXIS) !=0; + objprop.m_lockXRotaxis = (blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_X_ROT_AXIS) !=0; + objprop.m_lockYRotaxis = (blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Y_ROT_AXIS) !=0; + objprop.m_lockZRotaxis = (blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Z_ROT_AXIS) !=0; objprop.m_isCompoundChild = isCompoundChild; - objprop.m_hasCompoundChildren = (blenderobject->gameflag & OB_CHILD) != 0; + objprop.m_hasCompoundChildren = hasCompoundChildren; objprop.m_margin = blenderobject->margin; + // ACTOR is now a separate feature objprop.m_isactor = (blenderobject->gameflag & OB_ACTOR)!=0; objprop.m_dyna = (blenderobject->gameflag & OB_DYNAMIC) != 0; objprop.m_softbody = (blenderobject->gameflag & OB_SOFT_BODY) != 0; objprop.m_angular_rigidbody = (blenderobject->gameflag & OB_RIGID_BODY) != 0; + ///contact processing threshold is only for rigid bodies and static geometry, not 'dynamic' + if (objprop.m_angular_rigidbody || !objprop.m_dyna ) + { + objprop.m_contactProcessingThreshold = blenderobject->m_contactProcessingThreshold; + } else + { + objprop.m_contactProcessingThreshold = 0.f; + } + + objprop.m_sensor = (blenderobject->gameflag & OB_SENSOR) != 0; + if (objprop.m_softbody) { ///for game soft bodies @@ -1363,7 +1466,9 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, objprop.m_soft_kAHR= blenderobject->bsoft->kAHR; /* Anchors hardness [0,1] */ objprop.m_soft_collisionflags= blenderobject->bsoft->collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */ objprop.m_soft_numclusteriterations= blenderobject->bsoft->numclusteriterations; /* number of iterations to refine collision clusters*/ - + objprop.m_soft_welding = blenderobject->bsoft->welding; /* welding */ + objprop.m_margin = blenderobject->bsoft->margin; + objprop.m_contactProcessingThreshold = 0.f; } else { objprop.m_gamesoftFlag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT; @@ -1402,6 +1507,9 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, objprop.m_soft_kAHR= 0.7f; objprop.m_soft_collisionflags= OB_BSB_COL_SDF_RS + OB_BSB_COL_VF_SS; objprop.m_soft_numclusteriterations= 16; + objprop.m_soft_welding = 0.f; + objprop.m_margin = 0.f; + objprop.m_contactProcessingThreshold = 0.f; } } @@ -1421,7 +1529,10 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, } KX_BoxBounds bb; - my_get_local_bounds(blenderobject,objprop.m_boundobject.box.m_center,bb.m_extends); + DerivedMesh* dm = NULL; + if (gameobj->GetDeformer()) + dm = gameobj->GetDeformer()->GetFinalMesh(); + my_get_local_bounds(blenderobject,dm,objprop.m_boundobject.box.m_center,bb.m_extends); if (blenderobject->gameflag & OB_BOUNDS) { switch (blenderobject->boundtype) @@ -1473,12 +1584,13 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, } - if (parent && (parent->gameflag & OB_DYNAMIC)) { - + if (parent/* && (parent->gameflag & OB_DYNAMIC)*/) { + // parented object cannot be dynamic KX_GameObject *parentgameobject = converter->FindGameObject(parent); objprop.m_dynamic_parent = parentgameobject; //cannot be dynamic: objprop.m_dyna = false; + objprop.m_softbody = false; shapeprops->m_mass = 0.f; } @@ -1489,22 +1601,10 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, { #ifdef USE_BULLET case UseBullet: - KX_ConvertBulletObject(gameobj, meshobj, kxscene, shapeprops, smmaterial, &objprop); + KX_ConvertBulletObject(gameobj, meshobj, dm, kxscene, shapeprops, smmaterial, &objprop); break; #endif -#ifdef USE_SUMO_SOLID - case UseSumo: - KX_ConvertSumoObject(gameobj, meshobj, kxscene, shapeprops, smmaterial, &objprop); - break; -#endif - -#ifdef USE_ODE - case UseODE: - KX_ConvertODEEngineObject(gameobj, meshobj, kxscene, shapeprops, smmaterial, &objprop); - break; -#endif //USE_ODE - case UseDynamo: //KX_ConvertDynamoObject(gameobj,meshobj,kxscene,shapeprops, smmaterial, &objprop); break; @@ -1564,7 +1664,7 @@ static KX_LightObject *gamelight_from_blamp(Object *ob, Lamp *la, unsigned int l static KX_Camera *gamecamera_from_bcamera(Object *ob, KX_Scene *kxscene, KX_BlenderSceneConverter *converter) { Camera* ca = static_cast<Camera*>(ob->data); - RAS_CameraData camdata(ca->lens, ca->clipsta, ca->clipend, ca->type == CAM_PERSP, dof_camera(ob)); + RAS_CameraData camdata(ca->lens, ca->ortho_scale, ca->clipsta, ca->clipend, ca->type == CAM_PERSP, dof_camera(ob)); KX_Camera *gamecamera; gamecamera= new KX_Camera(kxscene, KX_Scene::m_callbacks, camdata); @@ -1579,8 +1679,7 @@ static KX_GameObject *gameobject_from_blenderobject( Object *ob, KX_Scene *kxscene, RAS_IRenderTools *rendertools, - KX_BlenderSceneConverter *converter, - Scene *blenderscene) + KX_BlenderSceneConverter *converter) { KX_GameObject *gameobj = NULL; @@ -1612,14 +1711,9 @@ static KX_GameObject *gameobject_from_blenderobject( case OB_MESH: { Mesh* mesh = static_cast<Mesh*>(ob->data); - RAS_MeshObject* meshobj = converter->FindGameMesh(mesh, ob->lay); float center[3], extents[3]; float radius = my_boundbox_mesh((Mesh*) ob->data, center, extents); - - if (!meshobj) { - meshobj = BL_ConvertMesh(mesh,ob,rendertools,kxscene,converter); - converter->RegisterGameMesh(meshobj, mesh); - } + RAS_MeshObject* meshobj = BL_ConvertMesh(mesh,ob,kxscene,converter); // needed for python scripting kxscene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj); @@ -1634,14 +1728,22 @@ static KX_GameObject *gameobject_from_blenderobject( bool ignoreActivityCulling = ((ob->gameflag2 & OB_NEVER_DO_ACTIVITY_CULLING)!=0); gameobj->SetIgnoreActivityCulling(ignoreActivityCulling); + gameobj->SetOccluder((ob->gameflag & OB_OCCLUDER) != 0, false); // two options exists for deform: shape keys and armature // only support relative shape key bool bHasShapeKey = mesh->key != NULL && mesh->key->type==KEY_RELATIVE; bool bHasDvert = mesh->dvert != NULL && ob->defbase.first; bool bHasArmature = (ob->parent && ob->parent->type == OB_ARMATURE && ob->partype==PARSKEL && bHasDvert); + bool bHasModifier = BL_ModifierDeformer::HasCompatibleDeformer(ob); - if (bHasShapeKey) { + if (bHasModifier) { + BL_ModifierDeformer *dcont = new BL_ModifierDeformer((BL_DeformableGameObject *)gameobj, + kxscene->GetBlenderScene(), ob, (BL_SkinMeshObject *)meshobj); + ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont); + if (bHasShapeKey && bHasArmature) + dcont->LoadShapeDrivers(ob->parent); + } else if (bHasShapeKey) { // not that we can have shape keys without dvert! BL_ShapeDeformer *dcont = new BL_ShapeDeformer((BL_DeformableGameObject*)gameobj, ob, (BL_SkinMeshObject*)meshobj); @@ -1675,7 +1777,8 @@ static KX_GameObject *gameobject_from_blenderobject( gameobj = new BL_ArmatureObject( kxscene, KX_Scene::m_callbacks, - ob // handle + ob, + kxscene->GetBlenderScene() // handle ); /* Get the current pose from the armature object and apply it as the rest pose */ break; @@ -1690,7 +1793,6 @@ static KX_GameObject *gameobject_from_blenderobject( } if (gameobj) { - gameobj->SetPhysicsEnvironment(kxscene->GetPhysicsEnvironment()); gameobj->SetLayer(ob->lay); gameobj->SetBlenderObject(ob); /* set the visibility state based on the objects render option in the outliner */ @@ -1705,7 +1807,7 @@ struct parentChildLink { }; #include "DNA_constraint_types.h" -#include "BIF_editconstraint.h" +//XXX #include "BIF_editconstraint.h" bPoseChannel *get_active_posechannel2 (Object *ob) { @@ -1726,7 +1828,8 @@ ListBase *get_active_constraints2(Object *ob) if (!ob) return NULL; - if (ob->flag & OB_POSEMODE) { + // XXX - shouldnt we care about the pose data and not the mode??? + if (ob->mode & OB_MODE_POSE) { bPoseChannel *pchan; pchan = get_active_posechannel2(ob); @@ -1789,12 +1892,10 @@ KX_GameObject* getGameOb(STR_String busc,CListValue* sumolist){ // convert blender objects into ketsji gameobjects void BL_ConvertBlenderObjects(struct Main* maggie, - const STR_String& scenename, KX_Scene* kxscene, KX_KetsjiEngine* ketsjiEngine, e_PhysicsEngine physics_engine, PyObject* pythondictionary, - SCA_IInputDevice* keydev, RAS_IRenderTools* rendertools, RAS_ICanvas* canvas, KX_BlenderSceneConverter* converter, @@ -1802,7 +1903,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, ) { - Scene *blenderscene = converter->GetBlenderSceneForName(scenename); + Scene *blenderscene = kxscene->GetBlenderScene(); // for SETLOOPER Scene *sce; Base *base; @@ -1823,42 +1924,41 @@ void BL_ConvertBlenderObjects(struct Main* maggie, aspect_width = canvas->GetWidth(); aspect_height = canvas->GetHeight(); } else { - if (blenderscene->framing.type == SCE_GAMEFRAMING_BARS) { + if (blenderscene->gm.framing.type == SCE_GAMEFRAMING_BARS) { frame_type = RAS_FrameSettings::e_frame_bars; - } else if (blenderscene->framing.type == SCE_GAMEFRAMING_EXTEND) { + } else if (blenderscene->gm.framing.type == SCE_GAMEFRAMING_EXTEND) { frame_type = RAS_FrameSettings::e_frame_extend; } else { frame_type = RAS_FrameSettings::e_frame_scale; } - aspect_width = blenderscene->r.xsch; - aspect_height = blenderscene->r.ysch; + aspect_width = blenderscene->gm.xsch; + aspect_height = blenderscene->gm.ysch; } RAS_FrameSettings frame_settings( frame_type, - blenderscene->framing.col[0], - blenderscene->framing.col[1], - blenderscene->framing.col[2], + blenderscene->gm.framing.col[0], + blenderscene->gm.framing.col[1], + blenderscene->gm.framing.col[2], aspect_width, aspect_height ); kxscene->SetFramingType(frame_settings); - kxscene->SetGravity(MT_Vector3(0,0,(blenderscene->world != NULL) ? -blenderscene->world->gravity : -9.8)); + kxscene->SetGravity(MT_Vector3(0,0, -blenderscene->gm.gravity)); /* set activity culling parameters */ - if (blenderscene->world) { - kxscene->SetActivityCulling( (blenderscene->world->mode & WO_ACTIVITY_CULLING) != 0); - kxscene->SetActivityCullingRadius(blenderscene->world->activityBoxRadius); - } else { - kxscene->SetActivityCulling(false); - } + kxscene->SetActivityCulling( (blenderscene->gm.mode & WO_ACTIVITY_CULLING) != 0); + kxscene->SetActivityCullingRadius(blenderscene->gm.activityBoxRadius); + kxscene->SetDbvtCulling((blenderscene->gm.mode & WO_DBVT_CULLING) != 0); + // no occlusion culling by default + kxscene->SetDbvtOcclusionRes(0); + int activeLayerBitInfo = blenderscene->lay; - // templist to find Root Parents (object with no parents) - CListValue* templist = new CListValue(); + // list of all object converted, active and inactive CListValue* sumolist = new CListValue(); vector<parentChildLink> vec_parent_child; @@ -1895,8 +1995,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, base->object, kxscene, rendertools, - converter, - blenderscene); + converter); bool isInActiveLayer = (blenderobject->lay & activeLayerBitInfo) !=0; bool addobj=true; @@ -1911,25 +2010,18 @@ void BL_ConvertBlenderObjects(struct Main* maggie, MT_Matrix3x3 angor; if (converter->addInitFromFrame) blenderscene->r.cfra=blenderscene->r.sfra; - MT_Point3 pos = MT_Point3( + MT_Point3 pos; + pos.setValue( blenderobject->loc[0]+blenderobject->dloc[0], blenderobject->loc[1]+blenderobject->dloc[1], blenderobject->loc[2]+blenderobject->dloc[2] ); - MT_Vector3 eulxyz = MT_Vector3( - blenderobject->rot[0], - blenderobject->rot[1], - blenderobject->rot[2] - ); - MT_Vector3 scale = MT_Vector3( - blenderobject->size[0], - blenderobject->size[1], - blenderobject->size[2] - ); + MT_Vector3 eulxyz(blenderobject->rot); + MT_Vector3 scale(blenderobject->size); if (converter->addInitFromFrame){//rcruiz float eulxyzPrev[3]; blenderscene->r.cfra=blenderscene->r.sfra-1; - update_for_newframe(); + //XXX update_for_newframe(); MT_Vector3 tmp=pos-MT_Point3(blenderobject->loc[0]+blenderobject->dloc[0], blenderobject->loc[1]+blenderobject->dloc[1], blenderobject->loc[2]+blenderobject->dloc[2] @@ -1947,13 +2039,13 @@ void BL_ConvertBlenderObjects(struct Main* maggie, tmp.scale(fps, fps, fps); iniang.push_back(tmp); blenderscene->r.cfra=blenderscene->r.sfra; - update_for_newframe(); + //XXX update_for_newframe(); } gameobj->NodeSetLocalPosition(pos); gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz)); gameobj->NodeSetLocalScale(scale); - gameobj->NodeUpdateGS(0,true); + gameobj->NodeUpdateGS(0); BL_ConvertIpos(blenderobject,gameobj,converter); BL_ConvertMaterialIpos(blenderobject, gameobj, converter); @@ -1965,14 +2057,12 @@ void BL_ConvertBlenderObjects(struct Main* maggie, gameobj->SetName(blenderobject->id.name); - // templist to find Root Parents (object with no parents) - templist->Add(gameobj->AddRef()); - // update children/parent hierarchy if ((blenderobject->parent != 0)&&(!converter->addInitFromFrame)) { // blender has an additional 'parentinverse' offset in each object - SG_Node* parentinversenode = new SG_Node(NULL,NULL,SG_Callbacks()); + SG_Callbacks callback(NULL,NULL,NULL,KX_Scene::KX_ScenegraphUpdateFunc,KX_Scene::KX_ScenegraphRescheduleFunc); + SG_Node* parentinversenode = new SG_Node(NULL,kxscene,callback); // define a normal parent relationship for this node. KX_NormalParentRelation * parent_relation = KX_NormalParentRelation::New(); @@ -1997,18 +2087,18 @@ void BL_ConvertBlenderObjects(struct Main* maggie, MT_Vector3 x(ori.getColumn(0)); MT_Vector3 y(ori.getColumn(1)); MT_Vector3 z(ori.getColumn(2)); - MT_Vector3 scale(x.length(), y.length(), z.length()); - if (!MT_fuzzyZero(scale[0])) - x /= scale[0]; - if (!MT_fuzzyZero(scale[1])) - y /= scale[1]; - if (!MT_fuzzyZero(scale[2])) - z /= scale[2]; + MT_Vector3 parscale(x.length(), y.length(), z.length()); + if (!MT_fuzzyZero(parscale[0])) + x /= parscale[0]; + if (!MT_fuzzyZero(parscale[1])) + y /= parscale[1]; + if (!MT_fuzzyZero(parscale[2])) + z /= parscale[2]; ori.setColumn(0, x); ori.setColumn(1, y); ori.setColumn(2, z); parentinversenode->SetLocalOrientation(ori); - parentinversenode->SetLocalScale(scale); + parentinversenode->SetLocalScale(parscale); parentinversenode->AddChild(gameobj->GetSGNode()); } @@ -2036,7 +2126,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, objectlist->Add(gameobj->AddRef()); //tf.Add(gameobj->GetSGNode()); - gameobj->NodeUpdateGS(0,true); + gameobj->NodeUpdateGS(0); gameobj->AddMeshUser(); } @@ -2094,8 +2184,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, blenderobject, kxscene, rendertools, - converter, - blenderscene); + converter); // this code is copied from above except that // object from groups are never in active layer @@ -2113,25 +2202,17 @@ void BL_ConvertBlenderObjects(struct Main* maggie, if (converter->addInitFromFrame) blenderscene->r.cfra=blenderscene->r.sfra; - MT_Point3 pos = MT_Point3( + MT_Point3 pos( blenderobject->loc[0]+blenderobject->dloc[0], blenderobject->loc[1]+blenderobject->dloc[1], blenderobject->loc[2]+blenderobject->dloc[2] ); - MT_Vector3 eulxyz = MT_Vector3( - blenderobject->rot[0], - blenderobject->rot[1], - blenderobject->rot[2] - ); - MT_Vector3 scale = MT_Vector3( - blenderobject->size[0], - blenderobject->size[1], - blenderobject->size[2] - ); + MT_Vector3 eulxyz(blenderobject->rot); + MT_Vector3 scale(blenderobject->size); if (converter->addInitFromFrame){//rcruiz float eulxyzPrev[3]; blenderscene->r.cfra=blenderscene->r.sfra-1; - update_for_newframe(); + //XXX update_for_newframe(); MT_Vector3 tmp=pos-MT_Point3(blenderobject->loc[0]+blenderobject->dloc[0], blenderobject->loc[1]+blenderobject->dloc[1], blenderobject->loc[2]+blenderobject->dloc[2] @@ -2149,13 +2230,13 @@ void BL_ConvertBlenderObjects(struct Main* maggie, tmp.scale(fps, fps, fps); iniang.push_back(tmp); blenderscene->r.cfra=blenderscene->r.sfra; - update_for_newframe(); + //XXX update_for_newframe(); } gameobj->NodeSetLocalPosition(pos); gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz)); gameobj->NodeSetLocalScale(scale); - gameobj->NodeUpdateGS(0,true); + gameobj->NodeUpdateGS(0); BL_ConvertIpos(blenderobject,gameobj,converter); BL_ConvertMaterialIpos(blenderobject,gameobj, converter); @@ -2167,14 +2248,12 @@ void BL_ConvertBlenderObjects(struct Main* maggie, gameobj->SetName(blenderobject->id.name); - // templist to find Root Parents (object with no parents) - templist->Add(gameobj->AddRef()); - // update children/parent hierarchy if ((blenderobject->parent != 0)&&(!converter->addInitFromFrame)) { // blender has an additional 'parentinverse' offset in each object - SG_Node* parentinversenode = new SG_Node(NULL,NULL,SG_Callbacks()); + SG_Callbacks callback(NULL,NULL,NULL,KX_Scene::KX_ScenegraphUpdateFunc,KX_Scene::KX_ScenegraphRescheduleFunc); + SG_Node* parentinversenode = new SG_Node(NULL,kxscene,callback); // define a normal parent relationship for this node. KX_NormalParentRelation * parent_relation = KX_NormalParentRelation::New(); @@ -2194,18 +2273,18 @@ void BL_ConvertBlenderObjects(struct Main* maggie, MT_Vector3 x(ori.getColumn(0)); MT_Vector3 y(ori.getColumn(1)); MT_Vector3 z(ori.getColumn(2)); - MT_Vector3 scale(x.length(), y.length(), z.length()); - if (!MT_fuzzyZero(scale[0])) - x /= scale[0]; - if (!MT_fuzzyZero(scale[1])) - y /= scale[1]; - if (!MT_fuzzyZero(scale[2])) - z /= scale[2]; + MT_Vector3 localscale(x.length(), y.length(), z.length()); + if (!MT_fuzzyZero(localscale[0])) + x /= localscale[0]; + if (!MT_fuzzyZero(localscale[1])) + y /= localscale[1]; + if (!MT_fuzzyZero(localscale[2])) + z /= localscale[2]; ori.setColumn(0, x); ori.setColumn(1, y); ori.setColumn(2, z); parentinversenode->SetLocalOrientation(ori); - parentinversenode->SetLocalScale(scale); + parentinversenode->SetLocalScale(localscale); parentinversenode->AddChild(gameobj->GetSGNode()); } @@ -2233,7 +2312,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, objectlist->Add(gameobj->AddRef()); //tf.Add(gameobj->GetSGNode()); - gameobj->NodeUpdateGS(0,true); + gameobj->NodeUpdateGS(0); gameobj->AddMeshUser(); } else @@ -2316,21 +2395,22 @@ void BL_ConvertBlenderObjects(struct Main* maggie, // Remove the child reference in the local list! // Note: there may be descendents already if the children of the child were processed // by this loop before the child. In that case, we must remove the children also - CListValue* childrenlist = (CListValue*)childobj->PyGetChildrenRecursive(childobj); + CListValue* childrenlist = childobj->GetChildrenRecursive(); childrenlist->Add(childobj->AddRef()); for ( i=0;i<childrenlist->GetCount();i++) { KX_GameObject* obj = static_cast<KX_GameObject*>(childrenlist->GetValue(i)); - if (templist->RemoveValue(obj)) - obj->Release(); if (sumolist->RemoveValue(obj)) obj->Release(); if (logicbrick_conversionlist->RemoveValue(obj)) obj->Release(); } childrenlist->Release(); + // now destroy recursively + converter->UnregisterGameObject(childobj); // removing objects during conversion make sure this runs too kxscene->RemoveObject(childobj); + continue; } @@ -2353,7 +2433,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, case PARBONE: { // parent this to a bone - Bone *parent_bone = get_named_bone(get_armature(blenderchild->parent), blenderchild->parsubstr); + Bone *parent_bone = get_named_bone( (bArmature *)(blenderchild->parent)->data, blenderchild->parsubstr); if(parent_bone) { KX_BoneParentRelation *bone_parent_relation = KX_BoneParentRelation::New(parent_bone); @@ -2378,23 +2458,56 @@ void BL_ConvertBlenderObjects(struct Main* maggie, vec_parent_child.clear(); // find 'root' parents (object that has not parents in SceneGraph) - for (i=0;i<templist->GetCount();++i) + for (i=0;i<sumolist->GetCount();++i) { - KX_GameObject* gameobj = (KX_GameObject*) templist->GetValue(i); + KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); if (gameobj->GetSGNode()->GetSGParent() == 0) { parentlist->Add(gameobj->AddRef()); - gameobj->NodeUpdateGS(0,true); + gameobj->NodeUpdateGS(0); } } - + + // create graphic controller for culling + if (kxscene->GetDbvtCulling()) + { + bool occlusion = false; + for (i=0; i<sumolist->GetCount();i++) + { + KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); + if (gameobj->GetMeshCount() > 0) + { + MT_Point3 box[2]; + gameobj->GetSGNode()->BBox().getmm(box, MT_Transform::Identity()); + // box[0] is the min, box[1] is the max + bool isactive = objectlist->SearchValue(gameobj); + BL_CreateGraphicObjectNew(gameobj,box[0],box[1],kxscene,isactive,physics_engine); + if (gameobj->GetOccluder()) + occlusion = true; + } + } + if (occlusion) + kxscene->SetDbvtOcclusionRes(blenderscene->gm.occlusionRes); + } + if (blenderscene->world) + kxscene->GetPhysicsEnvironment()->setNumTimeSubSteps(blenderscene->gm.physubstep); + + // now that the scenegraph is complete, let's instantiate the deformers. + // We need that to create reusable derived mesh and physic shapes + for (i=0;i<sumolist->GetCount();++i) + { + KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); + if (gameobj->GetDeformer()) + gameobj->GetDeformer()->UpdateBuckets(); + } + bool processCompoundChildren = false; // create physics information for (i=0;i<sumolist->GetCount();i++) { KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); - struct Object* blenderobject = converter->FindBlenderObject(gameobj); + struct Object* blenderobject = gameobj->GetBlenderObject(); int nummeshes = gameobj->GetMeshCount(); RAS_MeshObject* meshobj = 0; if (nummeshes > 0) @@ -2410,7 +2523,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, for (i=0;i<sumolist->GetCount();i++) { KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); - struct Object* blenderobject = converter->FindBlenderObject(gameobj); + struct Object* blenderobject = gameobj->GetBlenderObject(); int nummeshes = gameobj->GetMeshCount(); RAS_MeshObject* meshobj = 0; if (nummeshes > 0) @@ -2421,7 +2534,6 @@ void BL_ConvertBlenderObjects(struct Main* maggie, BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,layerMask,physics_engine,converter,processCompoundChildren); } - //set ini linearVel and int angularVel //rcruiz if (converter->addInitFromFrame) for (i=0;i<sumolist->GetCount();i++) @@ -2439,7 +2551,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, for (i=0;i<sumolist->GetCount();i++) { KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); - struct Object* blenderobject = converter->FindBlenderObject(gameobj); + struct Object* blenderobject = gameobj->GetBlenderObject(); ListBase *conlist; bConstraint *curcon; conlist = get_active_constraints2(blenderobject); @@ -2507,26 +2619,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, } } - templist->Release(); - sumolist->Release(); - - int executePriority=0; /* incremented by converter routines */ - - // convert global sound stuff - - /* XXX, glob is the very very wrong place for this - * to be, re-enable once the listener has been moved into - * the scene. */ -#if 1 - SND_Scene* soundscene = kxscene->GetSoundScene(); - SND_SoundListener* listener = soundscene->GetListener(); - if (listener && G.listener) - { - listener->SetDopplerFactor(G.listener->dopplerfactor); - listener->SetDopplerVelocity(G.listener->dopplervelocity); - listener->SetGain(G.listener->gain); - } -#endif + sumolist->Release(); // convert world KX_WorldInfo* worldinfo = new BlenderWorldInfo(blenderscene->world); @@ -2539,26 +2632,26 @@ void BL_ConvertBlenderObjects(struct Main* maggie, for (i=0;i<logicbrick_conversionlist->GetCount();i++) { KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i)); - struct Object* blenderobj = converter->FindBlenderObject(gameobj); + struct Object* blenderobj = gameobj->GetBlenderObject(); int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; - BL_ConvertActuators(maggie->name, blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,executePriority, layerMask,isInActiveLayer,rendertools,converter); + BL_ConvertActuators(maggie->name, blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,layerMask,isInActiveLayer,rendertools,converter); } for ( i=0;i<logicbrick_conversionlist->GetCount();i++) { KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i)); - struct Object* blenderobj = converter->FindBlenderObject(gameobj); + struct Object* blenderobj = gameobj->GetBlenderObject(); int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; - BL_ConvertControllers(blenderobj,gameobj,logicmgr,pythondictionary,executePriority,layerMask,isInActiveLayer,converter); + BL_ConvertControllers(blenderobj,gameobj,logicmgr,pythondictionary,layerMask,isInActiveLayer,converter); } for ( i=0;i<logicbrick_conversionlist->GetCount();i++) { KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i)); - struct Object* blenderobj = converter->FindBlenderObject(gameobj); + struct Object* blenderobj = gameobj->GetBlenderObject(); int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; - BL_ConvertSensors(blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,keydev,executePriority,layerMask,isInActiveLayer,canvas,converter); + BL_ConvertSensors(blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,layerMask,isInActiveLayer,canvas,converter); // set the init state to all objects gameobj->SetInitState((blenderobj->init_state)?blenderobj->init_state:blenderobj->state); } @@ -2596,4 +2689,3 @@ void BL_ConvertBlenderObjects(struct Main* maggie, RAS_BucketManager *bucketmanager = kxscene->GetBucketManager(); bucketmanager->OptimizeBuckets(distance); } - diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.h b/source/gameengine/Converter/BL_BlenderDataConversion.h index 48f08fb357b..b8f9d1ec4e6 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.h +++ b/source/gameengine/Converter/BL_BlenderDataConversion.h @@ -34,15 +34,13 @@ #include "KX_Python.h" #include "KX_PhysicsEngineEnums.h" -class RAS_MeshObject* BL_ConvertMesh(struct Mesh* mesh,struct Object* lightobj,class RAS_IRenderTools* rendertools,class KX_Scene* scene, class KX_BlenderSceneConverter *converter); +class RAS_MeshObject* BL_ConvertMesh(struct Mesh* mesh,struct Object* lightobj,class KX_Scene* scene, class KX_BlenderSceneConverter *converter); void BL_ConvertBlenderObjects(struct Main* maggie, - const STR_String& scenename, class KX_Scene* kxscene, class KX_KetsjiEngine* ketsjiEngine, e_PhysicsEngine physics_engine, PyObject* pythondictionary, - class SCA_IInputDevice* keydev, class RAS_IRenderTools* rendertools, class RAS_ICanvas* canvas, class KX_BlenderSceneConverter* sceneconverter, diff --git a/source/gameengine/Converter/BL_DeformableGameObject.cpp b/source/gameengine/Converter/BL_DeformableGameObject.cpp index e2610d2b405..cb882f31e80 100644 --- a/source/gameengine/Converter/BL_DeformableGameObject.cpp +++ b/source/gameengine/Converter/BL_DeformableGameObject.cpp @@ -30,6 +30,8 @@ #include "BL_DeformableGameObject.h" #include "BL_ShapeDeformer.h" #include "BL_ShapeActionActuator.h" +#include "RAS_MaterialBucket.h" + #ifdef HAVE_CONFIG_H #include <config.h> @@ -41,27 +43,19 @@ BL_DeformableGameObject::~BL_DeformableGameObject() delete m_pDeformer; // __NLA : Temporary until we decide where to put this } -void BL_DeformableGameObject::ProcessReplica(KX_GameObject* replica) +void BL_DeformableGameObject::ProcessReplica() { - BL_MeshDeformer *deformer; - KX_GameObject::ProcessReplica(replica); - - if (m_pDeformer) { - deformer = (BL_MeshDeformer*)m_pDeformer->GetReplica(replica); - ((BL_DeformableGameObject*)replica)->m_pDeformer = deformer; - } + KX_GameObject::ProcessReplica(); + if (m_pDeformer) + m_pDeformer= (BL_MeshDeformer*)m_pDeformer->GetReplica(); } CValue* BL_DeformableGameObject::GetReplica() { BL_DeformableGameObject* replica = new BL_DeformableGameObject(*this);//m_float,GetName()); - - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - - ProcessReplica(replica); + replica->ProcessReplica(); return replica; } @@ -109,3 +103,14 @@ bool BL_DeformableGameObject::GetShape(vector<float> &shape) return !shape.empty(); } +void BL_DeformableGameObject::SetDeformer(class RAS_Deformer* deformer) +{ + m_pDeformer = deformer; + + SG_QList::iterator<RAS_MeshSlot> mit(m_meshSlots); + for(mit.begin(); !mit.end(); ++mit) + { + (*mit)->SetDeformer(deformer); + } +} + diff --git a/source/gameengine/Converter/BL_DeformableGameObject.h b/source/gameengine/Converter/BL_DeformableGameObject.h index 126a1fcb1e7..ed329e7953d 100644 --- a/source/gameengine/Converter/BL_DeformableGameObject.h +++ b/source/gameengine/Converter/BL_DeformableGameObject.h @@ -45,7 +45,6 @@ struct Key; class BL_DeformableGameObject : public KX_GameObject { public: - CValue* GetReplica(); double GetLastFrame () @@ -62,7 +61,7 @@ public: m_pDeformer->Relink (map); KX_GameObject::Relink(map); }; - void ProcessReplica(KX_GameObject* replica); + void ProcessReplica(); BL_DeformableGameObject(Object* blendobj, void* sgReplicationInfo, SG_Callbacks callbacks) : KX_GameObject(sgReplicationInfo,callbacks), @@ -83,10 +82,7 @@ public: return (m_pDeformer) ? ((BL_MeshDeformer*)m_pDeformer)->GetMesh()->key : NULL; } - virtual void SetDeformer(class RAS_Deformer* deformer) - { - m_pDeformer = deformer; - } + virtual void SetDeformer(class RAS_Deformer* deformer); virtual class RAS_Deformer* GetDeformer() { return m_pDeformer; @@ -103,6 +99,12 @@ protected: Object* m_blendobj; short m_activePriority; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_DeformableGameObject"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Converter/BL_MeshDeformer.cpp b/source/gameengine/Converter/BL_MeshDeformer.cpp index fa3b8185fe2..d7012abe316 100644 --- a/source/gameengine/Converter/BL_MeshDeformer.cpp +++ b/source/gameengine/Converter/BL_MeshDeformer.cpp @@ -47,11 +47,11 @@ #include "GEN_Map.h" #include "STR_HashedString.h" +#include "BLI_arithb.h" bool BL_MeshDeformer::Apply(RAS_IPolyMaterial*) { size_t i; - float *co; // only apply once per frame if the mesh is actually modified if(m_pMeshObject->MeshModified() && @@ -70,8 +70,7 @@ bool BL_MeshDeformer::Apply(RAS_IPolyMaterial*) // For each vertex for(i=it.startvertex; i<it.endvertex; i++) { RAS_TexVert& v = it.vertex[i]; - co = m_bmesh->mvert[v.getOrigIndex()].co; - v.SetXYZ(MT_Point3(co)); + v.SetXYZ(m_bmesh->mvert[v.getOrigIndex()].co); } } } @@ -92,6 +91,15 @@ BL_MeshDeformer::~BL_MeshDeformer() delete [] m_transnors; } +void BL_MeshDeformer::ProcessReplica() +{ + m_transverts = NULL; + m_transnors = NULL; + m_tvtot = 0; + m_bDynamic=false; + m_lastDeformUpdate = -1; +} + void BL_MeshDeformer::Relink(GEN_Map<class GEN_HashedPtr, void*>*map) { void **h_obj = (*map)[m_gameobj]; @@ -135,9 +143,9 @@ void BL_MeshDeformer::RecalcNormals() RAS_TexVert& v3 = it.vertex[it.index[i+2]]; RAS_TexVert *v4 = NULL; - const float *co1 = v1.getXYZ(); - const float *co2 = v2.getXYZ(); - const float *co3 = v3.getXYZ(); + const float *co1 = m_transverts[v1.getOrigIndex()]; + const float *co2 = m_transverts[v2.getOrigIndex()]; + const float *co3 = m_transverts[v3.getOrigIndex()]; const float *co4 = NULL; /* compute face normal */ @@ -145,7 +153,7 @@ void BL_MeshDeformer::RecalcNormals() if(nvert == 4) { v4 = &it.vertex[it.index[i+3]]; - co4 = v4->getXYZ(); + co4 = m_transverts[v4->getOrigIndex()]; n1[0]= co1[0]-co3[0]; n1[1]= co1[1]-co3[1]; @@ -168,6 +176,7 @@ void BL_MeshDeformer::RecalcNormals() fnor[0]= n1[1]*n2[2] - n1[2]*n2[1]; fnor[1]= n1[2]*n2[0] - n1[0]*n2[2]; fnor[2]= n1[0]*n2[1] - n1[1]*n2[0]; + Normalize(fnor); /* add to vertices for smooth normals */ float *vn1 = m_transnors[v1.getOrigIndex()]; diff --git a/source/gameengine/Converter/BL_MeshDeformer.h b/source/gameengine/Converter/BL_MeshDeformer.h index 8de59c1cdf3..1749d438d21 100644 --- a/source/gameengine/Converter/BL_MeshDeformer.h +++ b/source/gameengine/Converter/BL_MeshDeformer.h @@ -64,8 +64,12 @@ public: virtual void SetSimulatedTime(double time){}; virtual bool Apply(class RAS_IPolyMaterial *mat); virtual bool Update(void){ return false; }; - virtual RAS_Deformer* GetReplica(class KX_GameObject* replica){return NULL;}; + virtual bool UpdateBuckets(void){ return false; }; + virtual RAS_Deformer* GetReplica(){return NULL;}; + virtual void ProcessReplica(); struct Mesh* GetMesh() { return m_bmesh; }; + virtual class RAS_MeshObject* GetRasMesh() { return (RAS_MeshObject*)m_pMeshObject; }; + virtual float (* GetTransVerts(int *tot))[3] { *tot= m_tvtot; return m_transverts; } // virtual void InitDeform(double time){}; protected: @@ -81,6 +85,13 @@ protected: int m_tvtot; BL_DeformableGameObject* m_gameobj; double m_lastDeformUpdate; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_MeshDeformer"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Converter/BL_ModifierDeformer.cpp b/source/gameengine/Converter/BL_ModifierDeformer.cpp new file mode 100644 index 00000000000..80165548ff2 --- /dev/null +++ b/source/gameengine/Converter/BL_ModifierDeformer.cpp @@ -0,0 +1,183 @@ +/** + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** + */ + +#ifdef WIN32 +#pragma warning (disable : 4786) +#endif //WIN32 + +#include "MEM_guardedalloc.h" +#include "BL_ModifierDeformer.h" +#include "GEN_Map.h" +#include "STR_HashedString.h" +#include "RAS_IPolygonMaterial.h" +#include "BL_SkinMeshObject.h" +#include "PHY_IGraphicController.h" + +//#include "BL_ArmatureController.h" +#include "DNA_armature_types.h" +#include "DNA_action_types.h" +#include "DNA_key_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_ipo_types.h" +#include "DNA_curve_types.h" +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" +#include "BKE_armature.h" +#include "BKE_action.h" +#include "BKE_key.h" +#include "BKE_ipo.h" +#include "MT_Point3.h" + +extern "C"{ + #include "BKE_customdata.h" + #include "BKE_DerivedMesh.h" + #include "BKE_lattice.h" + #include "BKE_modifier.h" +} + #include "BKE_utildefines.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#define __NLA_DEFNORMALS +//#undef __NLA_DEFNORMALS + + +BL_ModifierDeformer::~BL_ModifierDeformer() +{ + if (m_dm) { + // deformedOnly is used as a user counter + if (--m_dm->deformedOnly == 0) { + m_dm->needsFree = 1; + m_dm->release(m_dm); + } + } +}; + +RAS_Deformer *BL_ModifierDeformer::GetReplica() +{ + BL_ModifierDeformer *result; + + result = new BL_ModifierDeformer(*this); + result->ProcessReplica(); + return result; +} + +void BL_ModifierDeformer::ProcessReplica() +{ + /* Note! - This is not inherited from PyObjectPlus */ + BL_ShapeDeformer::ProcessReplica(); + if (m_dm) + // by default try to reuse mesh, deformedOnly is used as a user count + m_dm->deformedOnly++; + // this will force an update and if the mesh cannot be reused, a new one will be created + m_lastModifierUpdate = -1; +} + +bool BL_ModifierDeformer::HasCompatibleDeformer(Object *ob) +{ + if (!ob->modifiers.first) + return false; + // soft body cannot use mesh modifiers + if ((ob->gameflag & OB_SOFT_BODY) != 0) + return false; + ModifierData* md; + for (md = (ModifierData*)ob->modifiers.first; md; md = (ModifierData*)md->next) { + if (modifier_dependsOnTime(md)) + continue; + if (!(md->mode & eModifierMode_Realtime)) + continue; + return true; + } + return false; +} + +bool BL_ModifierDeformer::Update(void) +{ + bool bShapeUpdate = BL_ShapeDeformer::Update(); + + if (bShapeUpdate || m_lastModifierUpdate != m_gameobj->GetLastFrame()) { + // static derived mesh are not updated + if (m_dm == NULL || m_bDynamic) { + /* execute the modifiers */ + Object* blendobj = m_gameobj->GetBlendObject(); + /* hack: the modifiers require that the mesh is attached to the object + It may not be the case here because of replace mesh actuator */ + Mesh *oldmesh = (Mesh*)blendobj->data; + blendobj->data = m_bmesh; + /* execute the modifiers */ + DerivedMesh *dm = mesh_create_derived_no_virtual(m_scene, blendobj, m_transverts, CD_MASK_MESH); + /* restore object data */ + blendobj->data = oldmesh; + /* free the current derived mesh and replace, (dm should never be NULL) */ + if (m_dm != NULL) { + // HACK! use deformedOnly as a user counter + if (--m_dm->deformedOnly == 0) { + m_dm->needsFree = 1; + m_dm->release(m_dm); + } + } + m_dm = dm; + // get rid of temporary data + m_dm->needsFree = 0; + m_dm->release(m_dm); + // HACK! use deformedOnly as a user counter + m_dm->deformedOnly = 1; + /* update the graphic controller */ + PHY_IGraphicController *ctrl = m_gameobj->GetGraphicController(); + if (ctrl) { + float min_r[3], max_r[3]; + INIT_MINMAX(min_r, max_r); + m_dm->getMinMax(m_dm, min_r, max_r); + ctrl->setLocalAabb(min_r, max_r); + } + } + m_lastModifierUpdate=m_gameobj->GetLastFrame(); + bShapeUpdate = true; + } + return bShapeUpdate; +} + +bool BL_ModifierDeformer::Apply(RAS_IPolyMaterial *mat) +{ + if (!Update()) + return false; + + // drawing is based on derived mesh, must set it in the mesh slots + int nmat = m_pMeshObject->NumMaterials(); + for (int imat=0; imat<nmat; imat++) { + RAS_MeshMaterial *mmat = m_pMeshObject->GetMeshMaterial(imat); + RAS_MeshSlot **slot = mmat->m_slots[(void*)m_gameobj]; + if(!slot || !*slot) + continue; + (*slot)->m_pDerivedMesh = m_dm; + } + return true; +} diff --git a/source/gameengine/Converter/BL_ModifierDeformer.h b/source/gameengine/Converter/BL_ModifierDeformer.h new file mode 100644 index 00000000000..5cc84c7d1e4 --- /dev/null +++ b/source/gameengine/Converter/BL_ModifierDeformer.h @@ -0,0 +1,113 @@ +/** + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** + */ + +#ifndef BL_MODIFIERDEFORMER +#define BL_MODIFIERDEFORMER + +#ifdef WIN32 +#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning +#endif //WIN32 + +#include "BL_ShapeDeformer.h" +#include "BL_DeformableGameObject.h" +#include <vector> + +struct DerivedMesh; +struct Object; + +class BL_ModifierDeformer : public BL_ShapeDeformer +{ +public: + static bool HasCompatibleDeformer(Object *ob); + + + BL_ModifierDeformer(BL_DeformableGameObject *gameobj, + Scene *scene, + Object *bmeshobj, + BL_SkinMeshObject *mesh) + : + BL_ShapeDeformer(gameobj,bmeshobj, mesh), + m_lastModifierUpdate(-1), + m_scene(scene), + m_dm(NULL) + { + m_recalcNormal = false; + }; + + /* this second constructor is needed for making a mesh deformable on the fly. */ + BL_ModifierDeformer(BL_DeformableGameObject *gameobj, + struct Scene *scene, + struct Object *bmeshobj_old, + struct Object *bmeshobj_new, + class BL_SkinMeshObject *mesh, + bool release_object, + BL_ArmatureObject* arma = NULL) + : + BL_ShapeDeformer(gameobj, bmeshobj_old, bmeshobj_new, mesh, release_object, false, arma), + m_lastModifierUpdate(-1), + m_scene(scene), + m_dm(NULL) + { + }; + + virtual void ProcessReplica(); + virtual RAS_Deformer *GetReplica(); + virtual ~BL_ModifierDeformer(); + virtual bool UseVertexArray() + { + return false; + } + + bool Update (void); + bool Apply(RAS_IPolyMaterial *mat); + void ForceUpdate() + { + m_lastModifierUpdate = -1.0; + }; + virtual struct DerivedMesh* GetFinalMesh() + { + return m_dm; + } + + +protected: + double m_lastModifierUpdate; + Scene *m_scene; + DerivedMesh *m_dm; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_ModifierDeformer"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif + diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.cpp b/source/gameengine/Converter/BL_ShapeActionActuator.cpp index 46f3141be29..81ce9ff6154 100644 --- a/source/gameengine/Converter/BL_ShapeActionActuator.cpp +++ b/source/gameengine/Converter/BL_ShapeActionActuator.cpp @@ -35,13 +35,13 @@ #include "SCA_LogicManager.h" #include "BL_ShapeActionActuator.h" -#include "BL_ActionActuator.h" #include "BL_ShapeDeformer.h" #include "KX_GameObject.h" #include "STR_HashedString.h" -#include "DNA_action_types.h" #include "DNA_nla_types.h" -#include "DNA_actuator_types.h" +#include "DNA_action_types.h" +#include "DNA_anim_types.h" +#include "DNA_scene_types.h" #include "BKE_action.h" #include "DNA_armature_types.h" #include "MEM_guardedalloc.h" @@ -52,6 +52,10 @@ #include "FloatValue.h" #include "PyObjectPlus.h" +extern "C" { + #include "BKE_animsys.h" +} + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -62,6 +66,7 @@ BL_ShapeActionActuator::~BL_ShapeActionActuator() void BL_ShapeActionActuator::ProcessReplica() { + SCA_IActuator::ProcessReplica(); m_localtime=m_startframe; m_lastUpdate=-1; } @@ -75,9 +80,6 @@ CValue* BL_ShapeActionActuator::GetReplica() { BL_ShapeActionActuator* replica = new BL_ShapeActionActuator(*this);//m_float,GetName()); replica->ProcessReplica(); - - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; } @@ -163,16 +165,9 @@ bool BL_ShapeActionActuator::Update(double curtime, bool frame) // maybe there are events for us in the queue ! if (frame) { - for (vector<CValue*>::iterator i=m_events.begin(); !(i==m_events.end());i++) - { - if ((*i)->GetNumber() == 0.0f) - bNegativeEvent = true; - else - bPositiveEvent= true; - (*i)->Release(); - - } - m_events.clear(); + bNegativeEvent = m_negevent; + bPositiveEvent = m_posevent; + RemoveAllEvents(); if (bPositiveEvent) m_flag |= ACT_FLAG_ACTIVE; @@ -380,9 +375,12 @@ bool BL_ShapeActionActuator::Update(double curtime, bool frame) m_blendstart = curtime; } // only interested in shape channel - extract_ipochannels_from_action(&tchanbase, &key->id, m_action, "Shape", m_localtime); - - if (!execute_ipochannels(&tchanbase)) { + + // in 2.4x was // extract_ipochannels_from_action(&tchanbase, &key->id, m_action, "Shape", m_localtime); + BKE_animsys_evaluate_animdata(&key->id, key->adt, m_localtime, ADT_RECALC_ANIM); + + // XXX - in 2.5 theres no way to do this. possibly not that important to support - Campbell + if (0) { // XXX !execute_ipochannels(&tchanbase)) { // no update, this is possible if action does not match the keys, stop the action keepgoing = false; } @@ -421,422 +419,76 @@ bool BL_ShapeActionActuator::Update(double curtime, bool frame) /* Integration hooks ------------------------------------------------------- */ PyTypeObject BL_ShapeActionActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "BL_ShapeActionActuator", - sizeof(BL_ShapeActionActuator), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 + PyVarObject_HEAD_INIT(NULL, 0) + "BL_ShapeActionActuator", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_IActuator::Type, + 0,0,0,0,0,0, + py_base_new }; -PyParentObject BL_ShapeActionActuator::Parents[] = { - &BL_ShapeActionActuator::Type, - &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL -}; PyMethodDef BL_ShapeActionActuator::Methods[] = { - {"setAction", (PyCFunction) BL_ShapeActionActuator::sPySetAction, METH_VARARGS, (PY_METHODCHAR)SetAction_doc}, - {"setStart", (PyCFunction) BL_ShapeActionActuator::sPySetStart, METH_VARARGS, (PY_METHODCHAR)SetStart_doc}, - {"setEnd", (PyCFunction) BL_ShapeActionActuator::sPySetEnd, METH_VARARGS, (PY_METHODCHAR)SetEnd_doc}, - {"setBlendin", (PyCFunction) BL_ShapeActionActuator::sPySetBlendin, METH_VARARGS, (PY_METHODCHAR)SetBlendin_doc}, - {"setPriority", (PyCFunction) BL_ShapeActionActuator::sPySetPriority, METH_VARARGS, (PY_METHODCHAR)SetPriority_doc}, - {"setFrame", (PyCFunction) BL_ShapeActionActuator::sPySetFrame, METH_VARARGS, (PY_METHODCHAR)SetFrame_doc}, - {"setProperty", (PyCFunction) BL_ShapeActionActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, - {"setFrameProperty", (PyCFunction) BL_ShapeActionActuator::sPySetFrameProperty, METH_VARARGS, (PY_METHODCHAR)SetFrameProperty_doc}, - {"setBlendtime", (PyCFunction) BL_ShapeActionActuator::sPySetBlendtime, METH_VARARGS, (PY_METHODCHAR)SetBlendtime_doc}, - - {"getAction", (PyCFunction) BL_ShapeActionActuator::sPyGetAction, METH_NOARGS, (PY_METHODCHAR)GetAction_doc}, - {"getStart", (PyCFunction) BL_ShapeActionActuator::sPyGetStart, METH_NOARGS, (PY_METHODCHAR)GetStart_doc}, - {"getEnd", (PyCFunction) BL_ShapeActionActuator::sPyGetEnd, METH_NOARGS, (PY_METHODCHAR)GetEnd_doc}, - {"getBlendin", (PyCFunction) BL_ShapeActionActuator::sPyGetBlendin, METH_NOARGS, (PY_METHODCHAR)GetBlendin_doc}, - {"getPriority", (PyCFunction) BL_ShapeActionActuator::sPyGetPriority, METH_NOARGS, (PY_METHODCHAR)GetPriority_doc}, - {"getFrame", (PyCFunction) BL_ShapeActionActuator::sPyGetFrame, METH_NOARGS, (PY_METHODCHAR)GetFrame_doc}, - {"getProperty", (PyCFunction) BL_ShapeActionActuator::sPyGetProperty, METH_NOARGS, (PY_METHODCHAR)GetProperty_doc}, - {"getFrameProperty", (PyCFunction) BL_ShapeActionActuator::sPyGetFrameProperty, METH_NOARGS, (PY_METHODCHAR)GetFrameProperty_doc}, - {"getType", (PyCFunction) BL_ShapeActionActuator::sPyGetType, METH_NOARGS, (PY_METHODCHAR)GetType_doc}, - {"setType", (PyCFunction) BL_ShapeActionActuator::sPySetType, METH_NOARGS, (PY_METHODCHAR)SetType_doc}, {NULL,NULL} //Sentinel }; -PyObject* BL_ShapeActionActuator::_getattr(const STR_String& attr) { - _getattr_up(SCA_IActuator); -} - -/* setStart */ -const char BL_ShapeActionActuator::GetAction_doc[] = -"getAction()\n" -"\tReturns a string containing the name of the current action.\n"; - -PyObject* BL_ShapeActionActuator::PyGetAction(PyObject* self) { - if (m_action){ - return PyString_FromString(m_action->id.name+2); - } - Py_RETURN_NONE; -} - -/* getProperty */ -const char BL_ShapeActionActuator::GetProperty_doc[] = -"getProperty()\n" -"\tReturns the name of the property to be used in FromProp mode.\n"; - -PyObject* BL_ShapeActionActuator::PyGetProperty(PyObject* self) { - PyObject *result; - - result = Py_BuildValue("s", (const char *)m_propname); - - return result; -} - -/* getFrame */ -const char BL_ShapeActionActuator::GetFrame_doc[] = -"getFrame()\n" -"\tReturns the current frame number.\n"; - -PyObject* BL_ShapeActionActuator::PyGetFrame(PyObject* self) { - PyObject *result; - - result = Py_BuildValue("f", m_localtime); - - return result; -} - -/* getEnd */ -const char BL_ShapeActionActuator::GetEnd_doc[] = -"getEnd()\n" -"\tReturns the last frame of the action.\n"; - -PyObject* BL_ShapeActionActuator::PyGetEnd(PyObject* self) { - PyObject *result; - - result = Py_BuildValue("f", m_endframe); - - return result; -} - -/* getStart */ -const char BL_ShapeActionActuator::GetStart_doc[] = -"getStart()\n" -"\tReturns the starting frame of the action.\n"; - -PyObject* BL_ShapeActionActuator::PyGetStart(PyObject* self) { - PyObject *result; - - result = Py_BuildValue("f", m_startframe); - - return result; -} - -/* getBlendin */ -const char BL_ShapeActionActuator::GetBlendin_doc[] = -"getBlendin()\n" -"\tReturns the number of interpolation animation frames to be\n" -"\tgenerated when this actuator is triggered.\n"; - -PyObject* BL_ShapeActionActuator::PyGetBlendin(PyObject* self) { - PyObject *result; - - result = Py_BuildValue("f", m_blendin); - - return result; -} - -/* getPriority */ -const char BL_ShapeActionActuator::GetPriority_doc[] = -"getPriority()\n" -"\tReturns the priority for this actuator. Actuators with lower\n" -"\tPriority numbers will override actuators with higher numbers.\n"; - -PyObject* BL_ShapeActionActuator::PyGetPriority(PyObject* self) { - PyObject *result; - - result = Py_BuildValue("i", m_priority); - - return result; -} - -/* setAction */ -const char BL_ShapeActionActuator::SetAction_doc[] = -"setAction(action, (reset))\n" -"\t - action : The name of the action to set as the current action.\n" -"\t Should be an action with Shape channels.\n" -"\t - reset : Optional parameter indicating whether to reset the\n" -"\t blend timer or not. A value of 1 indicates that the\n" -"\t timer should be reset. A value of 0 will leave it\n" -"\t unchanged. If reset is not specified, the timer will" -"\t be reset.\n"; - -PyObject* BL_ShapeActionActuator::PySetAction(PyObject* self, - PyObject* args, - PyObject* kwds) { - char *string; - int reset = 1; - - if (PyArg_ParseTuple(args,"s|i",&string, &reset)) - { - bAction *action; - - action = (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(STR_String(string)); - - if (!action){ - /* NOTE! Throw an exception or something */ - // printf ("setAction failed: Action not found\n", string); - } - else{ - m_action=action; - if (reset) - m_blendframe = 0.f; - } - } - else { - return NULL; - } - - Py_RETURN_NONE; -} - -/* setStart */ -const char BL_ShapeActionActuator::SetStart_doc[] = -"setStart(start)\n" -"\t - start : Specifies the starting frame of the animation.\n"; - -PyObject* BL_ShapeActionActuator::PySetStart(PyObject* self, - PyObject* args, - PyObject* kwds) { - float start; - - if (PyArg_ParseTuple(args,"f",&start)) - { - m_startframe = start; - } - else { - return NULL; - } - - Py_RETURN_NONE; -} - -/* setEnd */ -const char BL_ShapeActionActuator::SetEnd_doc[] = -"setEnd(end)\n" -"\t - end : Specifies the ending frame of the animation.\n"; - -PyObject* BL_ShapeActionActuator::PySetEnd(PyObject* self, - PyObject* args, - PyObject* kwds) { - float end; - - if (PyArg_ParseTuple(args,"f",&end)) - { - m_endframe = end; - } - else { - return NULL; - } - - Py_RETURN_NONE; -} - -/* setBlendin */ -const char BL_ShapeActionActuator::SetBlendin_doc[] = -"setBlendin(blendin)\n" -"\t - blendin : Specifies the number of frames of animation to generate\n" -"\t when making transitions between actions.\n"; - -PyObject* BL_ShapeActionActuator::PySetBlendin(PyObject* self, - PyObject* args, - PyObject* kwds) { - float blendin; - - if (PyArg_ParseTuple(args,"f",&blendin)) - { - m_blendin = blendin; - } - else { - return NULL; - } - - Py_RETURN_NONE; -} - -/* setBlendtime */ -const char BL_ShapeActionActuator::SetBlendtime_doc[] = -"setBlendtime(blendtime)\n" -"\t - blendtime : Allows the script to directly modify the internal timer\n" -"\t used when generating transitions between actions. This\n" -"\t parameter must be in the range from 0.0 to 1.0.\n"; - -PyObject* BL_ShapeActionActuator::PySetBlendtime(PyObject* self, - PyObject* args, - PyObject* kwds) { - float blendframe; - - if (PyArg_ParseTuple(args,"f",&blendframe)) - { - m_blendframe = blendframe * m_blendin; - if (m_blendframe<0.f) - m_blendframe = 0.f; - if (m_blendframe>m_blendin) - m_blendframe = m_blendin; - } - else { - return NULL; - } - - Py_RETURN_NONE; -} - -/* setPriority */ -const char BL_ShapeActionActuator::SetPriority_doc[] = -"setPriority(priority)\n" -"\t - priority : Specifies the new priority. Actuators will lower\n" -"\t priority numbers will override actuators with higher\n" -"\t numbers.\n"; - -PyObject* BL_ShapeActionActuator::PySetPriority(PyObject* self, - PyObject* args, - PyObject* kwds) { - int priority; - - if (PyArg_ParseTuple(args,"i",&priority)) - { - m_priority = priority; - } - else { - return NULL; - } - - Py_RETURN_NONE; -} - -/* getProperty */ -const char BL_ShapeActionActuator::GetFrameProperty_doc[] = -"getFrameProperty()\n" -"\tReturns the name of the property, that is set to the current frame number.\n"; - -PyObject* BL_ShapeActionActuator::PyGetFrameProperty(PyObject* self) { - PyObject *result; - - result = Py_BuildValue("s", (const char *)m_framepropname); - - return result; -} - - -/* setFrame */ -const char BL_ShapeActionActuator::SetFrame_doc[] = -"setFrame(frame)\n" -"\t - frame : Specifies the new current frame for the animation\n"; +PyAttributeDef BL_ShapeActionActuator::Attributes[] = { + KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ShapeActionActuator, m_startframe), + KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ShapeActionActuator, m_endframe), + KX_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendin), + KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ShapeActionActuator, pyattr_get_action, pyattr_set_action), + KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ShapeActionActuator, m_priority), + KX_PYATTRIBUTE_FLOAT_RW_CHECK("frame", 0, MAXFRAMEF, BL_ShapeActionActuator, m_localtime, CheckFrame), + KX_PYATTRIBUTE_STRING_RW("propName", 0, 31, false, BL_ShapeActionActuator, m_propname), + KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 31, false, BL_ShapeActionActuator, m_framepropname), + KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendframe, CheckBlendTime), + KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ShapeActionActuator,m_playtype,CheckType), + { NULL } //Sentinel +}; -PyObject* BL_ShapeActionActuator::PySetFrame(PyObject* self, - PyObject* args, - PyObject* kwds) { - float frame; - - if (PyArg_ParseTuple(args,"f",&frame)) - { - m_localtime = frame; - if (m_localtime<m_startframe) - m_localtime=m_startframe; - else if (m_localtime>m_endframe) - m_localtime=m_endframe; - } - else { - return NULL; - } - - Py_RETURN_NONE; +PyObject* BL_ShapeActionActuator::pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v); + return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name+2 : ""); } -/* setProperty */ -const char BL_ShapeActionActuator::SetProperty_doc[] = -"setProperty(prop)\n" -"\t - prop : A string specifying the property name to be used in\n" -"\t FromProp playback mode.\n"; - -PyObject* BL_ShapeActionActuator::PySetProperty(PyObject* self, - PyObject* args, - PyObject* kwds) { - char *string; - - if (PyArg_ParseTuple(args,"s",&string)) +int BL_ShapeActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v); + /* exact copy of BL_ActionActuator's function from here down */ + if (!PyUnicode_Check(value)) { - m_propname = string; - } - else { - return NULL; + PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, expected the string name of the action"); + return PY_SET_ATTR_FAIL; } - - Py_RETURN_NONE; -} -/* setFrameProperty */ -const char BL_ShapeActionActuator::SetFrameProperty_doc[] = -"setFrameProperty(prop)\n" -"\t - prop : A string specifying the property of the frame set up update.\n"; - -PyObject* BL_ShapeActionActuator::PySetFrameProperty(PyObject* self, - PyObject* args, - PyObject* kwds) { - char *string; + bAction *action= NULL; + STR_String val = _PyUnicode_AsString(value); - if (PyArg_ParseTuple(args,"s",&string)) + if (val != "") { - m_framepropname = string; - } - else { - return NULL; + action= (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(val); + if (action==NULL) + { + PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, action not found!"); + return PY_SET_ATTR_FAIL; + } } - Py_RETURN_NONE; -} - -/* getType */ -const char BL_ShapeActionActuator::GetType_doc[] = -"getType()\n" -"\tReturns the operation mode of the actuator.\n"; -PyObject* BL_ShapeActionActuator::PyGetType(PyObject* self) { - return Py_BuildValue("h", m_playtype); -} + self->SetAction(action); + return PY_SET_ATTR_SUCCESS; -/* setType */ -const char BL_ShapeActionActuator::SetType_doc[] = -"setType(mode)\n" -"\t - mode: Play (0), Flipper (2), LoopStop (3), LoopEnd (4) or Property (6)\n" -"\tSet the operation mode of the actuator.\n"; -PyObject* BL_ShapeActionActuator::PySetType(PyObject* self, - PyObject* args, - PyObject* kwds) { - short typeArg; - - if (!PyArg_ParseTuple(args, "h", &typeArg)) { - return NULL; - } - - switch (typeArg) { - case ACT_ACTION_PLAY: - case ACT_ACTION_FLIPPER: - case ACT_ACTION_LOOP_STOP: - case ACT_ACTION_LOOP_END: - case ACT_ACTION_FROM_PROP: - m_playtype = typeArg; - break; - default: - printf("Invalid type for action actuator: %d\n", typeArg); /* error */ - } - - Py_Return; } - diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.h b/source/gameengine/Converter/BL_ShapeActionActuator.h index 30b2d41fc67..28a6d90abdf 100644 --- a/source/gameengine/Converter/BL_ShapeActionActuator.h +++ b/source/gameengine/Converter/BL_ShapeActionActuator.h @@ -32,6 +32,7 @@ #include "GEN_HashedPtr.h" #include "SCA_IActuator.h" +#include "BL_ActionActuator.h" #include "MT_Point3.h" #include <vector> @@ -49,9 +50,8 @@ public: short playtype, short blendin, short priority, - float stride, - PyTypeObject* T=&Type) - : SCA_IActuator(gameobj,T), + float stride) + : SCA_IActuator(gameobj), m_lastpos(0, 0, 0), m_blendframe(0), @@ -78,31 +78,50 @@ public: void SetBlendTime (float newtime); void BlendShape(struct Key* key, float weigth); + + bAction* GetAction() { return m_action; } + void SetAction(bAction* act) { m_action= act; } + + static PyObject* pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static int CheckBlendTime(void *self, const PyAttributeDef*) + { + BL_ShapeActionActuator* act = reinterpret_cast<BL_ShapeActionActuator*>(self); + + if (act->m_blendframe > act->m_blendin) + act->m_blendframe = act->m_blendin; + + return 0; + } + static int CheckFrame(void *self, const PyAttributeDef*) + { + BL_ShapeActionActuator* act = reinterpret_cast<BL_ShapeActionActuator*>(self); - KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetAction); - KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetBlendin); - KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetPriority); - KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetStart); - KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetEnd); - KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetFrame); - KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetProperty); - KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetFrameProperty); - KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetBlendtime); - KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetChannel); - - KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetAction); - KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetBlendin); - KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetPriority); - KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetStart); - KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetEnd); - KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetFrame); - KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetProperty); - KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetFrameProperty); -// KX_PYMETHOD(BL_ActionActuator,GetChannel); - KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetType); - KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetType); - - virtual PyObject* _getattr(const STR_String& attr); + if (act->m_localtime < act->m_startframe) + act->m_localtime = act->m_startframe; + else if (act->m_localtime > act->m_endframe) + act->m_localtime = act->m_endframe; + + return 0; + } + static int CheckType(void *self, const PyAttributeDef*) + { + BL_ShapeActionActuator* act = reinterpret_cast<BL_ShapeActionActuator*>(self); + + switch (act->m_playtype) { + case ACT_ACTION_PLAY: + case ACT_ACTION_FLIPPER: + case ACT_ACTION_LOOP_STOP: + case ACT_ACTION_LOOP_END: + case ACT_ACTION_FROM_PROP: + return 0; + default: + PyErr_SetString(PyExc_ValueError, "Shape Action Actuator, invalid play type supplied"); + return 1; + } + + } protected: @@ -129,8 +148,8 @@ protected: short m_playtype; short m_priority; struct bAction *m_action; - STR_String m_propname; STR_String m_framepropname; + STR_String m_propname; vector<float> m_blendshape; }; diff --git a/source/gameengine/Converter/BL_ShapeDeformer.cpp b/source/gameengine/Converter/BL_ShapeDeformer.cpp index fc6498579ad..20ca7f07f2b 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.cpp +++ b/source/gameengine/Converter/BL_ShapeDeformer.cpp @@ -68,7 +68,7 @@ BL_ShapeDeformer::~BL_ShapeDeformer() { }; -RAS_Deformer *BL_ShapeDeformer::GetReplica(class KX_GameObject* replica) +RAS_Deformer *BL_ShapeDeformer::GetReplica() { BL_ShapeDeformer *result; @@ -79,6 +79,8 @@ RAS_Deformer *BL_ShapeDeformer::GetReplica(class KX_GameObject* replica) void BL_ShapeDeformer::ProcessReplica() { + BL_SkinDeformer::ProcessReplica(); + m_lastShapeUpdate = -1; } bool BL_ShapeDeformer::LoadShapeDrivers(Object* arma) @@ -87,7 +89,7 @@ bool BL_ShapeDeformer::LoadShapeDrivers(Object* arma) m_shapeDrivers.clear(); // check if this mesh has armature driven shape keys - if (m_bmesh->key->ipo) { + if (m_bmesh->key && m_bmesh->key->ipo) { for(icu= (IpoCurve*)m_bmesh->key->ipo->curve.first; icu; icu= (IpoCurve*)icu->next) { if(icu->driver && (icu->flag & IPO_MUTE) == 0 && @@ -107,8 +109,8 @@ bool BL_ShapeDeformer::ExecuteShapeDrivers(void) { if (!m_shapeDrivers.empty() && PoseUpdated()) { vector<IpoCurve*>::iterator it; - void *poin; - int type; +// void *poin; +// int type; // the shape drivers use the bone matrix as input. Must // update the matrix now @@ -116,16 +118,16 @@ bool BL_ShapeDeformer::ExecuteShapeDrivers(void) for (it=m_shapeDrivers.begin(); it!=m_shapeDrivers.end(); it++) { // no need to set a specific time: this curve has a driver - IpoCurve *icu = *it; - calc_icu(icu, 1.0f); - poin = get_ipo_poin((ID*)m_bmesh->key, icu, &type); - if (poin) - write_ipo_poin(poin, type, icu->curval); + // XXX IpoCurve *icu = *it; + //calc_icu(icu, 1.0f); + //poin = get_ipo_poin((ID*)m_bmesh->key, icu, &type); + //if (poin) + // write_ipo_poin(poin, type, icu->curval); } ForceUpdate(); m_armobj->RestorePose(); - + m_bDynamic = true; return true; } return false; @@ -147,7 +149,11 @@ bool BL_ShapeDeformer::Update(void) m_pMeshObject->CheckWeightCache(blendobj); /* we will blend the key directly in mvert array: it is used by armature as the start position */ - do_rel_key(0, m_bmesh->totvert, m_bmesh->totvert, (char *)m_bmesh->mvert->co, m_bmesh->key, 0); + /* m_bmesh->key can be NULL in case of Modifier deformer */ + if (m_bmesh->key) { + do_rel_key(0, m_bmesh->totvert, m_bmesh->totvert, (char *)m_bmesh->mvert->co, m_bmesh->key, 0); + m_bDynamic = true; + } // Don't release the weight array as in Blender, it will most likely be reusable on next frame // The weight array are ultimately deleted when the skin mesh is destroyed @@ -163,7 +169,8 @@ bool BL_ShapeDeformer::Update(void) // check for armature deform bSkinUpdate = BL_SkinDeformer::Update(); - if (!bSkinUpdate && bShapeUpdate) { + // non dynamic deformer = Modifer without armature and shape keys, no need to create storage + if (!bSkinUpdate && bShapeUpdate && m_bDynamic) { // this means that there is no armature, we still need to copy the vertex to m_transverts // and update the normal (was not done after shape key calculation) @@ -174,7 +181,8 @@ bool BL_ShapeDeformer::Update(void) VECCOPY(m_transverts[v], m_bmesh->mvert[v].co); #ifdef __NLA_DEFNORMALS - RecalcNormals(); + if (m_recalcNormal) + RecalcNormals(); #endif bSkinUpdate = true; } diff --git a/source/gameengine/Converter/BL_ShapeDeformer.h b/source/gameengine/Converter/BL_ShapeDeformer.h index 90b9f5caea1..ca3770d4006 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.h +++ b/source/gameengine/Converter/BL_ShapeDeformer.h @@ -58,15 +58,16 @@ public: struct Object *bmeshobj_new, class BL_SkinMeshObject *mesh, bool release_object, + bool recalc_normal, BL_ArmatureObject* arma = NULL) : - BL_SkinDeformer(gameobj, bmeshobj_old, bmeshobj_new, mesh, release_object, arma), + BL_SkinDeformer(gameobj, bmeshobj_old, bmeshobj_new, mesh, release_object, recalc_normal, arma), m_lastShapeUpdate(-1) { }; + virtual RAS_Deformer *GetReplica(); virtual void ProcessReplica(); - virtual RAS_Deformer *GetReplica(class KX_GameObject* replica); virtual ~BL_ShapeDeformer(); bool Update (void); @@ -82,6 +83,12 @@ protected: vector<IpoCurve*> m_shapeDrivers; double m_lastShapeUpdate; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_ShapeDeformer"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Converter/BL_SkinDeformer.cpp b/source/gameengine/Converter/BL_SkinDeformer.cpp index d8563763954..a13f78e1b27 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.cpp +++ b/source/gameengine/Converter/BL_SkinDeformer.cpp @@ -65,9 +65,10 @@ BL_SkinDeformer::BL_SkinDeformer(BL_DeformableGameObject *gameobj, BL_MeshDeformer(gameobj, bmeshobj, mesh), m_armobj(arma), m_lastArmaUpdate(-1), - m_defbase(&bmeshobj->defbase), + //m_defbase(&bmeshobj->defbase), m_releaseobject(false), - m_poseApplied(false) + m_poseApplied(false), + m_recalcNormal(true) { Mat4CpyMat4(m_obmat, bmeshobj->obmat); }; @@ -78,12 +79,14 @@ BL_SkinDeformer::BL_SkinDeformer( struct Object *bmeshobj_new, // Blender object that owns the original mesh class BL_SkinMeshObject *mesh, bool release_object, + bool recalc_normal, BL_ArmatureObject* arma) : BL_MeshDeformer(gameobj, bmeshobj_old, mesh), m_armobj(arma), m_lastArmaUpdate(-1), - m_defbase(&bmeshobj_old->defbase), - m_releaseobject(release_object) + //m_defbase(&bmeshobj_old->defbase), + m_releaseobject(release_object), + m_recalcNormal(recalc_normal) { // this is needed to ensure correct deformation of mesh: // the deformation is done with Blender's armature_deform_verts() function @@ -105,7 +108,7 @@ void BL_SkinDeformer::Relink(GEN_Map<class GEN_HashedPtr, void*>*map) void **h_obj = (*map)[m_armobj]; if (h_obj) - SetArmature( (BL_ArmatureObject*)(*h_obj) ); + m_armobj = (BL_ArmatureObject*)(*h_obj); else m_armobj=NULL; } @@ -118,45 +121,53 @@ bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat) RAS_MeshSlot::iterator it; RAS_MeshMaterial *mmat; RAS_MeshSlot *slot; - size_t i; + size_t i, nmat, imat; // update the vertex in m_transverts - Update(); - - // The vertex cache can only be updated for this deformer: - // Duplicated objects with more than one ploymaterial (=multiple mesh slot per object) - // share the same mesh (=the same cache). As the rendering is done per polymaterial - // cycling through the objects, the entire mesh cache cannot be updated in one shot. - mmat = m_pMeshObject->GetMeshMaterial(mat); - if(!mmat->m_slots[(void*)m_gameobj]) - return true; - - slot = *mmat->m_slots[(void*)m_gameobj]; - - // for each array - for(slot->begin(it); !slot->end(it); slot->next(it)) { - // for each vertex - // copy the untransformed data from the original mvert - for(i=it.startvertex; i<it.endvertex; i++) { - RAS_TexVert& v = it.vertex[i]; - v.SetXYZ(m_transverts[v.getOrigIndex()]); + if (!Update()) + return false; + + if (m_transverts) { + // the vertex cache is unique to this deformer, no need to update it + // if it wasn't updated! We must update all the materials at once + // because we will not get here again for the other material + nmat = m_pMeshObject->NumMaterials(); + for (imat=0; imat<nmat; imat++) { + mmat = m_pMeshObject->GetMeshMaterial(imat); + if(!mmat->m_slots[(void*)m_gameobj]) + continue; + + slot = *mmat->m_slots[(void*)m_gameobj]; + + // for each array + for(slot->begin(it); !slot->end(it); slot->next(it)) { + // for each vertex + // copy the untransformed data from the original mvert + for(i=it.startvertex; i<it.endvertex; i++) { + RAS_TexVert& v = it.vertex[i]; + v.SetXYZ(m_transverts[v.getOrigIndex()]); + } + } } } - return true; } -RAS_Deformer *BL_SkinDeformer::GetReplica(class KX_GameObject* replica) +RAS_Deformer *BL_SkinDeformer::GetReplica() { BL_SkinDeformer *result; result = new BL_SkinDeformer(*this); + /* there is m_armobj that must be fixed but we cannot do it now, it will be done in Relink */ result->ProcessReplica(); return result; } void BL_SkinDeformer::ProcessReplica() { + BL_MeshDeformer::ProcessReplica(); + m_lastArmaUpdate = -1; + m_releaseobject = false; } //void where_is_pose (Object *ob); @@ -191,14 +202,16 @@ bool BL_SkinDeformer::Update(void) Mat4CpyMat4(m_objMesh->obmat, obmat); #ifdef __NLA_DEFNORMALS - RecalcNormals(); + if (m_recalcNormal) + RecalcNormals(); #endif /* Update the current frame */ m_lastArmaUpdate=m_armobj->GetLastFrame(); m_armobj->RestorePose(); - + /* dynamic vertex, cannot use display list */ + m_bDynamic = true; /* indicate that the m_transverts and normals are up to date */ return true; } diff --git a/source/gameengine/Converter/BL_SkinDeformer.h b/source/gameengine/Converter/BL_SkinDeformer.h index f87860021c6..b83895d5609 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.h +++ b/source/gameengine/Converter/BL_SkinDeformer.h @@ -64,13 +64,20 @@ public: struct Object *bmeshobj_new, class BL_SkinMeshObject *mesh, bool release_object, + bool recalc_normal, BL_ArmatureObject* arma = NULL); + virtual RAS_Deformer *GetReplica(); virtual void ProcessReplica(); - virtual RAS_Deformer *GetReplica(class KX_GameObject* replica); + virtual ~BL_SkinDeformer(); bool Update (void); bool Apply (class RAS_IPolyMaterial *polymat); + bool UpdateBuckets(void) + { + // update the deformer and all the mesh slots; Apply() does it well, so just call it. + return Apply(NULL); + } bool PoseUpdated(void) { if (m_armobj && m_lastArmaUpdate!=m_armobj->GetLastFrame()) { @@ -83,16 +90,27 @@ public: { m_lastArmaUpdate = -1.0; }; + virtual bool ShareVertexArray() + { + return false; + } protected: BL_ArmatureObject* m_armobj; // Our parent object float m_time; double m_lastArmaUpdate; - ListBase* m_defbase; + //ListBase* m_defbase; float m_obmat[4][4]; // the reference matrix for skeleton deform bool m_releaseobject; bool m_poseApplied; + bool m_recalcNormal; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_SkinDeformer"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Converter/BL_SkinMeshObject.cpp b/source/gameengine/Converter/BL_SkinMeshObject.cpp index eb3f9d0588d..4eb01df410b 100644 --- a/source/gameengine/Converter/BL_SkinMeshObject.cpp +++ b/source/gameengine/Converter/BL_SkinMeshObject.cpp @@ -46,8 +46,8 @@ #include "BL_SkinMeshObject.h" #include "BL_DeformableGameObject.h" -BL_SkinMeshObject::BL_SkinMeshObject(Mesh* mesh, int lightlayer) - : RAS_MeshObject (mesh, lightlayer) +BL_SkinMeshObject::BL_SkinMeshObject(Mesh* mesh) + : RAS_MeshObject (mesh) { m_bDeformed = true; @@ -87,7 +87,7 @@ void BL_SkinMeshObject::UpdateBuckets(void* clientobj,double* oglmatrix,bool use continue; RAS_MeshSlot *slot = *it->m_slots[clientobj]; - slot->m_pDeformer = ((BL_DeformableGameObject*)clientobj)->GetDeformer(); + slot->SetDeformer(((BL_DeformableGameObject*)clientobj)->GetDeformer()); } RAS_MeshObject::UpdateBuckets(clientobj, oglmatrix, useObjectColor, rgbavec, visible, culled); diff --git a/source/gameengine/Converter/BL_SkinMeshObject.h b/source/gameengine/Converter/BL_SkinMeshObject.h index 8544a2b958c..838c6c3cb95 100644 --- a/source/gameengine/Converter/BL_SkinMeshObject.h +++ b/source/gameengine/Converter/BL_SkinMeshObject.h @@ -46,7 +46,7 @@ protected: vector<int> m_cacheWeightIndex; public: - BL_SkinMeshObject(Mesh* mesh, int lightlayer); + BL_SkinMeshObject(Mesh* mesh); ~BL_SkinMeshObject(); void UpdateBuckets(void* clientobj, double* oglmatrix, @@ -54,6 +54,13 @@ public: // for shape keys, void CheckWeightCache(struct Object* obj); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_SkinMeshObject"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Converter/BlenderWorldInfo.h b/source/gameengine/Converter/BlenderWorldInfo.h index fd6bb0212b7..7ccb96e4683 100644 --- a/source/gameengine/Converter/BlenderWorldInfo.h +++ b/source/gameengine/Converter/BlenderWorldInfo.h @@ -94,6 +94,13 @@ public: setMistColorBlue( float d ); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BlenderWorldInfo"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__BLENDERWORLDINFO_H diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt index 217bdb30907..257ca856b2c 100644 --- a/source/gameengine/Converter/CMakeLists.txt +++ b/source/gameengine/Converter/CMakeLists.txt @@ -27,47 +27,40 @@ FILE(GLOB SRC *.cpp) SET(INC - . - ../../../source/kernel/gen_system - ../../../intern/string - ../../../intern/guardedalloc - ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../intern/bmfont - ../../../intern/SoundSystem - ../../../intern/SoundSystem/include - ../../../intern/SoundSystem/openal - ../../../intern/SoundSystem/dummy - ../../../intern/SoundSystem/intern - ../../../source/gameengine/Converter - ../../../source/gameengine/BlenderRoutines - ../../../source/blender/imbuf - ../../../intern/moto/include - ../../../source/gameengine/Ketsji - ../../../source/gameengine/Ketsji/KXNetwork - ../../../source/blender/blenlib - ../../../source/blender/blenkernel - ../../../source/blender - ../../../source/blender/include - ../../../source/blender/makesdna - ../../../source/gameengine/Rasterizer - ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../source/gameengine/GameLogic - ../../../source/gameengine/Expressions - ../../../source/gameengine/Network - ../../../source/gameengine/SceneGraph - ../../../source/gameengine/Physics/common - ../../../source/gameengine/Physics/Bullet - ../../../source/gameengine/Physics/BlOde - ../../../source/gameengine/Physics/Dummy - ../../../source/gameengine/Physics/Sumo - ../../../source/gameengine/Physics/Sumo/Fuzzics/include - ../../../source/gameengine/Network/LoopBackNetwork - ../../../source/blender/misc - ../../../source/blender/blenloader - ../../../source/blender/gpu - ../../../extern/bullet2/src - ../../../extern/solid - ${PYTHON_INC} + . + ../../../source/kernel/gen_system + ../../../intern/string + ../../../intern/guardedalloc + ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer + ../../../intern/audaspace/intern + ../../../source/gameengine/Converter + ../../../source/gameengine/BlenderRoutines + ../../../source/blender/imbuf + ../../../intern/moto/include + ../../../source/gameengine/Ketsji + ../../../source/gameengine/Ketsji/KXNetwork + ../../../source/blender/blenlib + ../../../source/blender/blenkernel + ../../../source/blender/windowmanager + ../../../source/blender + ../../../source/blender/include + ../../../source/blender/makesdna + ../../../source/blender/makesrna + ../../../source/gameengine/Rasterizer + ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer + ../../../source/gameengine/GameLogic + ../../../source/gameengine/Expressions + ../../../source/gameengine/Network + ../../../source/gameengine/SceneGraph + ../../../source/gameengine/Physics/common + ../../../source/gameengine/Physics/Bullet + ../../../source/gameengine/Physics/Dummy + ../../../source/gameengine/Network/LoopBackNetwork + ../../../source/blender/misc + ../../../source/blender/blenloader + ../../../source/blender/gpu + ../../../extern/bullet2/src + ${PYTHON_INC} ) BLENDERLIB(bf_converter "${SRC}" "${INC}") diff --git a/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp b/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp index 4d79febb7b4..24910422176 100644 --- a/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp +++ b/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp @@ -28,32 +28,30 @@ #include "KX_BlenderScalarInterpolator.h" +#include <cstring> + extern "C" { #include "DNA_ipo_types.h" -#include "BKE_ipo.h" +#include "DNA_action_types.h" +#include "DNA_anim_types.h" +#include "BKE_fcurve.h" } -static const int BL_MAX_CHANNELS = 32; - float BL_ScalarInterpolator::GetValue(float currentTime) const { - return IPO_GetFloatValue(m_blender_ipo, m_channel, currentTime); + // XXX 2.4x IPO_GetFloatValue(m_blender_adt, m_channel, currentTime); + return evaluate_fcurve(m_fcu, currentTime); } - - -BL_InterpolatorList::BL_InterpolatorList(struct Ipo *ipo) { - IPO_Channel channels[BL_MAX_CHANNELS]; - - int num_channels = IPO_GetChannels(ipo, channels); - - int i; - - for (i = 0; i != num_channels; ++i) { - BL_ScalarInterpolator *new_ipo = - new BL_ScalarInterpolator(ipo, channels[i]); - - //assert(new_ipo); - push_back(new_ipo); +BL_InterpolatorList::BL_InterpolatorList(struct AnimData *adt) { + if(adt->action==NULL) + return; + + for(FCurve *fcu= (FCurve *)adt->action->curves.first; fcu; fcu= (FCurve *)fcu->next) { + if(fcu->rna_path) { + BL_ScalarInterpolator *new_ipo = new BL_ScalarInterpolator(fcu); + //assert(new_ipo); + push_back(new_ipo); + } } } @@ -64,15 +62,13 @@ BL_InterpolatorList::~BL_InterpolatorList() { } } - -KX_IScalarInterpolator *BL_InterpolatorList::GetScalarInterpolator(BL_IpoChannel channel) { - BL_InterpolatorList::iterator i = begin(); - while (!(i == end()) && - (static_cast<BL_ScalarInterpolator *>(*i))->GetChannel() != - channel) { - ++i; +KX_IScalarInterpolator *BL_InterpolatorList::GetScalarInterpolator(const char *rna_path, int array_index) { + for(BL_InterpolatorList::iterator i = begin(); (i != end()) ; i++ ) + { + FCurve *fcu= (static_cast<BL_ScalarInterpolator *>(*i))->GetFCurve(); + if(array_index==fcu->array_index && strcmp(rna_path, fcu->rna_path)==0) + return *i; } - - return (i == end()) ? 0 : *i; + return NULL; } diff --git a/source/gameengine/Converter/KX_BlenderScalarInterpolator.h b/source/gameengine/Converter/KX_BlenderScalarInterpolator.h index 94d15aff6be..e7fbb8083e4 100644 --- a/source/gameengine/Converter/KX_BlenderScalarInterpolator.h +++ b/source/gameengine/Converter/KX_BlenderScalarInterpolator.h @@ -38,29 +38,40 @@ typedef unsigned short BL_IpoChannel; class BL_ScalarInterpolator : public KX_IScalarInterpolator { public: BL_ScalarInterpolator() {} // required for use in STL list - BL_ScalarInterpolator(struct Ipo *ipo, BL_IpoChannel channel) : - m_blender_ipo(ipo), - m_channel(channel) + BL_ScalarInterpolator(struct FCurve* fcu) : + m_fcu(fcu) {} virtual ~BL_ScalarInterpolator() {} virtual float GetValue(float currentTime) const; - - BL_IpoChannel GetChannel() const { return m_channel; } + struct FCurve *GetFCurve() { return m_fcu;}; private: - struct Ipo *m_blender_ipo; - BL_IpoChannel m_channel; + struct FCurve *m_fcu; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_ScalarInterpolator"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; class BL_InterpolatorList : public std::vector<KX_IScalarInterpolator *> { public: - BL_InterpolatorList(struct Ipo *ipo); + BL_InterpolatorList(struct AnimData *adt); ~BL_InterpolatorList(); - KX_IScalarInterpolator *GetScalarInterpolator(BL_IpoChannel channel); + KX_IScalarInterpolator *GetScalarInterpolator(const char *rna_path, int array_index); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_InterpolatorList"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_SCALARINTERPOLATOR_H diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index 7eec93dc402..151564391f3 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -44,21 +44,12 @@ #include "DummyPhysicsEnvironment.h" -//to decide to use sumo/ode or dummy physics - defines USE_ODE #include "KX_ConvertPhysicsObject.h" #ifdef USE_BULLET #include "CcdPhysicsEnvironment.h" #endif -#ifdef USE_ODE -#include "OdePhysicsEnvironment.h" -#endif //USE_ODE - -#ifdef USE_SUMO_SOLID -#include "SumoPhysicsEnvironment.h" -#endif - #include "KX_BlenderSceneConverter.h" #include "KX_BlenderScalarInterpolator.h" #include "BL_BlenderDataConversion.h" @@ -83,21 +74,20 @@ extern "C" #include "DNA_curve_types.h" #include "BLI_blenlib.h" #include "MEM_guardedalloc.h" -#include "BSE_editipo.h" -#include "BSE_editipo_types.h" +//XXX #include "BSE_editipo.h" +//XXX #include "BSE_editipo_types.h" #include "DNA_ipo_types.h" #include "BKE_global.h" +#include "BKE_ipo.h" // eval_icu #include "DNA_space_types.h" } KX_BlenderSceneConverter::KX_BlenderSceneConverter( struct Main* maggie, - struct SpaceIpo* sipo, class KX_KetsjiEngine* engine ) : m_maggie(maggie), - m_sipo(sipo), m_ketsjiEngine(engine), m_alwaysUseExpandFraming(false), m_usemat(false), @@ -114,11 +104,11 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter() // delete sumoshapes - int numipolists = m_map_blender_to_gameipolist.size(); - for (i=0; i<numipolists; i++) { - BL_InterpolatorList *ipoList= *m_map_blender_to_gameipolist.at(i); + int numAdtLists = m_map_blender_to_gameAdtList.size(); + for (i=0; i<numAdtLists; i++) { + BL_InterpolatorList *adtList= *m_map_blender_to_gameAdtList.at(i); - delete (ipoList); + delete (adtList); } vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator itw = m_worldinfos.begin(); @@ -146,10 +136,6 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter() delete (*itm).second; itm++; } - -#ifdef USE_SUMO_SOLID - KX_ClearSumoSharedShapes(); -#endif #ifdef USE_BULLET KX_ClearBulletSharedShapes(); @@ -256,55 +242,52 @@ struct BlenderDebugDraw : public btIDebugDraw #endif -void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename, - class KX_Scene* destinationscene, +void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene, PyObject* dictobj, - class SCA_IInputDevice* keyinputdev, class RAS_IRenderTools* rendertools, class RAS_ICanvas* canvas) { //find out which physics engine - Scene *blenderscene = GetBlenderSceneForName(scenename); + Scene *blenderscene = destinationscene->GetBlenderScene(); e_PhysicsEngine physics_engine = UseBullet; + bool useDbvtCulling = false; // hook for registration function during conversion. m_currentScene = destinationscene; destinationscene->SetSceneConverter(this); + SG_SetActiveStage(SG_STAGE_CONVERTER); if (blenderscene) { - if (blenderscene->world) + switch (blenderscene->gm.physicsEngine) { - switch (blenderscene->world->physicsEngine) + case WOPHY_BULLET: { - case WOPHY_BULLET: - { - physics_engine = UseBullet; - break; - } - - case WOPHY_ODE: - { - physics_engine = UseODE; - break; - } - case WOPHY_DYNAMO: - { - physics_engine = UseDynamo; - break; - } - case WOPHY_SUMO: - { - physics_engine = UseSumo; - break; - } - case WOPHY_NONE: - { - physics_engine = UseNone; - } + physics_engine = UseBullet; + useDbvtCulling = (blenderscene->gm.mode & WO_DBVT_CULLING) != 0; + break; + } + + case WOPHY_ODE: + { + physics_engine = UseODE; + break; + } + case WOPHY_DYNAMO: + { + physics_engine = UseDynamo; + break; + } + case WOPHY_SUMO: + { + physics_engine = UseSumo; + break; + } + case WOPHY_NONE: + { + physics_engine = UseNone; } - } } @@ -313,7 +296,7 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename, #ifdef USE_BULLET case UseBullet: { - CcdPhysicsEnvironment* ccdPhysEnv = new CcdPhysicsEnvironment(); + CcdPhysicsEnvironment* ccdPhysEnv = new CcdPhysicsEnvironment(useDbvtCulling); ccdPhysEnv->setDebugDrawer(new BlenderDebugDraw()); ccdPhysEnv->setDeactivationLinearTreshold(0.8f); // default, can be overridden by Python ccdPhysEnv->setDeactivationAngularTreshold(1.0f); // default, can be overridden by Python @@ -321,7 +304,7 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename, SYS_SystemHandle syshandle = SYS_GetSystem(); /*unused*/ int visualizePhysics = SYS_GetCommandLineInt(syshandle,"show_physics",0); if (visualizePhysics) - ccdPhysEnv->setDebugMode(btIDebugDraw::DBG_DrawWireframe|btIDebugDraw::DBG_DrawAabb|btIDebugDraw::DBG_DrawContactPoints|btIDebugDraw::DBG_DrawText); + ccdPhysEnv->setDebugMode(btIDebugDraw::DBG_DrawWireframe|btIDebugDraw::DBG_DrawAabb|btIDebugDraw::DBG_DrawContactPoints|btIDebugDraw::DBG_DrawText|btIDebugDraw::DBG_DrawConstraintLimits|btIDebugDraw::DBG_DrawConstraints); //todo: get a button in blender ? //disable / enable debug drawing (contact points, aabb's etc) @@ -329,20 +312,7 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename, destinationscene->SetPhysicsEnvironment(ccdPhysEnv); break; } -#endif - -#ifdef USE_SUMO_SOLID - case UseSumo: - destinationscene ->SetPhysicsEnvironment(new SumoPhysicsEnvironment()); - break; -#endif -#ifdef USE_ODE - - case UseODE: - destinationscene ->SetPhysicsEnvironment(new ODEPhysicsEnvironment()); - break; -#endif //USE_ODE - +#endif case UseDynamo: { } @@ -355,12 +325,10 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename, } BL_ConvertBlenderObjects(m_maggie, - scenename, destinationscene, m_ketsjiEngine, physics_engine, dictobj, - keyinputdev, rendertools, canvas, this, @@ -377,10 +345,6 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename, //This cache mecanism is buggy so I leave it disable and the memory leak //that would result from this is fixed in RemoveScene() m_map_mesh_to_gamemesh.clear(); - //Don't clear this lookup, it is needed for the baking physics into ipo animation - //To avoid it's infinite grows, object will be unregister when they are deleted - //see KX_Scene::NewRemoveObject - //m_map_gameobject_to_blender.clear(); } // This function removes all entities stored in the converter for that scene @@ -494,27 +458,28 @@ void KX_BlenderSceneConverter::RegisterGameObject( KX_GameObject *gameobject, struct Object *for_blenderobject) { - m_map_gameobject_to_blender.insert(CHashedPtr(gameobject),for_blenderobject); + /* only maintained while converting, freed during game runtime */ m_map_blender_to_gameobject.insert(CHashedPtr(for_blenderobject),gameobject); } +/* only need to run this during conversion since + * m_map_blender_to_gameobject is freed after conversion */ void KX_BlenderSceneConverter::UnregisterGameObject( KX_GameObject *gameobject) { - CHashedPtr gptr(gameobject); - struct Object **bobp= m_map_gameobject_to_blender[gptr]; + struct Object *bobp= gameobject->GetBlenderObject(); if (bobp) { - CHashedPtr bptr(*bobp); + CHashedPtr bptr(bobp); KX_GameObject **gobp= m_map_blender_to_gameobject[bptr]; if (gobp && *gobp == gameobject) + { // also maintain m_map_blender_to_gameobject if the gameobject // being removed is matching the blender object m_map_blender_to_gameobject.remove(bptr); - m_map_gameobject_to_blender.remove(gptr); + } } } - KX_GameObject *KX_BlenderSceneConverter::FindGameObject( struct Object *for_blenderobject) { @@ -523,18 +488,6 @@ KX_GameObject *KX_BlenderSceneConverter::FindGameObject( return obp?*obp:NULL; } - - -struct Object *KX_BlenderSceneConverter::FindBlenderObject( - KX_GameObject *for_gameobject) -{ - struct Object **obp= m_map_gameobject_to_blender[CHashedPtr(for_gameobject)]; - - return obp?*obp:NULL; -} - - - void KX_BlenderSceneConverter::RegisterGameMesh( RAS_MeshObject *gamemesh, struct Mesh *for_blendermesh) @@ -546,12 +499,12 @@ void KX_BlenderSceneConverter::RegisterGameMesh( RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh( - struct Mesh *for_blendermesh, - unsigned int onlayer) + struct Mesh *for_blendermesh/*, + unsigned int onlayer*/) { RAS_MeshObject** meshp = m_map_mesh_to_gamemesh[CHashedPtr(for_blendermesh)]; - if (meshp && onlayer==(*meshp)->GetLightLayer()) { + if (meshp/* && onlayer==(*meshp)->GetLightLayer()*/) { return *meshp; } else { return NULL; @@ -571,18 +524,18 @@ void KX_BlenderSceneConverter::RegisterPolyMaterial(RAS_IPolyMaterial *polymat) void KX_BlenderSceneConverter::RegisterInterpolatorList( - BL_InterpolatorList *ipoList, - struct Ipo *for_ipo) + BL_InterpolatorList *adtList, + struct AnimData *for_adt) { - m_map_blender_to_gameipolist.insert(CHashedPtr(for_ipo), ipoList); + m_map_blender_to_gameAdtList.insert(CHashedPtr(for_adt), adtList); } BL_InterpolatorList *KX_BlenderSceneConverter::FindInterpolatorList( - struct Ipo *for_ipo) + struct AnimData *for_adt) { - BL_InterpolatorList **listp = m_map_blender_to_gameipolist[CHashedPtr(for_ipo)]; + BL_InterpolatorList **listp = m_map_blender_to_gameAdtList[CHashedPtr(for_adt)]; return listp?*listp:NULL; } @@ -637,13 +590,14 @@ void KX_BlenderSceneConverter::RegisterWorldInfo( * When deleting an IPO curve from Python, check if the IPO is being * edited and if so clear the pointer to the old curve. */ -void KX_BlenderSceneConverter::localDel_ipoCurve ( IpoCurve * icu ,struct SpaceIpo* sipo) +void KX_BlenderSceneConverter::localDel_ipoCurve ( IpoCurve * icu ) { - if (!sipo) +#if 0 //XXX + if (!G.sipo) return; int i; - EditIpo *ei= (EditIpo *)sipo->editipo; + EditIpo *ei= (EditIpo *)G.sipo->editipo; if (!ei) return; for(i=0; i<G.sipo->totipo; i++, ei++) { @@ -653,17 +607,20 @@ void KX_BlenderSceneConverter::localDel_ipoCurve ( IpoCurve * icu ,struct SpaceI return; } } +#endif } //quick hack extern "C" { Ipo *add_ipo( char *name, int idcode ); - char *getIpoCurveName( IpoCurve * icu ); - struct IpoCurve *verify_ipocurve(struct ID *, short, char *, char *, char *, int, short); - void testhandles_ipocurve(struct IpoCurve *icu); + //XXX char *getIpoCurveName( IpoCurve * icu ); + //XXX struct IpoCurve *verify_ipocurve(struct ID *, short, char *, char *, char *, int); + //XXX void testhandles_ipocurve(struct IpoCurve *icu); void insert_vert_icu(struct IpoCurve *, float, float, short); - void Mat3ToEul(float tmat[][3], float *eul); + float eval_icu(struct IpoCurve *icu, float ipotime); + //void Mat3ToEul(float tmat[][3], float *eul); + void Mat3ToCompatibleEul(float mat[][3], float *eul, float *oldrot); } IpoCurve* findIpoCurve(IpoCurve* first, const char* searchName) @@ -671,11 +628,11 @@ IpoCurve* findIpoCurve(IpoCurve* first, const char* searchName) IpoCurve* icu1; for( icu1 = first; icu1; icu1 = icu1->next ) { - char* curveName = getIpoCurveName( icu1 ); + /*XXX char* curveName = getIpoCurveName( icu1 ); if( !strcmp( curveName, searchName) ) { return icu1; - } + }*/ } return 0; } @@ -717,7 +674,7 @@ void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo(bool clearIpo) { //KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); - Object* blenderObject = FindBlenderObject(gameObj); + Object* blenderObject = gameObj->GetBlenderObject(); if (blenderObject) { //erase existing ipo's @@ -745,11 +702,11 @@ void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo(bool clearIpo) if( tmpicu->bezt ) MEM_freeN( tmpicu->bezt ); MEM_freeN( tmpicu ); - localDel_ipoCurve( tmpicu ,m_sipo); + localDel_ipoCurve( tmpicu ); } } } else - { ipo = add_ipo(blenderObject->id.name+2, ID_OB); + { ipo = NULL; // XXX add_ipo(blenderObject->id.name+2, ID_OB); blenderObject->ipo = ipo; } @@ -781,7 +738,7 @@ void KX_BlenderSceneConverter::resetNoneDynamicObjectToIpo(){ for (int ix=0;ix<parentList->GetCount();ix++){ KX_GameObject* gameobj = (KX_GameObject*)parentList->GetValue(ix); if (!gameobj->IsDynamic()){ - Object* blenderobject = FindBlenderObject(gameobj); + Object* blenderobject = gameobj->GetBlenderObject(); if (!blenderobject) continue; if (blenderobject->type==OB_ARMATURE) @@ -806,14 +763,13 @@ void KX_BlenderSceneConverter::resetNoneDynamicObjectToIpo(){ gameobj->NodeSetLocalPosition(pos); gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz)); gameobj->NodeSetLocalScale(scale); - gameobj->NodeUpdateGS(0,true); + gameobj->NodeUpdateGS(0); } } } } } -#define TEST_HANDLES_GAME2IPO 0 ///this generates ipo curves for position, rotation, allowing to use game physics in animation void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber) @@ -836,139 +792,84 @@ void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber) { //KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); - Object* blenderObject = FindBlenderObject(gameObj); - if (blenderObject) + Object* blenderObject = gameObj->GetBlenderObject(); + if (blenderObject && blenderObject->ipo) { - +#if 0 + const MT_Point3& position = gameObj->NodeGetWorldPosition(); + //const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); const MT_Matrix3x3& orn = gameObj->NodeGetWorldOrientation(); + float eulerAngles[3]; + float eulerAnglesOld[3] = {0.0f, 0.0f, 0.0f}; float tmat[3][3]; - for (int r=0;r<3;r++) - { - for (int c=0;c<3;c++) - { - tmat[r][c] = orn[c][r]; - } - } - Mat3ToEul(tmat, eulerAngles); - - for(int x = 0; x < 3; x++) { - eulerAngles[x] *= (float) (180 / 3.14159265f); - } - - eulerAngles[0]/=10.f; - eulerAngles[1]/=10.f; - eulerAngles[2]/=10.f; - - - - //const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); - const MT_Point3& position = gameObj->NodeGetWorldPosition(); + // XXX animato Ipo* ipo = blenderObject->ipo; - if (ipo) - { - //create the curves, if not existing + //create the curves, if not existing, set linear if new - IpoCurve *icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); - if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X, 1); + IpoCurve *icu_lx = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); + if (!icu_lx) { + icu_lx = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X, 1); + if(icu_lx) icu_lx->ipo = IPO_LIN; + } + IpoCurve *icu_ly = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); + if (!icu_ly) { + icu_ly = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y, 1); + if(icu_ly) icu_ly->ipo = IPO_LIN; + } + IpoCurve *icu_lz = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); + if (!icu_lz) { + icu_lz = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z, 1); + if(icu_lz) icu_lz->ipo = IPO_LIN; + } + IpoCurve *icu_rx = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); + if (!icu_rx) { + icu_rx = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X, 1); + if(icu_rx) icu_rx->ipo = IPO_LIN; + } + IpoCurve *icu_ry = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); + if (!icu_ry) { + icu_ry = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y, 1); + if(icu_ry) icu_ry->ipo = IPO_LIN; + } + IpoCurve *icu_rz = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); + if (!icu_rz) { + icu_rz = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z, 1); + if(icu_rz) icu_rz->ipo = IPO_LIN; + } - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); - if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y, 1); + if(icu_rx) eulerAnglesOld[0]= eval_icu( icu_rx, frameNumber - 1 ) / ((180 / 3.14159265f) / 10); + if(icu_ry) eulerAnglesOld[1]= eval_icu( icu_ry, frameNumber - 1 ) / ((180 / 3.14159265f) / 10); + if(icu_rz) eulerAnglesOld[2]= eval_icu( icu_rz, frameNumber - 1 ) / ((180 / 3.14159265f) / 10); + + // orn.getValue((float *)tmat); // uses the wrong ordering, cant use this + for (int r=0;r<3;r++) + for (int c=0;c<3;c++) + tmat[r][c] = orn[c][r]; + + // Mat3ToEul(tmat, eulerAngles); // better to use Mat3ToCompatibleEul + Mat3ToCompatibleEul(tmat, eulerAngles, eulerAnglesOld); + + //eval_icu + for(int x = 0; x < 3; x++) + eulerAngles[x] *= (float) ((180 / 3.14159265f) / 10.0); - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); - if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z, 1); - - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); - if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X, 1); - - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); - if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y, 1); - - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); - if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z, 1); - - - //fill the curves with data - - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); - if (icu1) - { - float curVal = position.x(); - insert_vert_icu(icu1, frameNumber, curVal, 0); -#ifdef TEST_HANDLES_GAME2IPO - testhandles_ipocurve(icu1); -#endif - } - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); - if (icu1) - { - float curVal = position.y(); - insert_vert_icu(icu1, frameNumber, curVal, 0); -#ifdef TEST_HANDLES_GAME2IPO - - testhandles_ipocurve(icu1); -#endif - } - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); - if (icu1) - { - float curVal = position.z(); - insert_vert_icu(icu1, frameNumber, curVal, 0); -#ifdef TEST_HANDLES_GAME2IPO - testhandles_ipocurve(icu1); -#endif - } - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); - if (icu1) - { - float curVal = eulerAngles[0]; - insert_vert_icu(icu1, frameNumber, curVal, 0); -#ifdef TEST_HANDLES_GAME2IPO - - testhandles_ipocurve(icu1); -#endif - } - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); - if (icu1) - { - float curVal = eulerAngles[1]; - insert_vert_icu(icu1, frameNumber, curVal, 0); -#ifdef TEST_HANDLES_GAME2IPO - - testhandles_ipocurve(icu1); -#endif - } - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); - if (icu1) - { - float curVal = eulerAngles[2]; - insert_vert_icu(icu1, frameNumber, curVal, 0); -#ifdef TEST_HANDLES_GAME2IPO - - testhandles_ipocurve(icu1); + if (icu_lx) insert_vert_icu(icu_lx, frameNumber, position.x(), 1); + if (icu_ly) insert_vert_icu(icu_ly, frameNumber, position.y(), 1); + if (icu_lz) insert_vert_icu(icu_lz, frameNumber, position.z(), 1); + if (icu_rx) insert_vert_icu(icu_rx, frameNumber, eulerAngles[0], 1); + if (icu_ry) insert_vert_icu(icu_ry, frameNumber, eulerAngles[1], 1); + if (icu_rz) insert_vert_icu(icu_rz, frameNumber, eulerAngles[2], 1); + + // Handles are corrected at the end, testhandles_ipocurve isnt needed yet #endif - - } - - } } } - } - - - } - - + } } @@ -992,101 +893,22 @@ void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo() { //KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); - Object* blenderObject = FindBlenderObject(gameObj); - if (blenderObject) + Object* blenderObject = gameObj->GetBlenderObject(); + if (blenderObject && blenderObject->ipo) { - - const MT_Matrix3x3& orn = gameObj->NodeGetWorldOrientation(); - float eulerAngles[3]; - float tmat[3][3]; - for (int r=0;r<3;r++) - { - for (int c=0;c<3;c++) - { - tmat[r][c] = orn[c][r]; - } - } - Mat3ToEul(tmat, eulerAngles); - - for(int x = 0; x < 3; x++) { - eulerAngles[x] *= (float) (180 / 3.14159265f); - } - - eulerAngles[0]/=10.f; - eulerAngles[1]/=10.f; - eulerAngles[2]/=10.f; - - - - //const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); - //const MT_Point3& position = gameObj->NodeGetWorldPosition(); - + // XXX animato +#if 0 Ipo* ipo = blenderObject->ipo; - if (ipo) - { - - //create the curves, if not existing - - IpoCurve *icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); - if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X, 1); - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); - if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y, 1); - - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); - if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z, 1); - - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); - if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X, 1); - - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); - if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y, 1); - - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); - if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z, 1); - - - - //fill the curves with data - - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); - if (icu1) - { - testhandles_ipocurve(icu1); - } - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); - if (icu1) - { - testhandles_ipocurve(icu1); - } - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); - if (icu1) - { - testhandles_ipocurve(icu1); - } - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); - if (icu1) - { - testhandles_ipocurve(icu1); - } - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); - if (icu1) - { - testhandles_ipocurve(icu1); - } - icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); - if (icu1) - { - testhandles_ipocurve(icu1); - } - - } + //create the curves, if not existing + //testhandles_ipocurve checks for NULL + testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"LocX")); + testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"LocY")); + testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ")); + testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotX")); + testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotY")); + testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ")); +#endif } } diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.h b/source/gameengine/Converter/KX_BlenderSceneConverter.h index 2317e952a0a..bb87a21a683 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.h +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.h @@ -44,7 +44,6 @@ class BL_InterpolatorList; class BL_Material; struct IpoCurve; struct Main; -struct SpaceIpo; struct Scene; class KX_BlenderSceneConverter : public KX_ISceneConverter @@ -57,19 +56,14 @@ class KX_BlenderSceneConverter : public KX_ISceneConverter // Should also have a list of collision shapes. // For the time being this is held in KX_Scene::m_shapes - GEN_Map<CHashedPtr,struct Object*> m_map_gameobject_to_blender; - GEN_Map<CHashedPtr,KX_GameObject*> m_map_blender_to_gameobject; - - GEN_Map<CHashedPtr,RAS_MeshObject*> m_map_mesh_to_gamemesh; -// GEN_Map<CHashedPtr,DT_ShapeHandle> m_map_gamemesh_to_sumoshape; - - GEN_Map<CHashedPtr,SCA_IActuator*> m_map_blender_to_gameactuator; - GEN_Map<CHashedPtr,SCA_IController*> m_map_blender_to_gamecontroller; + GEN_Map<CHashedPtr,KX_GameObject*> m_map_blender_to_gameobject; /* cleared after conversion */ + GEN_Map<CHashedPtr,RAS_MeshObject*> m_map_mesh_to_gamemesh; /* cleared after conversion */ + GEN_Map<CHashedPtr,SCA_IActuator*> m_map_blender_to_gameactuator; /* cleared after conversion */ + GEN_Map<CHashedPtr,SCA_IController*>m_map_blender_to_gamecontroller; /* cleared after conversion */ - GEN_Map<CHashedPtr,BL_InterpolatorList*> m_map_blender_to_gameipolist; + GEN_Map<CHashedPtr,BL_InterpolatorList*> m_map_blender_to_gameAdtList; Main* m_maggie; - SpaceIpo* m_sipo; STR_String m_newfilename; class KX_KetsjiEngine* m_ketsjiEngine; @@ -78,13 +72,12 @@ class KX_BlenderSceneConverter : public KX_ISceneConverter bool m_usemat; bool m_useglslmat; - void localDel_ipoCurve ( IpoCurve * icu ,struct SpaceIpo* sipo); + void localDel_ipoCurve ( IpoCurve * icu ); // struct Ipo* findIpoForName(char* objName); public: KX_BlenderSceneConverter( Main* maggie, - SpaceIpo *sipo, class KX_KetsjiEngine* engine ); @@ -95,10 +88,8 @@ public: * dictobj: python dictionary (for pythoncontrollers) */ virtual void ConvertScene( - const STR_String& scenename, class KX_Scene* destinationscene, PyObject* dictobj, - class SCA_IInputDevice* keyinputdev, class RAS_IRenderTools* rendertools, class RAS_ICanvas* canvas ); @@ -112,20 +103,16 @@ public: void RegisterGameObject(KX_GameObject *gameobject, struct Object *for_blenderobject); void UnregisterGameObject(KX_GameObject *gameobject); KX_GameObject *FindGameObject(struct Object *for_blenderobject); - struct Object *FindBlenderObject(KX_GameObject *for_gameobject); void RegisterGameMesh(RAS_MeshObject *gamemesh, struct Mesh *for_blendermesh); - RAS_MeshObject *FindGameMesh(struct Mesh *for_blendermesh, unsigned int onlayer); - -// void RegisterSumoShape(DT_ShapeHandle shape, RAS_MeshObject *for_gamemesh); -// DT_ShapeHandle FindSumoShape(RAS_MeshObject *for_gamemesh); + RAS_MeshObject *FindGameMesh(struct Mesh *for_blendermesh/*, unsigned int onlayer*/); void RegisterPolyMaterial(RAS_IPolyMaterial *polymat); void RegisterBlenderMaterial(BL_Material *mat); - void RegisterInterpolatorList(BL_InterpolatorList *ipoList, struct Ipo *for_ipo); - BL_InterpolatorList *FindInterpolatorList(struct Ipo *for_ipo); + void RegisterInterpolatorList(BL_InterpolatorList *adtList, struct AnimData *for_adt); + BL_InterpolatorList *FindInterpolatorList(struct AnimData *for_adt); void RegisterGameActuator(SCA_IActuator *act, struct bActuator *for_actuator); SCA_IActuator *FindGameActuator(struct bActuator *for_actuator); @@ -153,6 +140,15 @@ public: virtual bool GetGLSLMaterials(); struct Scene* GetBlenderSceneForName(const STR_String& name); + + struct Main* GetMain() { return m_maggie; }; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_BlenderSceneConverter"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_BLENDERSCENECONVERTER_H diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 4f152acc918..91a39bd7686 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -38,7 +38,7 @@ #include "KX_BlenderSceneConverter.h" #include "KX_ConvertActuators.h" - +#include "AUD_C-API.h" // Actuators //SCA logiclibrary native logicbricks #include "SCA_PropertyActuator.h" @@ -50,7 +50,6 @@ #include "KX_SceneActuator.h" #include "KX_IpoActuator.h" #include "KX_SoundActuator.h" -#include "KX_CDActuator.h" #include "KX_ObjectActuator.h" #include "KX_TrackToActuator.h" #include "KX_ConstraintActuator.h" @@ -105,7 +104,6 @@ void BL_ConvertActuators(char* maggiename, SCA_LogicManager* logicmgr, KX_Scene* scene, KX_KetsjiEngine* ketsjiEngine, - int & executePriority, int activeLayerBitInfo, bool isInActiveLayer, RAS_IRenderTools* rendertools, @@ -114,11 +112,20 @@ void BL_ConvertActuators(char* maggiename, { int uniqueint = 0; + int actcount = 0; + int executePriority = 0; bActuator* bact = (bActuator*) blenderobject->actuators.first; + while (bact) + { + actcount++; + bact = bact->next; + } + gameobj->ReserveActuator(actcount); + bact = (bActuator*) blenderobject->actuators.first; while(bact) { STR_String uniquename = bact->name; - STR_String objectname = gameobj->GetName(); + STR_String& objectname = gameobj->GetName(); SCA_IActuator* baseact = NULL; switch (bact->type) @@ -126,6 +133,7 @@ void BL_ConvertActuators(char* maggiename, case ACT_OBJECT: { bObjectActuator* obact = (bObjectActuator*) bact->data; + KX_GameObject* obref = NULL; MT_Vector3 forcevec(KX_BLENDERTRUNC(obact->forceloc[0]), KX_BLENDERTRUNC(obact->forceloc[1]), KX_BLENDERTRUNC(obact->forceloc[2])); @@ -163,9 +171,13 @@ void BL_ConvertActuators(char* maggiename, bitLocalFlag.AngularVelocity = bool((obact->flag & ACT_ANG_VEL_LOCAL)!=0); bitLocalFlag.ServoControl = bool(obact->type == ACT_OBJECT_SERVO); bitLocalFlag.AddOrSetLinV = bool((obact->flag & ACT_ADD_LIN_VEL)!=0); - + if (obact->reference && bitLocalFlag.ServoControl) + { + obref = converter->FindGameObject(obact->reference); + } KX_ObjectActuator* tmpbaseact = new KX_ObjectActuator(gameobj, + obref, forcevec.getValue(), torquevec.getValue(), dlocvec.getValue(), @@ -334,8 +346,7 @@ void BL_ConvertActuators(char* maggiename, { bSoundActuator* soundact = (bSoundActuator*) bact->data; /* get type, and possibly a start and end frame */ - short startFrame = soundact->sta, stopFrame = soundact->end; - KX_SoundActuator::KX_SOUNDACT_TYPE + KX_SoundActuator::KX_SOUNDACT_TYPE soundActuatorType = KX_SoundActuator::KX_SOUNDACT_NODEF; switch(soundact->type) { @@ -365,173 +376,38 @@ void BL_ConvertActuators(char* maggiename, if (soundActuatorType != KX_SoundActuator::KX_SOUNDACT_NODEF) { - SND_Scene* soundscene = scene->GetSoundScene(); - STR_String samplename = ""; - bool sampleisloaded = false; - - if (soundact->sound) { - /* Need to convert the samplename into absolute path - * before checking if its loaded */ - char fullpath[FILE_MAX]; - - /* dont modify soundact->sound->name, only change a copy */ - BLI_strncpy(fullpath, soundact->sound->name, sizeof(fullpath)); - BLI_convertstringcode(fullpath, maggiename); - samplename = fullpath; - - /* let's see if the sample was already loaded */ - if (soundscene->IsSampleLoaded(samplename)) - { - sampleisloaded = true; - } - else { - /* if not, make it so */ - PackedFile* pf = soundact->sound->newpackedfile; - - /* but we need a packed file then */ - if (pf) - { - if (soundscene->LoadSample(samplename, pf->data, pf->size) > -1) - sampleisloaded = true; - } - /* or else load it from disk */ - else - { - if (soundscene->LoadSample(samplename, NULL, 0) > -1) { - sampleisloaded = true; - } - else { - std::cout << "WARNING: Sound actuator \"" << bact->name << - "\" from object \"" << blenderobject->id.name+2 << - "\" failed to load sample." << std::endl; - } - } - } - } else { + bSound* sound = soundact->sound; + bool is3d = soundact->flag & ACT_SND_3D_SOUND ? true : false; + AUD_Sound* snd_sound = NULL; + KX_3DSoundSettings settings; + settings.cone_inner_angle = soundact->sound3D.cone_inner_angle; + settings.cone_outer_angle = soundact->sound3D.cone_outer_angle; + settings.cone_outer_gain = soundact->sound3D.cone_outer_gain; + settings.max_distance = soundact->sound3D.max_distance; + settings.max_gain = soundact->sound3D.max_gain; + settings.min_gain = soundact->sound3D.min_gain; + settings.reference_distance = soundact->sound3D.reference_distance; + settings.rolloff_factor = soundact->sound3D.rolloff_factor; + + if(!sound) + { std::cout << "WARNING: Sound actuator \"" << bact->name << "\" from object \"" << blenderobject->id.name+2 << "\" has no sound datablock." << std::endl; } - - /* Note, allowing actuators for sounds that are not there was added since 2.47 - * This is because python may expect the actuator and raise an exception if it dosnt find it - * better just to add a dummy sound actuator. */ - SND_SoundObject* sndobj = NULL; - if (sampleisloaded) - { - /* setup the SND_SoundObject */ - sndobj = new SND_SoundObject(); - sndobj->SetSampleName(samplename.Ptr()); - sndobj->SetObjectName(bact->name); - if (soundact->sound) { - sndobj->SetRollOffFactor(soundact->sound->attenuation); - sndobj->SetGain(soundact->sound->volume); - sndobj->SetPitch(exp((soundact->sound->pitch / 12.0) * log(2.0))); - // sndobj->SetLoopStart(soundact->sound->loopstart); - // sndobj->SetLoopStart(soundact->sound->loopend); - if (soundact->sound->flags & SOUND_FLAGS_LOOP) - { - if (soundact->sound->flags & SOUND_FLAGS_BIDIRECTIONAL_LOOP) - sndobj->SetLoopMode(SND_LOOP_BIDIRECTIONAL); - else - sndobj->SetLoopMode(SND_LOOP_NORMAL); - } - else { - sndobj->SetLoopMode(SND_LOOP_OFF); - } - - if (soundact->sound->flags & SOUND_FLAGS_PRIORITY) - sndobj->SetHighPriority(true); - else - sndobj->SetHighPriority(false); - - if (soundact->sound->flags & SOUND_FLAGS_3D) - sndobj->Set3D(true); - else - sndobj->Set3D(false); - } - else { - /* dummy values for a NULL sound - * see editsound.c - defaults are unlikely to change soon */ - sndobj->SetRollOffFactor(1.0); - sndobj->SetGain(1.0); - sndobj->SetPitch(1.0); - sndobj->SetLoopMode(SND_LOOP_OFF); - sndobj->SetHighPriority(false); - sndobj->Set3D(false); - } - } - KX_SoundActuator* tmpsoundact = - new KX_SoundActuator(gameobj, - sndobj, - scene->GetSoundScene(), // needed for replication! - soundActuatorType, - startFrame, - stopFrame); - + else + snd_sound = sound->cache ? sound->cache : sound->handle; + KX_SoundActuator* tmpsoundact = + new KX_SoundActuator(gameobj, + snd_sound, + soundact->volume, + exp((soundact->pitch / 12.0) * log(2.0)), + is3d, + settings, + soundActuatorType); + tmpsoundact->SetName(bact->name); baseact = tmpsoundact; - if (sndobj) - soundscene->AddObject(sndobj); - } - break; - } - case ACT_CD: - { - bCDActuator* cdact = (bCDActuator*) bact->data; - /* get type, and possibly a start and end frame */ - short startFrame = cdact->sta, stopFrame = cdact->end; - KX_CDActuator::KX_CDACT_TYPE - cdActuatorType = KX_CDActuator::KX_CDACT_NODEF; - - switch(cdact->type) - { - case ACT_CD_PLAY_ALL: - cdActuatorType = KX_CDActuator::KX_CDACT_PLAY_ALL; - break; - case ACT_CD_PLAY_TRACK: - cdActuatorType = KX_CDActuator::KX_CDACT_PLAY_TRACK; - break; - case ACT_CD_LOOP_TRACK: - cdActuatorType = KX_CDActuator::KX_CDACT_LOOP_TRACK; - break; - case ACT_CD_VOLUME: - cdActuatorType = KX_CDActuator::KX_CDACT_VOLUME; - break; - case ACT_CD_STOP: - cdActuatorType = KX_CDActuator::KX_CDACT_STOP; - break; - case ACT_CD_PAUSE: - cdActuatorType = KX_CDActuator::KX_CDACT_PAUSE; - break; - case ACT_CD_RESUME: - cdActuatorType = KX_CDActuator::KX_CDACT_RESUME; - break; - - default: - /* This is an error!!! */ - cdActuatorType = KX_CDActuator::KX_CDACT_NODEF; - } - - if (cdActuatorType != KX_CDActuator::KX_CDACT_NODEF) - { - SND_CDObject* pCD = SND_CDObject::Instance(); - - if (pCD) - { - pCD->SetGain(cdact->volume); - - KX_CDActuator* tmpcdact = - new KX_CDActuator(gameobj, - scene->GetSoundScene(), // needed for replication! - cdActuatorType, - cdact->track, - startFrame, - stopFrame); - - tmpcdact->SetName(bact->name); - baseact = tmpcdact; - } } break; } @@ -585,15 +461,6 @@ void BL_ConvertActuators(char* maggiename, originalval = converter->FindGameObject(editobact->ob); } } - MT_Vector3 linvelvec ( - KX_BLENDERTRUNC(editobact->linVelocity[0]), - KX_BLENDERTRUNC(editobact->linVelocity[1]), - KX_BLENDERTRUNC(editobact->linVelocity[2])); - - MT_Vector3 angvelvec ( - KX_BLENDERTRUNC(editobact->angVelocity[0]), - KX_BLENDERTRUNC(editobact->angVelocity[1]), - KX_BLENDERTRUNC(editobact->angVelocity[2])); KX_SCA_AddObjectActuator* tmpaddact = new KX_SCA_AddObjectActuator( @@ -601,9 +468,9 @@ void BL_ConvertActuators(char* maggiename, originalval, editobact->time, scene, - linvelvec.getValue(), + editobact->linVelocity, (editobact->localflag & ACT_EDOB_LOCAL_LINV)!=0, - angvelvec.getValue(), + editobact->angVelocity, (editobact->localflag & ACT_EDOB_LOCAL_ANGV)!=0 ); @@ -625,7 +492,6 @@ void BL_ConvertActuators(char* maggiename, tmpmesh = BL_ConvertMesh( editobact->me, blenderobject, - rendertools, scene, converter ); @@ -634,7 +500,10 @@ void BL_ConvertActuators(char* maggiename, = new KX_SCA_ReplaceMeshActuator( gameobj, tmpmesh, - scene + scene, + (editobact->flag & ACT_EDOB_REPLACE_MESH_NOGFX)==0, + (editobact->flag & ACT_EDOB_REPLACE_MESH_PHYS)!=0 + ); baseact = tmpreplaceact; @@ -661,7 +530,8 @@ void BL_ConvertActuators(char* maggiename, { KX_SCA_DynamicActuator* tmpdynact = new KX_SCA_DynamicActuator(gameobj, - editobact->dyn_operation + editobact->dyn_operation, + editobact->mass ); baseact = tmpdynact; } @@ -949,6 +819,11 @@ void BL_ConvertActuators(char* maggiename, = (bRandomActuator *) bact->data; unsigned long seedArg = randAct->seed; + if (seedArg == 0) + { + seedArg = (int)(ketsjiEngine->GetRealTime()*100000.0); + seedArg ^= (intptr_t)randAct; + } SCA_RandomActuator::KX_RANDOMACT_MODE modeArg = SCA_RandomActuator::KX_RANDOMACT_NODEF; SCA_RandomActuator *tmprandomact; @@ -1016,9 +891,10 @@ void BL_ConvertActuators(char* maggiename, bVisibilityActuator *vis_act = (bVisibilityActuator *) bact->data; KX_VisibilityActuator * tmp_vis_act = NULL; bool v = ((vis_act->flag & ACT_VISIBILITY_INVISIBLE) != 0); + bool o = ((vis_act->flag & ACT_VISIBILITY_OCCLUSION) != 0); bool recursive = ((vis_act->flag & ACT_VISIBILITY_RECURSIVE) != 0); - tmp_vis_act = new KX_VisibilityActuator(gameobj, !v, recursive); + tmp_vis_act = new KX_VisibilityActuator(gameobj, !v, o, recursive); baseact = tmp_vis_act; } @@ -1104,7 +980,7 @@ void BL_ConvertActuators(char* maggiename, buf = txt_to_buf(_2dfilter->text); if (buf) { - tmp->SetShaderText(STR_String(buf)); + tmp->SetShaderText(buf); MEM_freeN(buf); } } @@ -1117,6 +993,8 @@ void BL_ConvertActuators(char* maggiename, { bParentActuator *parAct = (bParentActuator *) bact->data; int mode = KX_ParentActuator::KX_PARENT_NODEF; + bool addToCompound = true; + bool ghost = true; KX_GameObject *tmpgob = NULL; switch(parAct->type) @@ -1124,6 +1002,8 @@ void BL_ConvertActuators(char* maggiename, case ACT_PARENT_SET: mode = KX_ParentActuator::KX_PARENT_SET; tmpgob = converter->FindGameObject(parAct->ob); + addToCompound = !(parAct->flag & ACT_PARENT_COMPOUND); + ghost = !(parAct->flag & ACT_PARENT_GHOST); break; case ACT_PARENT_REMOVE: mode = KX_ParentActuator::KX_PARENT_REMOVE; @@ -1134,6 +1014,8 @@ void BL_ConvertActuators(char* maggiename, KX_ParentActuator *tmpparact = new KX_ParentActuator(gameobj, mode, + addToCompound, + ghost, tmpgob); baseact = tmpparact; break; @@ -1151,7 +1033,7 @@ void BL_ConvertActuators(char* maggiename, CIntValue* uniqueval = new CIntValue(uniqueint); uniquename += uniqueval->GetText(); uniqueval->Release(); - baseact->SetName(STR_String(bact->name)); + baseact->SetName(bact->name); //gameobj->SetProperty(uniquename,baseact); gameobj->AddActuator(baseact); diff --git a/source/gameengine/Converter/KX_ConvertActuators.h b/source/gameengine/Converter/KX_ConvertActuators.h index 03ea0db99b9..e38a9c74efc 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.h +++ b/source/gameengine/Converter/KX_ConvertActuators.h @@ -35,7 +35,6 @@ void BL_ConvertActuators(char* maggiename, class SCA_LogicManager* logicmgr, class KX_Scene* scene, class KX_KetsjiEngine* ketsjiEngine, - int & executePriority, int activeLayerBitInfo, bool isInActiveLayer, class RAS_IRenderTools* rendertools, diff --git a/source/gameengine/Converter/KX_ConvertControllers.cpp b/source/gameengine/Converter/KX_ConvertControllers.cpp index da490b4ee85..85ab8e4f8b8 100644 --- a/source/gameengine/Converter/KX_ConvertControllers.cpp +++ b/source/gameengine/Converter/KX_ConvertControllers.cpp @@ -76,6 +76,7 @@ LinkControllerToActuators( // Iterate through the actuators of the game blender // controller and find the corresponding ketsji actuator. + game_controller->ReserveActuator(bcontr->totlinks); for (int i=0;i<bcontr->totlinks;i++) { bActuator* bact = (bActuator*) bcontr->links[i]; @@ -92,52 +93,54 @@ void BL_ConvertControllers( class KX_GameObject* gameobj, SCA_LogicManager* logicmgr, PyObject* pythondictionary, - int &executePriority, int activeLayerBitInfo, bool isInActiveLayer, KX_BlenderSceneConverter* converter ) { int uniqueint=0; + int count = 0; + int executePriority=0; bController* bcontr = (bController*)blenderobject->controllers.first; while (bcontr) { + bcontr = bcontr->next; + count++; + } + gameobj->ReserveController(count); + bcontr = (bController*)blenderobject->controllers.first; + while (bcontr) + { SCA_IController* gamecontroller = NULL; switch(bcontr->type) { case CONT_LOGIC_AND: { gamecontroller = new SCA_ANDController(gameobj); - LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); break; } case CONT_LOGIC_OR: { gamecontroller = new SCA_ORController(gameobj); - LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); break; } case CONT_LOGIC_NAND: { gamecontroller = new SCA_NANDController(gameobj); - LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); break; } case CONT_LOGIC_NOR: { gamecontroller = new SCA_NORController(gameobj); - LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); break; } case CONT_LOGIC_XOR: { gamecontroller = new SCA_XORController(gameobj); - LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); break; } case CONT_LOGIC_XNOR: { gamecontroller = new SCA_XNORController(gameobj); - LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); break; } case CONT_EXPRESSION: @@ -147,37 +150,43 @@ void BL_ConvertControllers( if (expressiontext.Length() > 0) { gamecontroller = new SCA_ExpressionController(gameobj,expressiontext); - LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); - } break; } case CONT_PYTHON: { - - // we should create a Python controller here - - SCA_PythonController* pyctrl = new SCA_PythonController(gameobj); - gamecontroller = pyctrl; - bPythonCont* pycont = (bPythonCont*) bcontr->data; + SCA_PythonController* pyctrl = new SCA_PythonController(gameobj, pycont->mode); + gamecontroller = pyctrl; + pyctrl->SetDictionary(pythondictionary); - - if (pycont->text) - { - char *buf; - // this is some blender specific code - buf= txt_to_buf(pycont->text); - if (buf) + + if(pycont->mode==SCA_PythonController::SCA_PYEXEC_SCRIPT) { + if (pycont->text) { - pyctrl->SetScriptText(STR_String(buf)); - pyctrl->SetScriptName(pycont->text->id.name+2); - MEM_freeN(buf); + char *buf; + // this is some blender specific code + buf= txt_to_buf(pycont->text); + if (buf) + { + pyctrl->SetScriptText(STR_String(buf)); + pyctrl->SetScriptName(pycont->text->id.name+2); + MEM_freeN(buf); + } + } - } - - LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); + else { + /* let the controller print any warnings here when importing */ + pyctrl->SetScriptText(STR_String(pycont->module)); + pyctrl->SetScriptName(pycont->module); /* will be something like module.func so using it as the name is OK */ + } + + if(pycont->flag & CONT_PY_DEBUG) { + printf("\nDebuging \"%s\", module for object %s\n\texpect worse performance.\n", pycont->module, blenderobject->id.name+2); + pyctrl->SetDebug(true); + } + break; } default: @@ -188,7 +197,9 @@ void BL_ConvertControllers( if (gamecontroller) { + LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); gamecontroller->SetExecutePriority(executePriority++); + gamecontroller->SetBookmark((bcontr->flag & CONT_PRIO) != 0); gamecontroller->SetState(bcontr->state_mask); STR_String uniquename = bcontr->name; uniquename += "#CONTR#"; @@ -200,6 +211,22 @@ void BL_ConvertControllers( gameobj->AddController(gamecontroller); converter->RegisterGameController(gamecontroller, bcontr); + + if (bcontr->type==CONT_PYTHON) { + SCA_PythonController *pyctrl= static_cast<SCA_PythonController*>(gamecontroller); + /* not strictly needed but gives syntax errors early on and + * gives more pradictable performance for larger scripts */ + if(pyctrl->m_mode==SCA_PythonController::SCA_PYEXEC_SCRIPT) + pyctrl->Compile(); + else { + /* We cant do this because importing runs the script which could end up accessing + * internal BGE functions, this is unstable while we're converting the scene. + * This is a pitty because its useful to see errors at startup but cant help it */ + + // pyctrl->Import(); + } + } + //done with gamecontroller gamecontroller->Release(); } diff --git a/source/gameengine/Converter/KX_ConvertControllers.h b/source/gameengine/Converter/KX_ConvertControllers.h index 3e8a87fc90b..d340778290c 100644 --- a/source/gameengine/Converter/KX_ConvertControllers.h +++ b/source/gameengine/Converter/KX_ConvertControllers.h @@ -36,7 +36,6 @@ void BL_ConvertControllers( class KX_GameObject* gameobj, class SCA_LogicManager* logicmgr, PyObject* pythondictionary, - int & executePriority, int activeLayerBitInfo, bool isInActiveLayer, class KX_BlenderSceneConverter* converter diff --git a/source/gameengine/Converter/KX_ConvertProperties.cpp b/source/gameengine/Converter/KX_ConvertProperties.cpp index dfbc6f0c48d..1c22d2a0600 100644 --- a/source/gameengine/Converter/KX_ConvertProperties.cpp +++ b/source/gameengine/Converter/KX_ConvertProperties.cpp @@ -32,26 +32,26 @@ #include <config.h> #endif -/* This little block needed for linking to Blender... */ -#ifdef WIN32 -#include "BLI_winstuff.h" -#endif #include "DNA_object_types.h" #include "DNA_property_types.h" /* end of blender include block */ + #include "Value.h" #include "VectorValue.h" #include "BoolValue.h" #include "StringValue.h" #include "FloatValue.h" #include "KX_GameObject.h" -//#include "ListValue.h" #include "IntValue.h" #include "SCA_TimeEventManager.h" #include "SCA_IScene.h" +/* This little block needed for linking to Blender... */ +#ifdef WIN32 +#include "BLI_winstuff.h" +#endif void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventManager* timemgr,SCA_IScene* scene, bool isInActiveLayer) { @@ -66,58 +66,58 @@ void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventMan show_debug_info = bool (prop->flag & PROP_DEBUG); switch(prop->type) { - case PROP_BOOL: - { - propval = new CBoolValue((bool)(prop->data != 0)); - gameobj->SetProperty(prop->name,propval); - //promp->poin= &prop->data; - break; - } - case PROP_INT: - { - propval = new CIntValue((int)prop->data); - gameobj->SetProperty(prop->name,propval); - break; - } - case PROP_FLOAT: - { - //prop->poin= &prop->data; - float floatprop = *((float*)&prop->data); - propval = new CFloatValue(floatprop); - gameobj->SetProperty(prop->name,propval); - } - break; - case PROP_STRING: - { - //prop->poin= callocN(MAX_PROPSTRING, "property string"); - propval = new CStringValue((char*)prop->poin,""); - gameobj->SetProperty(prop->name,propval); + case GPROP_BOOL: + { + propval = new CBoolValue((bool)(prop->data != 0)); + gameobj->SetProperty(prop->name,propval); + //promp->poin= &prop->data; + break; + } + case GPROP_INT: + { + propval = new CIntValue((int)prop->data); + gameobj->SetProperty(prop->name,propval); + break; + } + case GPROP_FLOAT: + { + //prop->poin= &prop->data; + float floatprop = *((float*)&prop->data); + propval = new CFloatValue(floatprop); + gameobj->SetProperty(prop->name,propval); + } break; - } - case PROP_TIME: - { - float floatprop = *((float*)&prop->data); - - CValue* timeval = new CFloatValue(floatprop); - // set a subproperty called 'timer' so that - // we can register the replica of this property - // at the time a game object is replicated (AddObjectActuator triggers this) - CValue *bval = new CBoolValue(true); - timeval->SetProperty("timer",bval); - bval->Release(); - if (isInActiveLayer) + case GPROP_STRING: { - timemgr->AddTimeProperty(timeval); + //prop->poin= callocN(MAX_PROPSTRING, "property string"); + propval = new CStringValue((char*)prop->poin,""); + gameobj->SetProperty(prop->name,propval); + break; } - - propval = timeval; - gameobj->SetProperty(prop->name,timeval); + case GPROP_TIME: + { + float floatprop = *((float*)&prop->data); - } - default: - { - // todo make an assert etc. - } + CValue* timeval = new CFloatValue(floatprop); + // set a subproperty called 'timer' so that + // we can register the replica of this property + // at the time a game object is replicated (AddObjectActuator triggers this) + CValue *bval = new CBoolValue(true); + timeval->SetProperty("timer",bval); + bval->Release(); + if (isInActiveLayer) + { + timemgr->AddTimeProperty(timeval); + } + + propval = timeval; + gameobj->SetProperty(prop->name,timeval); + + } + default: + { + // todo make an assert etc. + } } if (propval) @@ -129,6 +129,22 @@ void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventMan // done with propval, release it propval->Release(); } + + + /* Warn if we double up on attributes, this isnt quite right since it wont find inherited attributes however there arnt many */ + for(PyAttributeDef *attrdef = KX_GameObject::Attributes; attrdef->m_name; attrdef++) { + if(strcmp(prop->name, attrdef->m_name)==0) { + printf("Warning! user defined property name \"%s\" is also a python attribute for object \"%s\"\n\tUse ob[\"%s\"] syntax to avoid conflict\n", prop->name, object->id.name+2, prop->name); + break; + } + } + for(PyMethodDef *methdef = KX_GameObject::Methods; methdef->ml_name; methdef++) { + if(strcmp(prop->name, methdef->ml_name)==0) { + printf("Warning! user defined property name \"%s\" is also a python method for object \"%s\"\n\tUse ob[\"%s\"] syntax to avoid conflict\n", prop->name, object->id.name+2, prop->name); + break; + } + } + /* end warning check */ prop = prop->next; } diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp index 13b7f43195d..09027f18844 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.cpp +++ b/source/gameengine/Converter/KX_ConvertSensors.cpp @@ -28,6 +28,7 @@ * Conversion of Blender data blocks to KX sensor system */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -36,6 +37,7 @@ #pragma warning (disable : 4786) #endif //WIN32 +#include "wm_event_types.h" #include "KX_BlenderSceneConverter.h" #include "KX_ConvertSensors.h" @@ -93,169 +95,194 @@ void BL_ConvertSensors(struct Object* blenderobject, SCA_LogicManager* logicmgr, KX_Scene* kxscene, KX_KetsjiEngine* kxengine, - SCA_IInputDevice* keydev, - int & executePriority, int activeLayerBitInfo, bool isInActiveLayer, RAS_ICanvas* canvas, KX_BlenderSceneConverter* converter ) { + static bool reverseTableConverted = false; - - - /* The reverse table. In order to not confuse ourselves, we */ - /* immediately convert all events that come in to KX codes. */ - gReverseKeyTranslateTable[LEFTMOUSE ] = SCA_IInputDevice::KX_LEFTMOUSE; - gReverseKeyTranslateTable[MIDDLEMOUSE ] = SCA_IInputDevice::KX_MIDDLEMOUSE; - gReverseKeyTranslateTable[RIGHTMOUSE ] = SCA_IInputDevice::KX_RIGHTMOUSE; - gReverseKeyTranslateTable[WHEELUPMOUSE ] = SCA_IInputDevice::KX_WHEELUPMOUSE; - gReverseKeyTranslateTable[WHEELDOWNMOUSE ] = SCA_IInputDevice::KX_WHEELDOWNMOUSE; - gReverseKeyTranslateTable[MOUSEX ] = SCA_IInputDevice::KX_MOUSEX; - gReverseKeyTranslateTable[MOUSEY ] = SCA_IInputDevice::KX_MOUSEY; - - // TIMERS - - gReverseKeyTranslateTable[TIMER0 ] = SCA_IInputDevice::KX_TIMER0; - gReverseKeyTranslateTable[TIMER1 ] = SCA_IInputDevice::KX_TIMER1; - gReverseKeyTranslateTable[TIMER2 ] = SCA_IInputDevice::KX_TIMER2; - gReverseKeyTranslateTable[TIMER3 ] = SCA_IInputDevice::KX_TIMER3; - - // SYSTEM - - gReverseKeyTranslateTable[KEYBD ] = SCA_IInputDevice::KX_KEYBD; - gReverseKeyTranslateTable[RAWKEYBD ] = SCA_IInputDevice::KX_RAWKEYBD; - gReverseKeyTranslateTable[REDRAW ] = SCA_IInputDevice::KX_REDRAW; - gReverseKeyTranslateTable[INPUTCHANGE ] = SCA_IInputDevice::KX_INPUTCHANGE; - gReverseKeyTranslateTable[QFULL ] = SCA_IInputDevice::KX_QFULL; - gReverseKeyTranslateTable[WINFREEZE ] = SCA_IInputDevice::KX_WINFREEZE; - gReverseKeyTranslateTable[WINTHAW ] = SCA_IInputDevice::KX_WINTHAW; - gReverseKeyTranslateTable[WINCLOSE ] = SCA_IInputDevice::KX_WINCLOSE; - gReverseKeyTranslateTable[WINQUIT ] = SCA_IInputDevice::KX_WINQUIT; - gReverseKeyTranslateTable[Q_FIRSTTIME ] = SCA_IInputDevice::KX_Q_FIRSTTIME; - - // standard keyboard - - gReverseKeyTranslateTable[AKEY ] = SCA_IInputDevice::KX_AKEY; - gReverseKeyTranslateTable[BKEY ] = SCA_IInputDevice::KX_BKEY; - gReverseKeyTranslateTable[CKEY ] = SCA_IInputDevice::KX_CKEY; - gReverseKeyTranslateTable[DKEY ] = SCA_IInputDevice::KX_DKEY; - gReverseKeyTranslateTable[EKEY ] = SCA_IInputDevice::KX_EKEY; - gReverseKeyTranslateTable[FKEY ] = SCA_IInputDevice::KX_FKEY; - gReverseKeyTranslateTable[GKEY ] = SCA_IInputDevice::KX_GKEY; - gReverseKeyTranslateTable[HKEY ] = SCA_IInputDevice::KX_HKEY; - gReverseKeyTranslateTable[IKEY ] = SCA_IInputDevice::KX_IKEY; - gReverseKeyTranslateTable[JKEY ] = SCA_IInputDevice::KX_JKEY; - gReverseKeyTranslateTable[KKEY ] = SCA_IInputDevice::KX_KKEY; - gReverseKeyTranslateTable[LKEY ] = SCA_IInputDevice::KX_LKEY; - gReverseKeyTranslateTable[MKEY ] = SCA_IInputDevice::KX_MKEY; - gReverseKeyTranslateTable[NKEY ] = SCA_IInputDevice::KX_NKEY; - gReverseKeyTranslateTable[OKEY ] = SCA_IInputDevice::KX_OKEY; - gReverseKeyTranslateTable[PKEY ] = SCA_IInputDevice::KX_PKEY; - gReverseKeyTranslateTable[QKEY ] = SCA_IInputDevice::KX_QKEY; - gReverseKeyTranslateTable[RKEY ] = SCA_IInputDevice::KX_RKEY; - gReverseKeyTranslateTable[SKEY ] = SCA_IInputDevice::KX_SKEY; - gReverseKeyTranslateTable[TKEY ] = SCA_IInputDevice::KX_TKEY; - gReverseKeyTranslateTable[UKEY ] = SCA_IInputDevice::KX_UKEY; - gReverseKeyTranslateTable[VKEY ] = SCA_IInputDevice::KX_VKEY; - gReverseKeyTranslateTable[WKEY ] = SCA_IInputDevice::KX_WKEY; - gReverseKeyTranslateTable[XKEY ] = SCA_IInputDevice::KX_XKEY; - gReverseKeyTranslateTable[YKEY ] = SCA_IInputDevice::KX_YKEY; - gReverseKeyTranslateTable[ZKEY ] = SCA_IInputDevice::KX_ZKEY; - - gReverseKeyTranslateTable[ZEROKEY ] = SCA_IInputDevice::KX_ZEROKEY; - gReverseKeyTranslateTable[ONEKEY ] = SCA_IInputDevice::KX_ONEKEY; - gReverseKeyTranslateTable[TWOKEY ] = SCA_IInputDevice::KX_TWOKEY; - gReverseKeyTranslateTable[THREEKEY ] = SCA_IInputDevice::KX_THREEKEY; - gReverseKeyTranslateTable[FOURKEY ] = SCA_IInputDevice::KX_FOURKEY; - gReverseKeyTranslateTable[FIVEKEY ] = SCA_IInputDevice::KX_FIVEKEY; - gReverseKeyTranslateTable[SIXKEY ] = SCA_IInputDevice::KX_SIXKEY; - gReverseKeyTranslateTable[SEVENKEY ] = SCA_IInputDevice::KX_SEVENKEY; - gReverseKeyTranslateTable[EIGHTKEY ] = SCA_IInputDevice::KX_EIGHTKEY; - gReverseKeyTranslateTable[NINEKEY ] = SCA_IInputDevice::KX_NINEKEY; - - gReverseKeyTranslateTable[CAPSLOCKKEY ] = SCA_IInputDevice::KX_CAPSLOCKKEY; - - gReverseKeyTranslateTable[LEFTCTRLKEY ] = SCA_IInputDevice::KX_LEFTCTRLKEY; - gReverseKeyTranslateTable[LEFTALTKEY ] = SCA_IInputDevice::KX_LEFTALTKEY; - gReverseKeyTranslateTable[RIGHTALTKEY ] = SCA_IInputDevice::KX_RIGHTALTKEY; - gReverseKeyTranslateTable[RIGHTCTRLKEY ] = SCA_IInputDevice::KX_RIGHTCTRLKEY; - gReverseKeyTranslateTable[RIGHTSHIFTKEY ] = SCA_IInputDevice::KX_RIGHTSHIFTKEY; - gReverseKeyTranslateTable[LEFTSHIFTKEY ] = SCA_IInputDevice::KX_LEFTSHIFTKEY; - - gReverseKeyTranslateTable[ESCKEY ] = SCA_IInputDevice::KX_ESCKEY; - gReverseKeyTranslateTable[TABKEY ] = SCA_IInputDevice::KX_TABKEY; - gReverseKeyTranslateTable[RETKEY ] = SCA_IInputDevice::KX_RETKEY; - gReverseKeyTranslateTable[SPACEKEY ] = SCA_IInputDevice::KX_SPACEKEY; - gReverseKeyTranslateTable[LINEFEEDKEY ] = SCA_IInputDevice::KX_LINEFEEDKEY; - gReverseKeyTranslateTable[BACKSPACEKEY ] = SCA_IInputDevice::KX_BACKSPACEKEY; - gReverseKeyTranslateTable[DELKEY ] = SCA_IInputDevice::KX_DELKEY; - gReverseKeyTranslateTable[SEMICOLONKEY ] = SCA_IInputDevice::KX_SEMICOLONKEY; - gReverseKeyTranslateTable[PERIODKEY ] = SCA_IInputDevice::KX_PERIODKEY; - gReverseKeyTranslateTable[COMMAKEY ] = SCA_IInputDevice::KX_COMMAKEY; - gReverseKeyTranslateTable[QUOTEKEY ] = SCA_IInputDevice::KX_QUOTEKEY; - gReverseKeyTranslateTable[ACCENTGRAVEKEY ] = SCA_IInputDevice::KX_ACCENTGRAVEKEY; - gReverseKeyTranslateTable[MINUSKEY ] = SCA_IInputDevice::KX_MINUSKEY; - gReverseKeyTranslateTable[SLASHKEY ] = SCA_IInputDevice::KX_SLASHKEY; - gReverseKeyTranslateTable[BACKSLASHKEY ] = SCA_IInputDevice::KX_BACKSLASHKEY; - gReverseKeyTranslateTable[EQUALKEY ] = SCA_IInputDevice::KX_EQUALKEY; - gReverseKeyTranslateTable[LEFTBRACKETKEY ] = SCA_IInputDevice::KX_LEFTBRACKETKEY; - gReverseKeyTranslateTable[RIGHTBRACKETKEY ] = SCA_IInputDevice::KX_RIGHTBRACKETKEY; - - gReverseKeyTranslateTable[LEFTARROWKEY ] = SCA_IInputDevice::KX_LEFTARROWKEY; - gReverseKeyTranslateTable[DOWNARROWKEY ] = SCA_IInputDevice::KX_DOWNARROWKEY; - gReverseKeyTranslateTable[RIGHTARROWKEY ] = SCA_IInputDevice::KX_RIGHTARROWKEY; - gReverseKeyTranslateTable[UPARROWKEY ] = SCA_IInputDevice::KX_UPARROWKEY; - - gReverseKeyTranslateTable[PAD2 ] = SCA_IInputDevice::KX_PAD2; - gReverseKeyTranslateTable[PAD4 ] = SCA_IInputDevice::KX_PAD4; - gReverseKeyTranslateTable[PAD6 ] = SCA_IInputDevice::KX_PAD6; - gReverseKeyTranslateTable[PAD8 ] = SCA_IInputDevice::KX_PAD8; - - gReverseKeyTranslateTable[PAD1 ] = SCA_IInputDevice::KX_PAD1; - gReverseKeyTranslateTable[PAD3 ] = SCA_IInputDevice::KX_PAD3; - gReverseKeyTranslateTable[PAD5 ] = SCA_IInputDevice::KX_PAD5; - gReverseKeyTranslateTable[PAD7 ] = SCA_IInputDevice::KX_PAD7; - gReverseKeyTranslateTable[PAD9 ] = SCA_IInputDevice::KX_PAD9; - - gReverseKeyTranslateTable[PADPERIOD ] = SCA_IInputDevice::KX_PADPERIOD; - gReverseKeyTranslateTable[PADSLASHKEY ] = SCA_IInputDevice::KX_PADSLASHKEY; - gReverseKeyTranslateTable[PADASTERKEY ] = SCA_IInputDevice::KX_PADASTERKEY; - - gReverseKeyTranslateTable[PAD0 ] = SCA_IInputDevice::KX_PAD0; - gReverseKeyTranslateTable[PADMINUS ] = SCA_IInputDevice::KX_PADMINUS; - gReverseKeyTranslateTable[PADENTER ] = SCA_IInputDevice::KX_PADENTER; - gReverseKeyTranslateTable[PADPLUSKEY ] = SCA_IInputDevice::KX_PADPLUSKEY; - - - gReverseKeyTranslateTable[F1KEY ] = SCA_IInputDevice::KX_F1KEY; - gReverseKeyTranslateTable[F2KEY ] = SCA_IInputDevice::KX_F2KEY; - gReverseKeyTranslateTable[F3KEY ] = SCA_IInputDevice::KX_F3KEY; - gReverseKeyTranslateTable[F4KEY ] = SCA_IInputDevice::KX_F4KEY; - gReverseKeyTranslateTable[F5KEY ] = SCA_IInputDevice::KX_F5KEY; - gReverseKeyTranslateTable[F6KEY ] = SCA_IInputDevice::KX_F6KEY; - gReverseKeyTranslateTable[F7KEY ] = SCA_IInputDevice::KX_F7KEY; - gReverseKeyTranslateTable[F8KEY ] = SCA_IInputDevice::KX_F8KEY; - gReverseKeyTranslateTable[F9KEY ] = SCA_IInputDevice::KX_F9KEY; - gReverseKeyTranslateTable[F10KEY ] = SCA_IInputDevice::KX_F10KEY; - gReverseKeyTranslateTable[F11KEY ] = SCA_IInputDevice::KX_F11KEY; - gReverseKeyTranslateTable[F12KEY ] = SCA_IInputDevice::KX_F12KEY; - - gReverseKeyTranslateTable[PAUSEKEY ] = SCA_IInputDevice::KX_PAUSEKEY; - gReverseKeyTranslateTable[INSERTKEY ] = SCA_IInputDevice::KX_INSERTKEY; - gReverseKeyTranslateTable[HOMEKEY ] = SCA_IInputDevice::KX_HOMEKEY; - gReverseKeyTranslateTable[PAGEUPKEY ] = SCA_IInputDevice::KX_PAGEUPKEY; - gReverseKeyTranslateTable[PAGEDOWNKEY ] = SCA_IInputDevice::KX_PAGEDOWNKEY; - gReverseKeyTranslateTable[ENDKEY ] = SCA_IInputDevice::KX_ENDKEY; - + if (!reverseTableConverted) + { + reverseTableConverted = true; + + /* The reverse table. In order to not confuse ourselves, we */ + /* immediately convert all events that come in to KX codes. */ + gReverseKeyTranslateTable[LEFTMOUSE ] = SCA_IInputDevice::KX_LEFTMOUSE; + gReverseKeyTranslateTable[MIDDLEMOUSE ] = SCA_IInputDevice::KX_MIDDLEMOUSE; + gReverseKeyTranslateTable[RIGHTMOUSE ] = SCA_IInputDevice::KX_RIGHTMOUSE; + gReverseKeyTranslateTable[WHEELUPMOUSE ] = SCA_IInputDevice::KX_WHEELUPMOUSE; + gReverseKeyTranslateTable[WHEELDOWNMOUSE ] = SCA_IInputDevice::KX_WHEELDOWNMOUSE; + gReverseKeyTranslateTable[MOUSEX ] = SCA_IInputDevice::KX_MOUSEX; + gReverseKeyTranslateTable[MOUSEY ] = SCA_IInputDevice::KX_MOUSEY; + + // TIMERS + + gReverseKeyTranslateTable[TIMER0 ] = SCA_IInputDevice::KX_TIMER0; + gReverseKeyTranslateTable[TIMER1 ] = SCA_IInputDevice::KX_TIMER1; + gReverseKeyTranslateTable[TIMER2 ] = SCA_IInputDevice::KX_TIMER2; + + // SYSTEM + +#if 0 + /* **** XXX **** */ + gReverseKeyTranslateTable[KEYBD ] = SCA_IInputDevice::KX_KEYBD; + gReverseKeyTranslateTable[RAWKEYBD ] = SCA_IInputDevice::KX_RAWKEYBD; + gReverseKeyTranslateTable[REDRAW ] = SCA_IInputDevice::KX_REDRAW; + gReverseKeyTranslateTable[INPUTCHANGE ] = SCA_IInputDevice::KX_INPUTCHANGE; + gReverseKeyTranslateTable[QFULL ] = SCA_IInputDevice::KX_QFULL; + gReverseKeyTranslateTable[WINFREEZE ] = SCA_IInputDevice::KX_WINFREEZE; + gReverseKeyTranslateTable[WINTHAW ] = SCA_IInputDevice::KX_WINTHAW; + gReverseKeyTranslateTable[WINCLOSE ] = SCA_IInputDevice::KX_WINCLOSE; + gReverseKeyTranslateTable[WINQUIT ] = SCA_IInputDevice::KX_WINQUIT; + gReverseKeyTranslateTable[Q_FIRSTTIME ] = SCA_IInputDevice::KX_Q_FIRSTTIME; + /* **** XXX **** */ +#endif + + // standard keyboard + + gReverseKeyTranslateTable[AKEY ] = SCA_IInputDevice::KX_AKEY; + gReverseKeyTranslateTable[BKEY ] = SCA_IInputDevice::KX_BKEY; + gReverseKeyTranslateTable[CKEY ] = SCA_IInputDevice::KX_CKEY; + gReverseKeyTranslateTable[DKEY ] = SCA_IInputDevice::KX_DKEY; + gReverseKeyTranslateTable[EKEY ] = SCA_IInputDevice::KX_EKEY; + gReverseKeyTranslateTable[FKEY ] = SCA_IInputDevice::KX_FKEY; + gReverseKeyTranslateTable[GKEY ] = SCA_IInputDevice::KX_GKEY; + +//XXX clean up +#ifdef WIN32 +#define HKEY 'h' +#endif + gReverseKeyTranslateTable[HKEY ] = SCA_IInputDevice::KX_HKEY; +//XXX clean up +#ifdef WIN32 +#undef HKEY +#endif + + gReverseKeyTranslateTable[IKEY ] = SCA_IInputDevice::KX_IKEY; + gReverseKeyTranslateTable[JKEY ] = SCA_IInputDevice::KX_JKEY; + gReverseKeyTranslateTable[KKEY ] = SCA_IInputDevice::KX_KKEY; + gReverseKeyTranslateTable[LKEY ] = SCA_IInputDevice::KX_LKEY; + gReverseKeyTranslateTable[MKEY ] = SCA_IInputDevice::KX_MKEY; + gReverseKeyTranslateTable[NKEY ] = SCA_IInputDevice::KX_NKEY; + gReverseKeyTranslateTable[OKEY ] = SCA_IInputDevice::KX_OKEY; + gReverseKeyTranslateTable[PKEY ] = SCA_IInputDevice::KX_PKEY; + gReverseKeyTranslateTable[QKEY ] = SCA_IInputDevice::KX_QKEY; + gReverseKeyTranslateTable[RKEY ] = SCA_IInputDevice::KX_RKEY; + gReverseKeyTranslateTable[SKEY ] = SCA_IInputDevice::KX_SKEY; + gReverseKeyTranslateTable[TKEY ] = SCA_IInputDevice::KX_TKEY; + gReverseKeyTranslateTable[UKEY ] = SCA_IInputDevice::KX_UKEY; + gReverseKeyTranslateTable[VKEY ] = SCA_IInputDevice::KX_VKEY; + gReverseKeyTranslateTable[WKEY ] = SCA_IInputDevice::KX_WKEY; + gReverseKeyTranslateTable[XKEY ] = SCA_IInputDevice::KX_XKEY; + gReverseKeyTranslateTable[YKEY ] = SCA_IInputDevice::KX_YKEY; + gReverseKeyTranslateTable[ZKEY ] = SCA_IInputDevice::KX_ZKEY; + + gReverseKeyTranslateTable[ZEROKEY ] = SCA_IInputDevice::KX_ZEROKEY; + gReverseKeyTranslateTable[ONEKEY ] = SCA_IInputDevice::KX_ONEKEY; + gReverseKeyTranslateTable[TWOKEY ] = SCA_IInputDevice::KX_TWOKEY; + gReverseKeyTranslateTable[THREEKEY ] = SCA_IInputDevice::KX_THREEKEY; + gReverseKeyTranslateTable[FOURKEY ] = SCA_IInputDevice::KX_FOURKEY; + gReverseKeyTranslateTable[FIVEKEY ] = SCA_IInputDevice::KX_FIVEKEY; + gReverseKeyTranslateTable[SIXKEY ] = SCA_IInputDevice::KX_SIXKEY; + gReverseKeyTranslateTable[SEVENKEY ] = SCA_IInputDevice::KX_SEVENKEY; + gReverseKeyTranslateTable[EIGHTKEY ] = SCA_IInputDevice::KX_EIGHTKEY; + gReverseKeyTranslateTable[NINEKEY ] = SCA_IInputDevice::KX_NINEKEY; + + gReverseKeyTranslateTable[CAPSLOCKKEY ] = SCA_IInputDevice::KX_CAPSLOCKKEY; + + gReverseKeyTranslateTable[LEFTCTRLKEY ] = SCA_IInputDevice::KX_LEFTCTRLKEY; + gReverseKeyTranslateTable[LEFTALTKEY ] = SCA_IInputDevice::KX_LEFTALTKEY; + gReverseKeyTranslateTable[RIGHTALTKEY ] = SCA_IInputDevice::KX_RIGHTALTKEY; + gReverseKeyTranslateTable[RIGHTCTRLKEY ] = SCA_IInputDevice::KX_RIGHTCTRLKEY; + gReverseKeyTranslateTable[RIGHTSHIFTKEY ] = SCA_IInputDevice::KX_RIGHTSHIFTKEY; + gReverseKeyTranslateTable[LEFTSHIFTKEY ] = SCA_IInputDevice::KX_LEFTSHIFTKEY; + + gReverseKeyTranslateTable[ESCKEY ] = SCA_IInputDevice::KX_ESCKEY; + gReverseKeyTranslateTable[TABKEY ] = SCA_IInputDevice::KX_TABKEY; + gReverseKeyTranslateTable[RETKEY ] = SCA_IInputDevice::KX_RETKEY; + gReverseKeyTranslateTable[SPACEKEY ] = SCA_IInputDevice::KX_SPACEKEY; + gReverseKeyTranslateTable[LINEFEEDKEY ] = SCA_IInputDevice::KX_LINEFEEDKEY; + gReverseKeyTranslateTable[BACKSPACEKEY ] = SCA_IInputDevice::KX_BACKSPACEKEY; + gReverseKeyTranslateTable[DELKEY ] = SCA_IInputDevice::KX_DELKEY; + gReverseKeyTranslateTable[SEMICOLONKEY ] = SCA_IInputDevice::KX_SEMICOLONKEY; + gReverseKeyTranslateTable[PERIODKEY ] = SCA_IInputDevice::KX_PERIODKEY; + gReverseKeyTranslateTable[COMMAKEY ] = SCA_IInputDevice::KX_COMMAKEY; + gReverseKeyTranslateTable[QUOTEKEY ] = SCA_IInputDevice::KX_QUOTEKEY; + gReverseKeyTranslateTable[ACCENTGRAVEKEY ] = SCA_IInputDevice::KX_ACCENTGRAVEKEY; + gReverseKeyTranslateTable[MINUSKEY ] = SCA_IInputDevice::KX_MINUSKEY; + gReverseKeyTranslateTable[SLASHKEY ] = SCA_IInputDevice::KX_SLASHKEY; + gReverseKeyTranslateTable[BACKSLASHKEY ] = SCA_IInputDevice::KX_BACKSLASHKEY; + gReverseKeyTranslateTable[EQUALKEY ] = SCA_IInputDevice::KX_EQUALKEY; + gReverseKeyTranslateTable[LEFTBRACKETKEY ] = SCA_IInputDevice::KX_LEFTBRACKETKEY; + gReverseKeyTranslateTable[RIGHTBRACKETKEY ] = SCA_IInputDevice::KX_RIGHTBRACKETKEY; + + gReverseKeyTranslateTable[LEFTARROWKEY ] = SCA_IInputDevice::KX_LEFTARROWKEY; + gReverseKeyTranslateTable[DOWNARROWKEY ] = SCA_IInputDevice::KX_DOWNARROWKEY; + gReverseKeyTranslateTable[RIGHTARROWKEY ] = SCA_IInputDevice::KX_RIGHTARROWKEY; + gReverseKeyTranslateTable[UPARROWKEY ] = SCA_IInputDevice::KX_UPARROWKEY; + + gReverseKeyTranslateTable[PAD2 ] = SCA_IInputDevice::KX_PAD2; + gReverseKeyTranslateTable[PAD4 ] = SCA_IInputDevice::KX_PAD4; + gReverseKeyTranslateTable[PAD6 ] = SCA_IInputDevice::KX_PAD6; + gReverseKeyTranslateTable[PAD8 ] = SCA_IInputDevice::KX_PAD8; + + gReverseKeyTranslateTable[PAD1 ] = SCA_IInputDevice::KX_PAD1; + gReverseKeyTranslateTable[PAD3 ] = SCA_IInputDevice::KX_PAD3; + gReverseKeyTranslateTable[PAD5 ] = SCA_IInputDevice::KX_PAD5; + gReverseKeyTranslateTable[PAD7 ] = SCA_IInputDevice::KX_PAD7; + gReverseKeyTranslateTable[PAD9 ] = SCA_IInputDevice::KX_PAD9; + + gReverseKeyTranslateTable[PADPERIOD ] = SCA_IInputDevice::KX_PADPERIOD; + gReverseKeyTranslateTable[PADSLASHKEY ] = SCA_IInputDevice::KX_PADSLASHKEY; + gReverseKeyTranslateTable[PADASTERKEY ] = SCA_IInputDevice::KX_PADASTERKEY; + + gReverseKeyTranslateTable[PAD0 ] = SCA_IInputDevice::KX_PAD0; + gReverseKeyTranslateTable[PADMINUS ] = SCA_IInputDevice::KX_PADMINUS; + gReverseKeyTranslateTable[PADENTER ] = SCA_IInputDevice::KX_PADENTER; + gReverseKeyTranslateTable[PADPLUSKEY ] = SCA_IInputDevice::KX_PADPLUSKEY; + + + gReverseKeyTranslateTable[F1KEY ] = SCA_IInputDevice::KX_F1KEY; + gReverseKeyTranslateTable[F2KEY ] = SCA_IInputDevice::KX_F2KEY; + gReverseKeyTranslateTable[F3KEY ] = SCA_IInputDevice::KX_F3KEY; + gReverseKeyTranslateTable[F4KEY ] = SCA_IInputDevice::KX_F4KEY; + gReverseKeyTranslateTable[F5KEY ] = SCA_IInputDevice::KX_F5KEY; + gReverseKeyTranslateTable[F6KEY ] = SCA_IInputDevice::KX_F6KEY; + gReverseKeyTranslateTable[F7KEY ] = SCA_IInputDevice::KX_F7KEY; + gReverseKeyTranslateTable[F8KEY ] = SCA_IInputDevice::KX_F8KEY; + gReverseKeyTranslateTable[F9KEY ] = SCA_IInputDevice::KX_F9KEY; + gReverseKeyTranslateTable[F10KEY ] = SCA_IInputDevice::KX_F10KEY; + gReverseKeyTranslateTable[F11KEY ] = SCA_IInputDevice::KX_F11KEY; + gReverseKeyTranslateTable[F12KEY ] = SCA_IInputDevice::KX_F12KEY; + + gReverseKeyTranslateTable[PAUSEKEY ] = SCA_IInputDevice::KX_PAUSEKEY; + gReverseKeyTranslateTable[INSERTKEY ] = SCA_IInputDevice::KX_INSERTKEY; + gReverseKeyTranslateTable[HOMEKEY ] = SCA_IInputDevice::KX_HOMEKEY; + gReverseKeyTranslateTable[PAGEUPKEY ] = SCA_IInputDevice::KX_PAGEUPKEY; + gReverseKeyTranslateTable[PAGEDOWNKEY ] = SCA_IInputDevice::KX_PAGEDOWNKEY; + gReverseKeyTranslateTable[ENDKEY ] = SCA_IInputDevice::KX_ENDKEY; + } + + int executePriority = 0; int uniqueint = 0; + int count = 0; bSensor* sens = (bSensor*)blenderobject->sensors.first; bool pos_pulsemode = false; bool neg_pulsemode = false; int frequency = 0; bool invert = false; bool level = false; + bool tap = false; + while (sens) + { + sens = sens->next; + count++; + } + gameobj->ReserveSensor(count); + sens = (bSensor*)blenderobject->sensors.first; while(sens) { SCA_ISensor* gamesensor=NULL; @@ -268,6 +295,7 @@ void BL_ConvertSensors(struct Object* blenderobject, frequency = sens->freq; invert = !(sens->invert == 0); level = !(sens->level == 0); + tap = !(sens->tap == 0); switch (sens->type) { @@ -306,12 +334,12 @@ void BL_ConvertSensors(struct Object* blenderobject, { // collision sensor can sense both materials and properties. - bool bFindMaterial = false; + bool bFindMaterial = false, bTouchPulse = false; bCollisionSensor* blendertouchsensor = (bCollisionSensor*)sens->data; - bFindMaterial = (blendertouchsensor->mode - & SENS_COLLISION_MATERIAL); + bFindMaterial = (blendertouchsensor->mode & SENS_COLLISION_MATERIAL); + bTouchPulse = (blendertouchsensor->mode & SENS_COLLISION_PULSE); STR_String touchPropOrMatName = ( bFindMaterial ? @@ -324,6 +352,7 @@ void BL_ConvertSensors(struct Object* blenderobject, gamesensor = new KX_TouchSensor(eventmgr, gameobj, bFindMaterial, + bTouchPulse, touchPropOrMatName); } @@ -349,6 +378,7 @@ void BL_ConvertSensors(struct Object* blenderobject, gamesensor = new KX_TouchSensor(eventmgr, gameobj, bFindMaterial, + false, touchpropertyname); } } @@ -414,9 +444,8 @@ void BL_ConvertSensors(struct Object* blenderobject, blendernearsensor->dist, blendernearsensor->resetdist, bFindMaterial, - nearpropertyname,kxscene, - physCtrl - ); + nearpropertyname, + physCtrl); } break; @@ -507,7 +536,7 @@ void BL_ConvertSensors(struct Object* blenderobject, starty, keytype, trackfocus, - canvas, + (bmouse->flag & SENS_MOUSE_FOCUS_PULSE) ? true:false, kxscene, kxengine, gameobj); @@ -619,8 +648,7 @@ void BL_ConvertSensors(struct Object* blenderobject, smallmargin, largemargin, bFindMaterial, - radarpropertyname, - kxscene); + radarpropertyname); } @@ -667,6 +695,11 @@ void BL_ConvertSensors(struct Object* blenderobject, if (eventmgr) { int randomSeed = blenderrndsensor->seed; + if (randomSeed == 0) + { + randomSeed = (int)(kxengine->GetRealTime()*100000.0); + randomSeed ^= (intptr_t)blenderrndsensor; + } gamesensor = new SCA_RandomSensor(eventmgr, gameobj, randomSeed); } } @@ -706,6 +739,11 @@ void BL_ConvertSensors(struct Object* blenderobject, hatf = bjoy->hatf; joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_HAT; break; + case SENS_JOY_AXIS_SINGLE: + axis = bjoy->axis_single; + prec = bjoy->precision; + joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_AXIS_SINGLE; + break; default: printf("Error: bad case statement\n"); break; @@ -749,7 +787,8 @@ void BL_ConvertSensors(struct Object* blenderobject, frequency); gamesensor->SetInvert(invert); gamesensor->SetLevel(level); - gamesensor->SetName(STR_String(sens->name)); + gamesensor->SetTap(tap); + gamesensor->SetName(sens->name); gameobj->AddSensor(gamesensor); @@ -758,7 +797,7 @@ void BL_ConvertSensors(struct Object* blenderobject, //if (isInActiveLayer) // gamesensor->RegisterToManager(); - + gamesensor->ReserveController(sens->totlinks); for (int i=0;i<sens->totlinks;i++) { bController* linkedcont = (bController*) sens->links[i]; diff --git a/source/gameengine/Converter/KX_ConvertSensors.h b/source/gameengine/Converter/KX_ConvertSensors.h index b18ffc10a2a..630323f30b4 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.h +++ b/source/gameengine/Converter/KX_ConvertSensors.h @@ -34,8 +34,6 @@ void BL_ConvertSensors(struct Object* blenderobject, class SCA_LogicManager* logicmgr, class KX_Scene* kxscene, class KX_KetsjiEngine* kxengine, - class SCA_IInputDevice* keydev, - int & executePriority , int activeLayerBitInfo, bool isInActiveLayer, class RAS_ICanvas* canvas, diff --git a/source/gameengine/Converter/KX_IpoConvert.cpp b/source/gameengine/Converter/KX_IpoConvert.cpp index ce004fa0504..848fcfcdaa0 100644 --- a/source/gameengine/Converter/KX_IpoConvert.cpp +++ b/source/gameengine/Converter/KX_IpoConvert.cpp @@ -71,20 +71,20 @@ #include "STR_HashedString.h" -static BL_InterpolatorList *GetIpoList(struct Ipo *for_ipo, KX_BlenderSceneConverter *converter) { - BL_InterpolatorList *ipoList= converter->FindInterpolatorList(for_ipo); +static BL_InterpolatorList *GetAdtList(struct AnimData *for_adt, KX_BlenderSceneConverter *converter) { + BL_InterpolatorList *adtList= converter->FindInterpolatorList(for_adt); - if (!ipoList) { - ipoList = new BL_InterpolatorList(for_ipo); - converter->RegisterInterpolatorList(ipoList, for_ipo); + if (!adtList) { + adtList = new BL_InterpolatorList(for_adt); + converter->RegisterInterpolatorList(adtList, for_adt); } - return ipoList; + return adtList; } void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_BlenderSceneConverter *converter) { - if (blenderobject->ipo) { + if (blenderobject->adt) { KX_IpoSGController* ipocontr = new KX_IpoSGController(); gameobj->GetSGNode()->AddSGController(ipocontr); @@ -120,271 +120,79 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend ) ); - BL_InterpolatorList *ipoList= GetIpoList(blenderobject->ipo, converter); + BL_InterpolatorList *adtList= GetAdtList(blenderobject->adt, converter); - // For each active channel in the ipoList add an + // For each active channel in the adtList add an // interpolator to the game object. - KX_IScalarInterpolator *ipo; + KX_IInterpolator *interpolator; + KX_IScalarInterpolator *interp; - ipo = ipoList->GetScalarInterpolator(OB_LOC_X); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetPosition()[0]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_LOC_X, true); - - } - - ipo = ipoList->GetScalarInterpolator(OB_LOC_Y); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetPosition()[1]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_LOC_Y, true); - } - - ipo = ipoList->GetScalarInterpolator(OB_LOC_Z); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetPosition()[2]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_LOC_Z, true); - } - - // Master the art of cut & paste programming... - - ipo = ipoList->GetScalarInterpolator(OB_DLOC_X); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetDeltaPosition()[0]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DLOC_X, true); - } - - ipo = ipoList->GetScalarInterpolator(OB_DLOC_Y); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetDeltaPosition()[1]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DLOC_Y, true); - } - - ipo = ipoList->GetScalarInterpolator(OB_DLOC_Z); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetDeltaPosition()[2]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DLOC_Z, true); - } - - // Explore the finesse of reuse and slight modification - - ipo = ipoList->GetScalarInterpolator(OB_ROT_X); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetEulerAngles()[0]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_ROT_X, true); - } - ipo = ipoList->GetScalarInterpolator(OB_ROT_Y); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetEulerAngles()[1]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_ROT_Y, true); - } - ipo = ipoList->GetScalarInterpolator(OB_ROT_Z); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetEulerAngles()[2]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_ROT_Z, true); - } - - // Hmmm, the need for a macro comes to mind... - - ipo = ipoList->GetScalarInterpolator(OB_DROT_X); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[0]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DROT_X, true); - } - ipo = ipoList->GetScalarInterpolator(OB_DROT_Y); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[1]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DROT_Y, true); - } - ipo = ipoList->GetScalarInterpolator(OB_DROT_Z); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[2]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DROT_Z, true); - } - - // Hang on, almost there... - - ipo = ipoList->GetScalarInterpolator(OB_SIZE_X); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetScaling()[0]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_SIZE_X, true); - } - ipo = ipoList->GetScalarInterpolator(OB_SIZE_Y); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetScaling()[1]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_SIZE_Y, true); - } - ipo = ipoList->GetScalarInterpolator(OB_SIZE_Z); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetScaling()[2]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_SIZE_Z, true); - } - - // The last few... - - ipo = ipoList->GetScalarInterpolator(OB_DSIZE_X); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetDeltaScaling()[0]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DSIZE_X, true); - } - ipo = ipoList->GetScalarInterpolator(OB_DSIZE_Y); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetDeltaScaling()[1]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DSIZE_Y, true); + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("location", i))) { + interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetPosition()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_LOC_X+i, true); + } } - ipo = ipoList->GetScalarInterpolator(OB_DSIZE_Z); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &(ipocontr->GetIPOTransform().GetDeltaScaling()[2]), - ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DSIZE_Z, true); + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("delta_location", i))) { + interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaPosition()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_DLOC_X+i, true); + } } - - { - KX_ObColorIpoSGController* ipocontr=NULL; - - ipo = ipoList->GetScalarInterpolator(OB_COL_R); - if (ipo) - { - if (!ipocontr) - { - ipocontr = new KX_ObColorIpoSGController(); - gameobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(gameobj->GetSGNode()); - } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_rgba[0], - ipo); + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("rotation", i))) { + interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetEulerAngles()[i]), interp); ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_ROT_X+i, true); } - ipo = ipoList->GetScalarInterpolator(OB_COL_G); - if (ipo) - { - if (!ipocontr) - { - ipocontr = new KX_ObColorIpoSGController(); - gameobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(gameobj->GetSGNode()); - } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_rgba[1], - ipo); + } + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("delta_rotation", i))) { + interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[i]), interp); ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_DROT_X+i, true); } - ipo = ipoList->GetScalarInterpolator(OB_COL_B); - if (ipo) - { - if (!ipocontr) - { - ipocontr = new KX_ObColorIpoSGController(); - gameobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(gameobj->GetSGNode()); - } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_rgba[2], - ipo); + } + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("scale", i))) { + interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetScaling()[i]), interp); ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_SIZE_X+i, true); } - ipo = ipoList->GetScalarInterpolator(OB_COL_A); - if (ipo) - { - if (!ipocontr) - { - ipocontr = new KX_ObColorIpoSGController(); - gameobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(gameobj->GetSGNode()); - } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_rgba[3], - ipo); + } + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("delta_scale", i))) { + interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaScaling()[i]), interp); ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_DSIZE_X+i, true); } } - + { + KX_ObColorIpoSGController* ipocontr_obcol=NULL; + + for(int i=0; i<4; i++) { + if ((interp = adtList->GetScalarInterpolator("color", i))) { + if (!ipocontr_obcol) { + ipocontr_obcol = new KX_ObColorIpoSGController(); + gameobj->GetSGNode()->AddSGController(ipocontr_obcol); + ipocontr_obcol->SetObject(gameobj->GetSGNode()); + } + interpolator= new KX_ScalarInterpolator(&ipocontr_obcol->m_rgba[i], interp); + ipocontr_obcol->AddInterpolator(interpolator); + } + } + } } - - } void BL_ConvertLampIpos(struct Lamp* blenderlamp, KX_GameObject *lightobj,KX_BlenderSceneConverter *converter) { - if (blenderlamp->ipo) { + if (blenderlamp->adt) { KX_LightIpoSGController* ipocontr = new KX_LightIpoSGController(); lightobj->GetSGNode()->AddSGController(ipocontr); @@ -396,51 +204,32 @@ void BL_ConvertLampIpos(struct Lamp* blenderlamp, KX_GameObject *lightobj,KX_Ble ipocontr->m_col_rgb[2] = blenderlamp->b; ipocontr->m_dist = blenderlamp->dist; - BL_InterpolatorList *ipoList= GetIpoList(blenderlamp->ipo, converter); + BL_InterpolatorList *adtList= GetAdtList(blenderlamp->adt, converter); - // For each active channel in the ipoList add an + // For each active channel in the adtList add an // interpolator to the game object. - KX_IScalarInterpolator *ipo; + KX_IInterpolator *interpolator; + KX_IScalarInterpolator *interp; - ipo = ipoList->GetScalarInterpolator(LA_ENERGY); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_energy, ipo); + if ((interp= adtList->GetScalarInterpolator("energy", 0))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_energy, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyEnergy(true); } - ipo = ipoList->GetScalarInterpolator(LA_DIST); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_dist, ipo); + if ((interp = adtList->GetScalarInterpolator("distance", 0))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_dist, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyDist(true); } - - ipo = ipoList->GetScalarInterpolator(LA_COL_R); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_col_rgb[0], ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyColor(true); - } - - ipo = ipoList->GetScalarInterpolator(LA_COL_G); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_col_rgb[1], ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyColor(true); - } - - ipo = ipoList->GetScalarInterpolator(LA_COL_B); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_col_rgb[2], ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyColor(true); + + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("color", i))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_col_rgb[i], interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyColor(true); + } } } } @@ -451,7 +240,7 @@ void BL_ConvertLampIpos(struct Lamp* blenderlamp, KX_GameObject *lightobj,KX_Ble void BL_ConvertCameraIpos(struct Camera* blendercamera, KX_GameObject *cameraobj,KX_BlenderSceneConverter *converter) { - if (blendercamera->ipo) { + if (blendercamera->adt) { KX_CameraIpoSGController* ipocontr = new KX_CameraIpoSGController(); cameraobj->GetSGNode()->AddSGController(ipocontr); @@ -461,33 +250,28 @@ void BL_ConvertCameraIpos(struct Camera* blendercamera, KX_GameObject *cameraobj ipocontr->m_clipstart = blendercamera->clipsta; ipocontr->m_clipend = blendercamera->clipend; - BL_InterpolatorList *ipoList= GetIpoList(blendercamera->ipo, converter); + BL_InterpolatorList *adtList= GetAdtList(blendercamera->adt, converter); - // For each active channel in the ipoList add an + // For each active channel in the adtList add an // interpolator to the game object. - KX_IScalarInterpolator *ipo; + KX_IInterpolator *interpolator; + KX_IScalarInterpolator *interp; - ipo = ipoList->GetScalarInterpolator(CAM_LENS); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_lens, ipo); + if ((interp = adtList->GetScalarInterpolator("lens", 0))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_lens, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyLens(true); } - ipo = ipoList->GetScalarInterpolator(CAM_STA); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_clipstart, ipo); + if ((interp = adtList->GetScalarInterpolator("clip_start", 0))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_clipstart, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyClipStart(true); } - ipo = ipoList->GetScalarInterpolator(CAM_END); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_clipend, ipo); + if ((interp = adtList->GetScalarInterpolator("clip_end", 0))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_clipend, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyClipEnd(true); } @@ -499,7 +283,7 @@ void BL_ConvertCameraIpos(struct Camera* blendercamera, KX_GameObject *cameraobj void BL_ConvertWorldIpos(struct World* blenderworld,KX_BlenderSceneConverter *converter) { - if (blenderworld->ipo) { + if (blenderworld->adt) { KX_WorldIpoController* ipocontr = new KX_WorldIpoController(); @@ -514,49 +298,30 @@ void BL_ConvertWorldIpos(struct World* blenderworld,KX_BlenderSceneConverter *co ipocontr->m_mist_rgb[1] = blenderworld->horg; ipocontr->m_mist_rgb[2] = blenderworld->horb; - BL_InterpolatorList *ipoList= GetIpoList(blenderworld->ipo, converter); + BL_InterpolatorList *adtList= GetAdtList(blenderworld->adt, converter); - // For each active channel in the ipoList add an + // For each active channel in the adtList add an // interpolator to the game object. - KX_IScalarInterpolator *ipo; + KX_IInterpolator *interpolator; + KX_IScalarInterpolator *interp; - ipo = ipoList->GetScalarInterpolator(WO_HOR_R); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_mist_rgb[0], ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyMistColor(true); - } - - ipo = ipoList->GetScalarInterpolator(WO_HOR_G); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_mist_rgb[1], ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyMistColor(true); - } - - ipo = ipoList->GetScalarInterpolator(WO_HOR_B); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_mist_rgb[2], ipo); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyMistColor(true); + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("horizon_color", i))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_mist_rgb[i], interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyMistColor(true); + } } - ipo = ipoList->GetScalarInterpolator(WO_MISTDI); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_mist_dist, ipo); + if ((interp = adtList->GetScalarInterpolator("mist.depth", 0))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_mist_dist, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyMistDist(true); } - ipo = ipoList->GetScalarInterpolator(WO_MISTSTA); - if (ipo) { - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator(&ipocontr->m_mist_start, ipo); + if ((interp = adtList->GetScalarInterpolator("mist.start", 0))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_mist_start, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyMistStart(true); } @@ -570,12 +335,12 @@ static void ConvertMaterialIpos( KX_BlenderSceneConverter *converter ) { - if (blendermaterial->ipo) { + if (blendermaterial->adt) { KX_MaterialIpoController* ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); - BL_InterpolatorList *ipoList= GetIpoList(blendermaterial->ipo, converter); + BL_InterpolatorList *adtList= GetAdtList(blendermaterial->adt, converter); ipocontr->m_rgba[0] = blendermaterial->r; @@ -592,163 +357,82 @@ static void ConvertMaterialIpos( ipocontr->m_ref = blendermaterial->ref; ipocontr->m_emit = blendermaterial->emit; ipocontr->m_alpha = blendermaterial->alpha; - KX_IScalarInterpolator *ipo; - // -- - ipo = ipoList->GetScalarInterpolator(MA_COL_R); - if (ipo) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - gameobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(gameobj->GetSGNode()); - } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_rgba[0], - ipo); - ipocontr->AddInterpolator(interpolator); - } + KX_IInterpolator *interpolator; + KX_IScalarInterpolator *sinterp; - ipo = ipoList->GetScalarInterpolator(MA_COL_G); - if (ipo) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - gameobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(gameobj->GetSGNode()); - } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_rgba[1], - ipo); - ipocontr->AddInterpolator(interpolator); - } - - ipo = ipoList->GetScalarInterpolator(MA_COL_B); - if (ipo) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - gameobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(gameobj->GetSGNode()); + // -- + for(int i=0; i<3; i++) { + if ((sinterp = adtList->GetScalarInterpolator("diffuse_color", i))) { + if (!ipocontr) { + ipocontr = new KX_MaterialIpoController(matname_hash); + gameobj->GetSGNode()->AddSGController(ipocontr); + ipocontr->SetObject(gameobj->GetSGNode()); + } + interpolator= new KX_ScalarInterpolator(&ipocontr->m_rgba[i], sinterp); + ipocontr->AddInterpolator(interpolator); } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_rgba[2], - ipo); - ipocontr->AddInterpolator(interpolator); } - ipo = ipoList->GetScalarInterpolator(MA_ALPHA); - if (ipo) { + if ((sinterp = adtList->GetScalarInterpolator("alpha", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_rgba[3], - ipo); + interpolator= new KX_ScalarInterpolator(&ipocontr->m_rgba[3], sinterp); ipocontr->AddInterpolator(interpolator); } - // -- - ipo = ipoList->GetScalarInterpolator(MA_SPEC_R ); - if (ipo) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - gameobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(gameobj->GetSGNode()); - } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_specrgb[0], - ipo); - ipocontr->AddInterpolator(interpolator); - } - - ipo = ipoList->GetScalarInterpolator(MA_SPEC_G); - if (ipo) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - gameobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(gameobj->GetSGNode()); + for(int i=0; i<3; i++) { + if ((sinterp = adtList->GetScalarInterpolator("specular_color", i))) { + if (!ipocontr) { + ipocontr = new KX_MaterialIpoController(matname_hash); + gameobj->GetSGNode()->AddSGController(ipocontr); + ipocontr->SetObject(gameobj->GetSGNode()); + } + interpolator= new KX_ScalarInterpolator(&ipocontr->m_specrgb[i], sinterp); + ipocontr->AddInterpolator(interpolator); } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_specrgb[1], - ipo); - ipocontr->AddInterpolator(interpolator); } - ipo = ipoList->GetScalarInterpolator(MA_SPEC_B); - if (ipo) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - gameobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(gameobj->GetSGNode()); - } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_specrgb[2], - ipo); - ipocontr->AddInterpolator(interpolator); - } - - // -- - ipo = ipoList->GetScalarInterpolator(MA_HARD); - if (ipo) { + if ((sinterp = adtList->GetScalarInterpolator("specular_hardness", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_hard, - ipo); + interpolator= new KX_ScalarInterpolator(&ipocontr->m_hard, sinterp); ipocontr->AddInterpolator(interpolator); } - ipo = ipoList->GetScalarInterpolator(MA_SPEC); - if (ipo) { + if ((sinterp = adtList->GetScalarInterpolator("specularity", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_spec, - ipo); + interpolator= new KX_ScalarInterpolator(&ipocontr->m_spec, sinterp); ipocontr->AddInterpolator(interpolator); } - - ipo = ipoList->GetScalarInterpolator(MA_REF); - if (ipo) { + if ((sinterp = adtList->GetScalarInterpolator("diffuse_reflection", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_ref, - ipo); + interpolator= new KX_ScalarInterpolator(&ipocontr->m_ref, sinterp); ipocontr->AddInterpolator(interpolator); } - ipo = ipoList->GetScalarInterpolator(MA_EMIT); - if (ipo) { + if ((sinterp = adtList->GetScalarInterpolator("emit", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } - KX_IInterpolator *interpolator = - new KX_ScalarInterpolator( - &ipocontr->m_emit, - ipo); + interpolator= new KX_ScalarInterpolator(&ipocontr->m_emit, sinterp); ipocontr->AddInterpolator(interpolator); } } diff --git a/source/gameengine/Converter/Makefile b/source/gameengine/Converter/Makefile index 4dd63e428bd..e261f9350e9 100644 --- a/source/gameengine/Converter/Makefile +++ b/source/gameengine/Converter/Makefile @@ -37,17 +37,18 @@ CCFLAGS += $(LEVEL_1_CPP_WARNINGS) CPPFLAGS += -I$(OPENGL_HEADERS) CPPFLAGS += -I$(NAN_STRING)/include -CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) -CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO) -I$(NAN_MOTO)/include -CPPFLAGS += -I$(NAN_SOLID)/include +CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I$(NAN_BULLET2)/include +CPPFLAGS += -I$(NAN_AUDASPACE)/include CPPFLAGS += -I../../blender # these two needed because of blenkernel +CPPFLAGS += -I../../blender/windowmanager CPPFLAGS += -I../../blender/imbuf CPPFLAGS += -I../../blender/makesdna -CPPFLAGS += -I../../blender/include +CPPFLAGS += -I../../blender/makesrna +CPPFLAGS += -I../../blender/editors/include CPPFLAGS += -I../../blender/blenlib CPPFLAGS += -I../../blender/blenkernel CPPFLAGS += -I../../blender/render/extern/include diff --git a/source/gameengine/Converter/SConscript b/source/gameengine/Converter/SConscript index 3be352c568b..2d126310475 100644 --- a/source/gameengine/Converter/SConscript +++ b/source/gameengine/Converter/SConscript @@ -2,24 +2,25 @@ Import ('env') sources = env.Glob('*.cpp') +defs = [] incs = '. #source/kernel/gen_system #intern/string #intern/guardedalloc' -incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer #intern/bmfont' -incs += ' #intern/SoundSystem #intern/SoundSystem/include #intern/SoundSystem/openal' -incs += ' #intern/SoundSystem/dummy #intern/SoundSystem/intern #source/gameengine/Converter' +incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer' +incs += ' #intern/audaspace/intern #source/gameengine/Converter' incs += ' #source/gameengine/BlenderRoutines #source/blender/imbuf' incs += ' #intern/moto/include #source/gameengine/Ketsji #source/gameengine/Ketsji/KXNetwork' incs += ' #source/blender/blenlib #source/blender/blenkernel #source/blender' -incs += ' #source/blender/include #source/blender/makesdna #source/gameengine/Rasterizer' +incs += ' #source/blender/editors/include #source/blender/makesdna #source/gameengine/Rasterizer' incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer #source/gameengine/GameLogic' incs += ' #source/gameengine/Expressions #source/gameengine/Network #source/gameengine/SceneGraph' incs += ' #source/gameengine/Physics/common #source/gameengine/Physics/Bullet #source/gameengine/Physics/BlOde' -incs += ' #source/gameengine/Physics/Dummy #source/gameengine/Physics/Sumo' -incs += ' #source/gameengine/Physics/Sumo/Fuzzics/include #source/gameengine/Network/LoopBackNetwork' +incs += ' #source/gameengine/Physics/Dummy' +incs += ' #source/gameengine/Network/LoopBackNetwork' incs += ' #source/blender/misc #source/blender/blenloader #source/blender/gpu' +incs += ' #source/blender/windowmanager' +incs += ' #source/blender/makesrna' incs += ' ' + env['BF_PYTHON_INC'] -incs += ' ' + env['BF_SOLID_INC'] incs += ' ' + env['BF_BULLET_INC'] -env.BlenderLib ( 'bf_converter', sources, Split(incs), [], libtype=['game','player'], priority=[5,70] ) +env.BlenderLib ( 'bf_converter', sources, Split(incs), defs, libtype=['core','player'], priority=[305,40], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/Expressions/BoolValue.cpp b/source/gameengine/Expressions/BoolValue.cpp index cadb34d7e8f..6779c2ea780 100644 --- a/source/gameengine/Expressions/BoolValue.cpp +++ b/source/gameengine/Expressions/BoolValue.cpp @@ -26,6 +26,8 @@ // Construction/Destruction ////////////////////////////////////////////////////////////////////// +const STR_String CBoolValue::sTrueString = "TRUE"; +const STR_String CBoolValue::sFalseString = "FALSE"; CBoolValue::CBoolValue() /* @@ -45,7 +47,7 @@ CBoolValue::CBoolValue(bool inBool) -CBoolValue::CBoolValue(bool innie,STR_String name,AllocationTYPE alloctype) +CBoolValue::CBoolValue(bool innie,const char *name,AllocationTYPE alloctype) { m_bool = innie; SetName(name); @@ -181,18 +183,15 @@ ret: the bool stored in the object -float CBoolValue::GetNumber() +double CBoolValue::GetNumber() { - return (float)m_bool; + return (double)m_bool; } const STR_String& CBoolValue::GetText() { - static STR_String sTrueString = STR_String("TRUE"); - static STR_String sFalseString = STR_String("FALSE"); - return m_bool ? sTrueString : sFalseString; } @@ -201,7 +200,7 @@ const STR_String& CBoolValue::GetText() CValue* CBoolValue::GetReplica() { CBoolValue* replica = new CBoolValue(*this); - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } @@ -210,5 +209,5 @@ CValue* CBoolValue::GetReplica() PyObject* CBoolValue::ConvertValueToPython() { - return PyInt_FromLong(m_bool != 0); + return PyBool_FromLong(m_bool != 0); } diff --git a/source/gameengine/Expressions/BoolValue.h b/source/gameengine/Expressions/BoolValue.h index 6c4d964249f..4d0103ec1dd 100644 --- a/source/gameengine/Expressions/BoolValue.h +++ b/source/gameengine/Expressions/BoolValue.h @@ -28,12 +28,15 @@ class CBoolValue : public CPropValue //PLUGIN_DECLARE_SERIAL(CBoolValue,CValue) public: + static const STR_String sTrueString; + static const STR_String sFalseString; + CBoolValue(); CBoolValue(bool inBool); - CBoolValue(bool innie, STR_String name, AllocationTYPE alloctype = CValue::HEAPVALUE); + CBoolValue(bool innie, const char *name, AllocationTYPE alloctype = CValue::HEAPVALUE); virtual const STR_String& GetText(); - virtual float GetNumber(); + virtual double GetNumber(); bool GetBool(); virtual void SetValue(CValue* newval); @@ -46,6 +49,13 @@ public: private: bool m_bool; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CBoolValue"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined _BOOLVALUE_H diff --git a/source/gameengine/Expressions/CMakeLists.txt b/source/gameengine/Expressions/CMakeLists.txt index 6b2a835d648..439a50852a7 100644 --- a/source/gameengine/Expressions/CMakeLists.txt +++ b/source/gameengine/Expressions/CMakeLists.txt @@ -27,11 +27,13 @@ FILE(GLOB SRC *.cpp) SET(INC - . - ../../../source/kernel/gen_system - ../../../intern/string - ../../../intern/moto/include - ${PYTHON_INC} + . + ../../../source/kernel/gen_system + ../../../intern/string + ../../../intern/moto/include + ../../../source/gameengine/SceneGraph + ../../../source/blender/blenloader + ${PYTHON_INC} ) BLENDERLIB(bf_expressions "${SRC}" "${INC}") diff --git a/source/gameengine/Expressions/ConstExpr.cpp b/source/gameengine/Expressions/ConstExpr.cpp index e33ba091ac4..6b64be9c9a9 100644 --- a/source/gameengine/Expressions/ConstExpr.cpp +++ b/source/gameengine/Expressions/ConstExpr.cpp @@ -84,7 +84,7 @@ void CConstExpr::ClearModified() -float CConstExpr::GetNumber() +double CConstExpr::GetNumber() { return -1; } diff --git a/source/gameengine/Expressions/ConstExpr.h b/source/gameengine/Expressions/ConstExpr.h index e27ece52a83..f48b8d34355 100644 --- a/source/gameengine/Expressions/ConstExpr.h +++ b/source/gameengine/Expressions/ConstExpr.h @@ -32,7 +32,7 @@ public: //bool IsInside(float x,float y,float z,bool bBorderInclude=true); bool NeedsRecalculated(); void ClearModified(); - virtual float GetNumber(); + virtual double GetNumber(); virtual CValue* Calculate(); CConstExpr(CValue* constval); CConstExpr(); @@ -41,6 +41,13 @@ public: private: CValue* m_value; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CConstExpr"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined(AFX_CONSTEXPR_H__061ECFC3_BE87_11D1_A51C_00A02472FC58__INCLUDED_) diff --git a/source/gameengine/Expressions/EmptyValue.cpp b/source/gameengine/Expressions/EmptyValue.cpp index c2b60e590a4..5d1273b5301 100644 --- a/source/gameengine/Expressions/EmptyValue.cpp +++ b/source/gameengine/Expressions/EmptyValue.cpp @@ -76,7 +76,7 @@ this object -float CEmptyValue::GetNumber() +double CEmptyValue::GetNumber() { return 0; } @@ -121,7 +121,7 @@ const STR_String & CEmptyValue::GetText() CValue* CEmptyValue::GetReplica() { CEmptyValue* replica = new CEmptyValue(*this); - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } diff --git a/source/gameengine/Expressions/EmptyValue.h b/source/gameengine/Expressions/EmptyValue.h index b9cca0e57e5..01029d1655d 100644 --- a/source/gameengine/Expressions/EmptyValue.h +++ b/source/gameengine/Expressions/EmptyValue.h @@ -27,13 +27,20 @@ public: virtual ~CEmptyValue(); virtual const STR_String & GetText(); - virtual float GetNumber(); + virtual double GetNumber(); CListValue* GetPolySoup(); virtual double* GetVector3(bool bGetTransformedVec=false); bool IsInside(CValue* testpoint,bool bBorderInclude=true); CValue * Calc(VALUE_OPERATOR op, CValue *val); CValue * CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); virtual CValue* GetReplica(); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CEmptyValue"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined _EMPTYVALUE_H diff --git a/source/gameengine/Expressions/ErrorValue.cpp b/source/gameengine/Expressions/ErrorValue.cpp index e52be4c8021..a44abf8b22e 100644 --- a/source/gameengine/Expressions/ErrorValue.cpp +++ b/source/gameengine/Expressions/ErrorValue.cpp @@ -34,13 +34,15 @@ effect: constructs a new CErrorValue containing errormessage "Error" -CErrorValue::CErrorValue(STR_String errmsg) +CErrorValue::CErrorValue(const char *errmsg) /* pre: effect: constructs a new CErrorValue containing errormessage errmsg */ { - m_strErrorText = "[" + errmsg + "]"; + m_strErrorText = "["; + m_strErrorText += errmsg; + m_strErrorText += "]"; SetError(true); } @@ -99,7 +101,7 @@ ret: a new object containing the result of applying operator op to val and -float CErrorValue::GetNumber() +double CErrorValue::GetNumber() { return -1; } diff --git a/source/gameengine/Expressions/ErrorValue.h b/source/gameengine/Expressions/ErrorValue.h index 16e608ca01a..2f65850c4f1 100644 --- a/source/gameengine/Expressions/ErrorValue.h +++ b/source/gameengine/Expressions/ErrorValue.h @@ -23,9 +23,9 @@ class CErrorValue : public CPropValue public: virtual const STR_String & GetText(); - virtual float GetNumber(); + virtual double GetNumber(); CErrorValue(); - CErrorValue(STR_String errmsg); + CErrorValue(const char *errmsg); virtual ~CErrorValue(); virtual CValue* Calc(VALUE_OPERATOR op, CValue* val); virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); @@ -33,6 +33,13 @@ public: private: STR_String m_strErrorText; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CErrorValue"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined _ERRORVALUE_H diff --git a/source/gameengine/Expressions/Expression.h b/source/gameengine/Expressions/Expression.h index 400a2b7c789..bd346fd0552 100644 --- a/source/gameengine/Expressions/Expression.h +++ b/source/gameengine/Expressions/Expression.h @@ -63,6 +63,12 @@ class CBrokenLinkInfo CExpression* m_pExpr; bool m_bRestored; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CBrokenLinkInfo"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; @@ -126,6 +132,13 @@ public: protected: int m_refcount; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CExpression"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined _EXPRESSION_H diff --git a/source/gameengine/Expressions/FloatValue.cpp b/source/gameengine/Expressions/FloatValue.cpp index 93f102d04a6..4de685a82c1 100644 --- a/source/gameengine/Expressions/FloatValue.cpp +++ b/source/gameengine/Expressions/FloatValue.cpp @@ -50,7 +50,7 @@ effect: constructs a new CFloatValue containing value fl -CFloatValue::CFloatValue(float fl,STR_String name,AllocationTYPE alloctype) +CFloatValue::CFloatValue(float fl,const char *name,AllocationTYPE alloctype) /* pre: effect: constructs a new CFloatValue containing value fl @@ -127,6 +127,9 @@ ret: a new object containing the result of applying operator op to val and { switch (op) { + case VALUE_MOD_OPERATOR: + ret = new CFloatValue(fmod(((CIntValue *) val)->GetInt(), m_float)); + break; case VALUE_ADD_OPERATOR: ret = new CFloatValue(((CIntValue *) val)->GetInt() + m_float); break; @@ -171,6 +174,9 @@ ret: a new object containing the result of applying operator op to val and { switch (op) { + case VALUE_MOD_OPERATOR: + ret = new CFloatValue(fmod(((CFloatValue *) val)->GetFloat(), m_float)); + break; case VALUE_ADD_OPERATOR: ret = new CFloatValue(((CFloatValue *) val)->GetFloat() + m_float); break; @@ -272,7 +278,7 @@ ret: the float stored in the object -float CFloatValue::GetNumber() +double CFloatValue::GetNumber() { return m_float; } @@ -281,7 +287,7 @@ float CFloatValue::GetNumber() void CFloatValue::SetValue(CValue* newval) { - m_float = newval->GetNumber(); + m_float = (float)newval->GetNumber(); SetModified(true); } @@ -301,8 +307,8 @@ const STR_String & CFloatValue::GetText() CValue* CFloatValue::GetReplica() { CFloatValue* replica = new CFloatValue(*this); - replica->m_pstrRep = NULL; - CValue::AddDataToReplica(replica); + replica->m_pstrRep = NULL; /* should be in CFloatValue::ProcessReplica() but its not defined, no matter */ + replica->ProcessReplica(); return replica; } diff --git a/source/gameengine/Expressions/FloatValue.h b/source/gameengine/Expressions/FloatValue.h index 33f05f1d7f2..442f0eb6cf8 100644 --- a/source/gameengine/Expressions/FloatValue.h +++ b/source/gameengine/Expressions/FloatValue.h @@ -23,12 +23,12 @@ class CFloatValue : public CPropValue public: CFloatValue(); CFloatValue(float fl); - CFloatValue(float fl,STR_String name,AllocationTYPE alloctype=CValue::HEAPVALUE); + CFloatValue(float fl,const char *name,AllocationTYPE alloctype=CValue::HEAPVALUE); virtual const STR_String & GetText(); void Configure(CValue* menuvalue); - virtual float GetNumber(); + virtual double GetNumber(); virtual void SetValue(CValue* newval); float GetFloat(); void SetFloat(float fl); @@ -42,6 +42,12 @@ protected: float m_float; STR_String* m_pstrRep; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CFloatValue"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined _FLOATVALUE_H diff --git a/source/gameengine/Expressions/IdentifierExpr.h b/source/gameengine/Expressions/IdentifierExpr.h index b307228c8b9..7c14329f755 100644 --- a/source/gameengine/Expressions/IdentifierExpr.h +++ b/source/gameengine/Expressions/IdentifierExpr.h @@ -46,6 +46,13 @@ public: virtual CExpression* CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks); virtual void ClearModified(); virtual void BroadcastOperators(VALUE_OPERATOR op); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CIdentifierExpr"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__IDENTIFIER_EXPR diff --git a/source/gameengine/Expressions/IfExpr.cpp b/source/gameengine/Expressions/IfExpr.cpp index 5d3eb3641ca..fcb37bff52d 100644 --- a/source/gameengine/Expressions/IfExpr.cpp +++ b/source/gameengine/Expressions/IfExpr.cpp @@ -15,6 +15,7 @@ #include "IfExpr.h" #include "EmptyValue.h" #include "ErrorValue.h" +#include "BoolValue.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -72,14 +73,14 @@ ret: a new object containing the value of m_e1 if m_guard is a boolean TRUE { CValue *guardval; guardval = m_guard->Calculate(); - STR_String text = guardval->GetText(); + const STR_String& text = guardval->GetText(); guardval->Release(); - if (text == STR_String("TRUE")) + if (&text == &CBoolValue::sTrueString) { return m_e1->Calculate(); } - else if (text == STR_String("FALSE")) + else if (&text == &CBoolValue::sFalseString) { return m_e2->Calculate(); } diff --git a/source/gameengine/Expressions/IfExpr.h b/source/gameengine/Expressions/IfExpr.h index 9ab13dca413..f06718c851f 100644 --- a/source/gameengine/Expressions/IfExpr.h +++ b/source/gameengine/Expressions/IfExpr.h @@ -44,6 +44,13 @@ public: virtual CExpression* CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks); virtual void ClearModified(); virtual void BroadcastOperators(VALUE_OPERATOR op); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CIfExpr"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined(AFX_IFEXPR_H__1F691841_C5C7_11D1_A863_0000B4542BD8__INCLUDED_) diff --git a/source/gameengine/Expressions/InputParser.cpp b/source/gameengine/Expressions/InputParser.cpp index 32a9de32e21..96a52aec028 100644 --- a/source/gameengine/Expressions/InputParser.cpp +++ b/source/gameengine/Expressions/InputParser.cpp @@ -38,6 +38,14 @@ // cool things like (IF(LOD==1,CCurvedValue,IF(LOD==2,CCurvedValue2)) etc... #include "IfExpr.h" +#if (defined(WIN32) || defined(WIN64)) && !defined(FREE_WINDOWS) +#define strcasecmp _stricmp + +#ifndef strtoll +#define strtoll _strtoi64 +#endif + +#endif /* Def WIN32 or Def WIN64 */ #define NUM_PRIORITY 6 ////////////////////////////////////////////////////////////////////// @@ -58,7 +66,7 @@ CParser::~CParser() -void CParser::ScanError(STR_String str) +void CParser::ScanError(const char *str) { // sets the global variable errmsg to an errormessage with // contents str, appending if it already exists @@ -73,7 +81,7 @@ void CParser::ScanError(STR_String str) -CExpression* CParser::Error(STR_String str) +CExpression* CParser::Error(const char *str) { // makes and returns a new CConstExpr filled with an CErrorValue // with string str @@ -172,6 +180,9 @@ void CParser::NextSym() case ',': sym = commasym; NextCh(); break; + case '%' : + sym = opsym; opkind = OPmodulus; NextCh(); + break; case '+' : sym = opsym; opkind = OPplus; NextCh(); break; @@ -271,33 +282,30 @@ void CParser::NextSym() } else if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'))) { // reserved word? - int start; - STR_String funstr; + start = chcount; CharRep(); GrabString(start); - funstr = const_as_string; - funstr.Upper(); - if (funstr == STR_String("SUM")) { + if (!strcasecmp(const_as_string, "SUM")) { sym = sumsym; } - else if (funstr == STR_String("NOT")) { + else if (!strcasecmp(const_as_string, "NOT")) { sym = opsym; opkind = OPnot; } - else if (funstr == STR_String("AND")) { + else if (!strcasecmp(const_as_string, "AND")) { sym = opsym; opkind = OPand; } - else if (funstr == STR_String("OR")) { + else if (!strcasecmp(const_as_string, "OR")) { sym = opsym; opkind = OPor; } - else if (funstr == STR_String("IF")) { + else if (!strcasecmp(const_as_string, "IF")) sym = ifsym; - } else if (funstr == STR_String("WHOMADE")) { + else if (!strcasecmp(const_as_string, "WHOMADE")) sym = whocodedsym; - } else if (funstr == STR_String("FALSE")) { + else if (!strcasecmp(const_as_string, "FALSE")) { sym = constsym; constkind = booltype; boolvalue = false; - } else if (funstr == STR_String("TRUE")) { + } else if (!strcasecmp(const_as_string, "TRUE")) { sym = constsym; constkind = booltype; boolvalue = true; } else { sym = idsym; @@ -316,12 +324,14 @@ void CParser::NextSym() } } +#if 0 int CParser::MakeInt() { // returns the integer representation of the value in the global // variable const_as_string // pre: const_as_string contains only numercal chars return atoi(const_as_string); } +#endif STR_String CParser::Symbol2Str(int s) { // returns a string representation of of symbol s, @@ -370,6 +380,7 @@ int CParser::Priority(int optorkind) { case OPunequal: return 3; case OPplus: case OPminus: return 4; + case OPmodulus: case OPtimes: case OPdivide: return 5; } @@ -390,6 +401,7 @@ CExpression *CParser::Ex(int i) { NextSym(); e2 = Ex(i + 1); switch(opkind2) { + case OPmodulus: e1 = new COperator2Expr(VALUE_MOD_OPERATOR,e1, e2); break; case OPplus: e1 = new COperator2Expr(VALUE_ADD_OPERATOR,e1, e2); break; case OPminus: e1 = new COperator2Expr(VALUE_SUB_OPERATOR,e1, e2); break; case OPtimes: e1 = new COperator2Expr(VALUE_MUL_OPERATOR,e1, e2); break; @@ -431,8 +443,8 @@ CExpression *CParser::Ex(int i) { break; case inttype: { - int temp; - temp = atoi(const_as_string); + cInt temp; + temp = strtoll(const_as_string, NULL, 10); /* atoi is for int only */ e1 = new CConstExpr(new CIntValue(temp)); break; } @@ -525,7 +537,7 @@ CExpression *CParser::Expr() { } CExpression* CParser::ProcessText -(STR_String intext) { +(const char *intext) { // and parses the string in intext and returns it. @@ -562,7 +574,7 @@ CExpression* CParser::ProcessText -float CParser::GetFloat(STR_String txt) +float CParser::GetFloat(STR_String& txt) { // returns parsed text into a float // empty string returns -1 @@ -575,7 +587,7 @@ float CParser::GetFloat(STR_String txt) CExpression* expr = ProcessText(txt); if (expr) { val = expr->Calculate(); - result=val->GetNumber(); + result=(float)val->GetNumber(); @@ -587,7 +599,7 @@ float CParser::GetFloat(STR_String txt) return result; } -CValue* CParser::GetValue(STR_String txt, bool bFallbackToText) +CValue* CParser::GetValue(STR_String& txt, bool bFallbackToText) { // returns parsed text into a value, // empty string returns NULL value ! @@ -624,32 +636,3 @@ void CParser::SetContext(CValue* context) } m_identifierContext = context; } - - - - -PyObject* CParserPyMake(PyObject* ignored,PyObject* args) -{ - char* txt; - if (!PyArg_ParseTuple(args,"s",&txt)) - return NULL; - CParser parser; - CExpression* expr = parser.ProcessText(txt); - CValue* val = expr->Calculate(); - expr->Release(); - return val; -} - -static PyMethodDef CParserMethods[] = -{ - { "calc", CParserPyMake , METH_VARARGS}, - { NULL,NULL} // Sentinel -}; - -extern "C" { - void initExpressionModule(void) - { - Py_InitModule("Expression",CParserMethods); - } -} - diff --git a/source/gameengine/Expressions/InputParser.h b/source/gameengine/Expressions/InputParser.h index 4caa47cbb0c..0d7eab27aeb 100644 --- a/source/gameengine/Expressions/InputParser.h +++ b/source/gameengine/Expressions/InputParser.h @@ -27,9 +27,9 @@ public: CParser(); virtual ~CParser(); - float GetFloat(STR_String txt); - CValue* GetValue(STR_String txt, bool bFallbackToText=false); - CExpression* ProcessText(STR_String intext); + float GetFloat(STR_String& txt); + CValue* GetValue(STR_String& txt, bool bFallbackToText=false); + CExpression* ProcessText(const char *intext); void SetContext(CValue* context); private: @@ -49,6 +49,7 @@ private: }; // all kinds of symbols enum optype { + OPmodulus, OPplus, OPminus, OPtimes, @@ -85,21 +86,29 @@ private: CValue* m_identifierContext;// context in which identifiers are looked up - void ScanError(STR_String str); - CExpression* Error(STR_String str); + void ScanError(const char *str); + CExpression* Error(const char *str); void NextCh(); void TermChar(char c); void DigRep(); void CharRep(); void GrabString(int start); void NextSym(); +#if 0 /* not used yet */ int MakeInt(); +#endif STR_String Symbol2Str(int s); void Term(int s); int Priority(int optor); CExpression *Ex(int i); CExpression *Expr(); - + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CParser"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Expressions/IntValue.cpp b/source/gameengine/Expressions/IntValue.cpp index fbf4f4f59e0..b782de4bef6 100644 --- a/source/gameengine/Expressions/IntValue.cpp +++ b/source/gameengine/Expressions/IntValue.cpp @@ -42,10 +42,10 @@ effect: constructs a new CIntValue -CIntValue::CIntValue(int innie) +CIntValue::CIntValue(cInt innie) /* pre: -effect: constructs a new CIntValue containing int innie +effect: constructs a new CIntValue containing cInt innie */ { m_int = innie; @@ -54,7 +54,7 @@ effect: constructs a new CIntValue containing int innie -CIntValue::CIntValue(int innie,STR_String name,AllocationTYPE alloctype) +CIntValue::CIntValue(cInt innie,const char *name,AllocationTYPE alloctype) { m_int = innie; SetName(name); @@ -125,6 +125,9 @@ this object case VALUE_INT_TYPE: { switch (op) { + case VALUE_MOD_OPERATOR: + ret = new CIntValue (((CIntValue *) val)->GetInt() % m_int); + break; case VALUE_ADD_OPERATOR: ret = new CIntValue (((CIntValue *) val)->GetInt() + m_int); break; @@ -181,6 +184,9 @@ this object case VALUE_FLOAT_TYPE: { switch (op) { + case VALUE_MOD_OPERATOR: + ret = new CFloatValue(fmod(((CFloatValue *) val)->GetFloat(), m_int)); + break; case VALUE_ADD_OPERATOR: ret = new CFloatValue (((CFloatValue *) val)->GetFloat() + m_int); break; @@ -274,10 +280,10 @@ this object -int CIntValue::GetInt() +cInt CIntValue::GetInt() /* pre: -ret: the int stored in the object +ret: the cInt stored in the object */ { return m_int; @@ -285,7 +291,7 @@ ret: the int stored in the object -float CIntValue::GetNumber() +double CIntValue::GetNumber() { return (float) m_int; } @@ -296,7 +302,7 @@ const STR_String & CIntValue::GetText() { if (!m_pstrRep) m_pstrRep=new STR_String(); - m_pstrRep->Format("%d",m_int); + m_pstrRep->Format("%lld",m_int); return *m_pstrRep; } @@ -305,7 +311,7 @@ const STR_String & CIntValue::GetText() CValue* CIntValue::GetReplica() { CIntValue* replica = new CIntValue(*this); - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); replica->m_pstrRep = NULL; return replica; @@ -315,7 +321,7 @@ CValue* CIntValue::GetReplica() { void CIntValue::SetValue(CValue* newval) { - m_int = (int)newval->GetNumber(); + m_int = (cInt)newval->GetNumber(); SetModified(true); } @@ -323,5 +329,8 @@ void CIntValue::SetValue(CValue* newval) PyObject* CIntValue::ConvertValueToPython() { - return PyInt_FromLong(m_int); + if((m_int > INT_MIN) && (m_int < INT_MAX)) + return PyLong_FromSsize_t(m_int); + else + return PyLong_FromLongLong(m_int); } diff --git a/source/gameengine/Expressions/IntValue.h b/source/gameengine/Expressions/IntValue.h index 4fdc1089857..0513026c4cf 100644 --- a/source/gameengine/Expressions/IntValue.h +++ b/source/gameengine/Expressions/IntValue.h @@ -18,19 +18,21 @@ #include "Value.h" +typedef long long cInt; + class CIntValue : public CPropValue { //PLUGIN_DECLARE_SERIAL (CIntValue,CValue) public: virtual const STR_String& GetText(); - virtual float GetNumber(); + virtual double GetNumber(); - int GetInt(); + cInt GetInt(); CIntValue(); - CIntValue(int innie); - CIntValue(int innie, - STR_String name, + CIntValue(cInt innie); + CIntValue(cInt innie, + const char *name, AllocationTYPE alloctype=CValue::HEAPVALUE); virtual CValue* Calc(VALUE_OPERATOR op, @@ -51,9 +53,15 @@ protected: virtual ~CIntValue(); private: - int m_int; + cInt m_int; STR_String* m_pstrRep; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CIntValue"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined _INTVALUE_H diff --git a/source/gameengine/Expressions/KX_HashedPtr.h b/source/gameengine/Expressions/KX_HashedPtr.h index b11efb99d68..0b54436147b 100644 --- a/source/gameengine/Expressions/KX_HashedPtr.h +++ b/source/gameengine/Expressions/KX_HashedPtr.h @@ -29,6 +29,10 @@ #ifndef __KX_HASHEDPTR #define __KX_HASHEDPTR +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + unsigned int KX_Hash(void * inDWord); class CHashedPtr @@ -44,6 +48,13 @@ public: { return rhs.m_valptr == lhs.m_valptr; } + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CHashedPtr"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_HASHEDPTR diff --git a/source/gameengine/Expressions/KX_Python.h b/source/gameengine/Expressions/KX_Python.h index b8006fdf0ed..f41accec730 100644 --- a/source/gameengine/Expressions/KX_Python.h +++ b/source/gameengine/Expressions/KX_Python.h @@ -30,8 +30,21 @@ #define KX_PYTHON_H //#define USE_DL_EXPORT + +/* python redefines, quiet the compiler */ +#ifdef _XOPEN_SOURCE +#undef _XOPEN_SOURCE +#endif + +#ifdef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif + + #include "Python.h" +#define USE_MATHUTILS // Blender 2.5x api will use mathutils, for a while we might want to test without it + #ifdef __FreeBSD__ #include <osreldate.h> #if __FreeBSD_version > 500039 diff --git a/source/gameengine/Expressions/ListValue.cpp b/source/gameengine/Expressions/ListValue.cpp index 9ffdbb1223c..002674450d1 100644 --- a/source/gameengine/Expressions/ListValue.cpp +++ b/source/gameengine/Expressions/ListValue.cpp @@ -18,6 +18,9 @@ #include "StringValue.h" #include "VoidValue.h" #include <algorithm> +#include "BoolValue.h" + +#include "BLO_sys_types.h" /* for intptr_t support */ #ifdef HAVE_CONFIG_H #include <config.h> @@ -27,55 +30,87 @@ #define Py_ssize_t int #endif -Py_ssize_t listvalue_bufferlen(PyObject* list) +Py_ssize_t listvalue_bufferlen(PyObject* self) { - return (Py_ssize_t)( ((CListValue*)list)->GetCount()); + CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); + if (list==NULL) + return 0; + + return (Py_ssize_t)list->GetCount(); } -PyObject* listvalue_buffer_item(PyObject* list,Py_ssize_t index) +PyObject* listvalue_buffer_item(PyObject* self, Py_ssize_t index) { - if (index >= 0 && index < ((CListValue*) list)->GetCount()) - { - PyObject* pyobj = ((CListValue*) list)->GetValue(index)->ConvertValueToPython(); - if (pyobj) - return pyobj; - else - return ((CListValue*) list)->GetValue(index)->AddRef(); - + CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); + CValue *cval; + + if (list==NULL) { + PyErr_SetString(PyExc_SystemError, "val = CList[i], "BGE_PROXY_ERROR_MSG); + return NULL; } - PyErr_SetString(PyExc_IndexError, "Python ListIndex out of range"); - return NULL; + + int count = list->GetCount(); + + if (index < 0) + index = count+index; + + if (index < 0 || index >= count) { + PyErr_SetString(PyExc_IndexError, "CList[i]: Python ListIndex out of range in CValueList"); + return NULL; + } + + cval= list->GetValue(index); + + PyObject* pyobj = cval->ConvertValueToPython(); + if (pyobj) + return pyobj; + else + return cval->GetProxy(); } -PyObject* listvalue_mapping_subscript(PyObject* list,PyObject* pyindex) +PyObject* listvalue_mapping_subscript(PyObject* self, PyObject* pyindex) { - if (PyString_Check(pyindex)) + CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); + if (list==NULL) { + PyErr_SetString(PyExc_SystemError, "value = CList[i], "BGE_PROXY_ERROR_MSG); + return NULL; + } + + if (PyUnicode_Check(pyindex)) { - STR_String index(PyString_AsString(pyindex)); - CValue *item = ((CListValue*) list)->FindValue(index); - if (item) - return (PyObject*) item; - + CValue *item = ((CListValue*) list)->FindValue(_PyUnicode_AsString(pyindex)); + if (item) { + PyObject* pyobj = item->ConvertValueToPython(); + if(pyobj) + return pyobj; + else + return item->GetProxy(); + } } - if (PyInt_Check(pyindex)) + else if (PyLong_Check(pyindex)) { - int index = PyInt_AsLong(pyindex); - return listvalue_buffer_item(list, index); + int index = PyLong_AsSsize_t(pyindex); + return listvalue_buffer_item(self, index); /* wont add a ref */ } PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */ - STR_String index_str(PyString_AsString(pyindex_str)); - PyErr_Format(PyExc_KeyError, "'%s' not in list", index_str.Ptr()); + PyErr_Format(PyExc_KeyError, "CList[key]: '%s' key not in list", _PyUnicode_AsString(pyindex_str)); Py_DECREF(pyindex_str); return NULL; } /* just slice it into a python list... */ -PyObject* listvalue_buffer_slice(PyObject* list,Py_ssize_t ilow, Py_ssize_t ihigh) +PyObject* listvalue_buffer_slice(PyObject* self,Py_ssize_t ilow, Py_ssize_t ihigh) { + CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); + if (list==NULL) { + PyErr_SetString(PyExc_SystemError, "val = CList[i:j], "BGE_PROXY_ERROR_MSG); + return NULL; + } + int i, j; - PyListObject *newlist; + PyObject *newlist; if (ilow < 0) ilow = 0; @@ -86,95 +121,132 @@ PyObject* listvalue_buffer_slice(PyObject* list,Py_ssize_t ilow, Py_ssize_t ihig if (ihigh < ilow) ihigh = ilow; - newlist = (PyListObject *) PyList_New(ihigh - ilow); + newlist = PyList_New(ihigh - ilow); if (!newlist) return NULL; for (i = ilow, j = 0; i < ihigh; i++, j++) { - PyObject* pyobj = ((CListValue*) list)->GetValue(i)->ConvertValueToPython(); + PyObject* pyobj = list->GetValue(i)->ConvertValueToPython(); if (!pyobj) - pyobj = ((CListValue*) list)->GetValue(i)->AddRef(); - newlist->ob_item[j] = pyobj; + pyobj = list->GetValue(i)->GetProxy(); + PyList_SET_ITEM(newlist, i, pyobj); } - return (PyObject *) newlist; + return newlist; } - -static PyObject * -listvalue_buffer_concat(PyObject * self, PyObject * other) +/* clist + list, return a list that python owns */ +static PyObject *listvalue_buffer_concat(PyObject * self, PyObject * other) { + CListValue *listval= static_cast<CListValue *>(BGE_PROXY_REF(self)); + int i, numitems, numitems_orig; + + if (listval==NULL) { + PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG); + return NULL; + } + + numitems_orig= listval->GetCount(); + // for now, we support CListValue concatenated with items // and CListValue concatenated to Python Lists // and CListValue concatenated with another CListValue - - CListValue* listval = (CListValue*) self; - listval->AddRef(); - if (other->ob_type == &PyList_Type) + + /* Shallow copy, dont use listval->GetReplica(), it will screw up with KX_GameObjects */ + CListValue* listval_new = new CListValue(); + + if (PyList_Check(other)) { + CValue* listitemval; bool error = false; - - int i; - int numitems = PyList_Size(other); + + numitems = PyList_Size(other); + + /* copy the first part of the list */ + listval_new->Resize(numitems_orig + numitems); + for (i=0;i<numitems_orig;i++) + listval_new->SetValue(i, listval->GetValue(i)->AddRef()); + for (i=0;i<numitems;i++) { - PyObject* listitem = PyList_GetItem(other,i); - CValue* listitemval = listval->ConvertPythonToValue(listitem); - if (listitemval) - { - listval->Add(listitemval); - } else - { - error = true; + listitemval = listval->ConvertPythonToValue(PyList_GetItem(other,i), "cList + pyList: CListValue, "); + + if (listitemval) { + listval_new->SetValue(i+numitems_orig, listitemval); + } else { + error= true; + break; } } - + if (error) { - PyErr_SetString(PyExc_SystemError, "Python Error: couldn't add one or more items to a list"); + listval_new->Resize(numitems_orig+i); /* resize so we dont try release NULL pointers */ + listval_new->Release(); + return NULL; /* ConvertPythonToValue above sets the error */ + } + + } + else if (PyObject_TypeCheck(other, &CListValue::Type)) { + // add items from otherlist to this list + CListValue* otherval = static_cast<CListValue *>(BGE_PROXY_REF(other)); + if(otherval==NULL) { + listval_new->Release(); + PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG); return NULL; } + + numitems = otherval->GetCount(); + + /* copy the first part of the list */ + listval_new->Resize(numitems_orig + numitems); /* resize so we dont try release NULL pointers */ + for (i=0;i<numitems_orig;i++) + listval_new->SetValue(i, listval->GetValue(i)->AddRef()); + + /* now copy the other part of the list */ + for (i=0;i<numitems;i++) + listval_new->SetValue(i+numitems_orig, otherval->GetValue(i)->AddRef()); + + } + return listval_new->NewProxy(true); /* python owns this list */ +} - } else - { - if (other->ob_type == &CListValue::Type) - { - // add items from otherlist to this list - CListValue* otherval = (CListValue*) other; - - - for (int i=0;i<otherval->GetCount();i++) - { - otherval->Add(listval->GetValue(i)->AddRef()); - } - } - else - { - CValue* objval = listval->ConvertPythonToValue(other); - if (objval) - { - listval->Add(objval); - } else - { - PyErr_SetString(PyExc_SystemError, "Python Error: couldn't add item to a list"); - return NULL; - } +static int listvalue_buffer_contains(PyObject *self_v, PyObject *value) +{ + CListValue *self= static_cast<CListValue *>(BGE_PROXY_REF(self_v)); + + if (self==NULL) { + PyErr_SetString(PyExc_SystemError, "val in CList, "BGE_PROXY_ERROR_MSG); + return -1; + } + + if (PyUnicode_Check(value)) { + if (self->FindValue((const char *)_PyUnicode_AsString(value))) { + return 1; } } - - return self; + else if (PyObject_TypeCheck(value, &CValue::Type)) { /* not dict like at all but this worked before __contains__ was used */ + CValue *item= static_cast<CValue *>(BGE_PROXY_REF(value)); + for (int i=0; i < self->GetCount(); i++) + if (self->GetValue(i) == item) // Com + return 1; + + } // not using CheckEqual + + return 0; } - static PySequenceMethods listvalue_as_sequence = { listvalue_bufferlen,//(inquiry)buffer_length, /*sq_length*/ listvalue_buffer_concat, /*sq_concat*/ NULL, /*sq_repeat*/ listvalue_buffer_item, /*sq_item*/ - listvalue_buffer_slice, /*sq_slice*/ +// TODO, slicing in py3 + NULL, // listvalue_buffer_slice, /*sq_slice*/ NULL, /*sq_ass_item*/ - NULL /*sq_ass_slice*/ + NULL, /*sq_ass_slice*/ + (objobjproc)listvalue_buffer_contains, /* sq_contains */ }; @@ -189,58 +261,62 @@ static PyMappingMethods instance_as_mapping = { PyTypeObject CListValue::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT(NULL, 0) "CListValue", /*tp_name*/ - sizeof(CListValue), /*tp_basicsize*/ + sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ - PyDestructor, /*tp_dealloc*/ + py_base_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - __getattr, /*tp_getattr*/ - __setattr, /*tp_setattr*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ 0, /*tp_compare*/ - __repr, /*tp_repr*/ + py_base_repr, /*tp_repr*/ 0, /*tp_as_number*/ &listvalue_as_sequence, /*tp_as_sequence*/ &instance_as_mapping, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call */ -}; - - - -PyParentObject CListValue::Parents[] = { - &CListValue::Type, + 0, + NULL, + NULL, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; - - - PyMethodDef CListValue::Methods[] = { - {"append", (PyCFunction)CListValue::sPyappend,METH_VARARGS}, - {"reverse", (PyCFunction)CListValue::sPyreverse,METH_VARARGS}, - {"index", (PyCFunction)CListValue::sPyindex,METH_VARARGS}, - {"count", (PyCFunction)CListValue::sPycount,METH_VARARGS}, + /* List style access */ + {"append", (PyCFunction)CListValue::sPyappend,METH_O}, + {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS}, + {"index", (PyCFunction)CListValue::sPyindex,METH_O}, + {"count", (PyCFunction)CListValue::sPycount,METH_O}, + + /* Dict style access */ + {"get", (PyCFunction)CListValue::sPyget,METH_VARARGS}, + + /* Own cvalue funcs */ + {"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O}, {NULL,NULL} //Sentinel }; - - -PyObject* CListValue::_getattr(const STR_String& attr) { - _getattr_up(CValue); -} - +PyAttributeDef CListValue::Attributes[] = { + { NULL } //Sentinel +}; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// -CListValue::CListValue(PyTypeObject *T ) -: CPropValue(T) +CListValue::CListValue() +: CPropValue() { m_bReleaseContents=true; } @@ -281,7 +357,7 @@ const STR_String & CListValue::GetText() CValue* CListValue::GetReplica() { CListValue* replica = new CListValue(*this); - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); replica->m_bReleaseContents=true; // for copy, complete array is copied for now... // copy all values @@ -331,23 +407,21 @@ void CListValue::ReleaseAndRemoveAll() CValue* CListValue::FindValue(const STR_String & name) { - CValue* resultval = NULL; - int i=0; + for (int i=0; i < GetCount(); i++) + if (GetValue(i)->GetName() == name) + return GetValue(i); - while (!resultval && i < GetCount()) - { - CValue* myval = GetValue(i); - - if (myval->GetName() == name) - resultval = GetValue(i)->AddRef(); // add referencecount - else - i++; - - } - return resultval; + return NULL; } - +CValue* CListValue::FindValue(const char * name) +{ + for (int i=0; i < GetCount(); i++) + if (GetValue(i)->GetName() == name) + return GetValue(i); + + return NULL; +} bool CListValue::SearchValue(CValue *val) { @@ -394,39 +468,32 @@ void CListValue::MergeList(CListValue *otherlist) { SetValue(i+numelements,otherlist->GetValue(i)->AddRef()); } - } - -PyObject* CListValue::Pyappend(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* CListValue::Pyappend(PyObject* value) { + CValue* objval = ConvertPythonToValue(value, "CList.append(i): CValueList, "); - PyObject* pyobj = NULL; - if (PyArg_ParseTuple(args,"O",&pyobj)) - { - return listvalue_buffer_concat(self,pyobj); - } - else - { - return NULL; + if (!objval) /* ConvertPythonToValue sets the error */ + return NULL; + + if (!BGE_PROXY_PYOWNS(m_proxy)) { + PyErr_SetString(PyExc_TypeError, "CList.append(i): this CValueList is used internally for the game engine and can't be modified"); + return NULL; } - + Add(objval); + + Py_RETURN_NONE; } -PyObject* CListValue::Pyreverse(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* CListValue::Pyreverse() { std::reverse(m_pValueArray.begin(),m_pValueArray.end()); - - Py_Return; - + Py_RETURN_NONE; } @@ -434,94 +501,142 @@ PyObject* CListValue::Pyreverse(PyObject* self, bool CListValue::CheckEqual(CValue* first,CValue* second) { bool result = false; - + CValue* eqval = ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second); - STR_String txt = eqval->GetText(); - eqval->Release(); - if (txt=="TRUE") + + if (eqval==NULL) + return false; + const STR_String& text = eqval->GetText(); + if (&text==&CBoolValue::sTrueString) { result = true; } + eqval->Release(); return result; } -PyObject* CListValue::Pyindex(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* CListValue::Pyindex(PyObject *value) { PyObject* result = NULL; - PyObject* pyobj = NULL; - if (PyArg_ParseTuple(args,"O",&pyobj)) + CValue* checkobj = ConvertPythonToValue(value, "val = cList[i]: CValueList, "); + if (checkobj==NULL) + return NULL; /* ConvertPythonToValue sets the error */ + + int numelem = GetCount(); + for (int i=0;i<numelem;i++) { - - CValue* checkobj = ConvertPythonToValue(pyobj); - int numelem = GetCount(); - for (int i=0;i<numelem;i++) + CValue* elem = GetValue(i); + if (checkobj==elem || CheckEqual(checkobj,elem)) { - CValue* elem = GetValue(i); - if (CheckEqual(checkobj,elem)) - { - result = PyInt_FromLong(i); - break; - } + result = PyLong_FromSsize_t(i); + break; } - checkobj->Release(); } + checkobj->Release(); + if (result==NULL) { + PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in CListValue"); + } return result; } -PyObject* CListValue::Pycount(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* CListValue::Pycount(PyObject* value) { - int numfound = 0; - PyObject* pyobj = NULL; - if (PyArg_ParseTuple(args,"O",&pyobj)) + CValue* checkobj = ConvertPythonToValue(value, ""); /* error ignored */ + + if (checkobj==NULL) { /* in this case just return that there are no items in the list */ + PyErr_Clear(); + return PyLong_FromSsize_t(0); + } + + int numelem = GetCount(); + for (int i=0;i<numelem;i++) { - CValue* checkobj = ConvertPythonToValue(pyobj); - int numelem = GetCount(); - for (int i=0;i<numelem;i++) + CValue* elem = GetValue(i); + if (checkobj==elem || CheckEqual(checkobj,elem)) { - CValue* elem = GetValue(i); - if (CheckEqual(checkobj,elem)) - { - numfound ++; - } + numfound ++; } - checkobj->Release(); } + checkobj->Release(); - return PyInt_FromLong(numfound); + return PyLong_FromSsize_t(numfound); +} + +/* Matches python dict.get(key, [default]) */ +PyObject* CListValue::Pyget(PyObject *args) +{ + char *key; + PyObject* def = Py_None; + + if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) + return NULL; + + CValue *item = FindValue((const char *)key); + if (item) { + PyObject* pyobj = item->ConvertValueToPython(); + if (pyobj) + return pyobj; + else + return item->GetProxy(); + } + Py_INCREF(def); + return def; } +PyObject* CListValue::Pyfrom_id(PyObject* value) +{ + uintptr_t id= (uintptr_t)PyLong_AsVoidPtr(value); + + if (PyErr_Occurred()) + return NULL; + + int numelem = GetCount(); + for (int i=0;i<numelem;i++) + { + if (reinterpret_cast<uintptr_t>(m_pValueArray[i]->m_proxy) == id) + return GetValue(i)->GetProxy(); + } + PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in CValueList"); + return NULL; + +} + /* --------------------------------------------------------------------- * Some stuff taken from the header * --------------------------------------------------------------------- */ CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val) { - assert(false); // todo: implement me! + //assert(false); // todo: implement me! + static int error_printed = 0; + if (error_printed==0) { + fprintf(stderr, "CValueList::Calc not yet implimented\n"); + error_printed = 1; + } return NULL; } - - CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue* val) { - assert(false); // todo: implement me! + //assert(false); // todo: implement me! + static int error_printed = 0; + if (error_printed==0) { + fprintf(stderr, "CValueList::CalcFinal not yet implimented\n"); + error_printed = 1; + } return NULL; } @@ -534,7 +649,7 @@ void CListValue::Add(CValue* value) -float CListValue::GetNumber() +double CListValue::GetNumber() { return -1; } diff --git a/source/gameengine/Expressions/ListValue.h b/source/gameengine/Expressions/ListValue.h index 431f8f558a9..2dc458e0148 100644 --- a/source/gameengine/Expressions/ListValue.h +++ b/source/gameengine/Expressions/ListValue.h @@ -24,7 +24,7 @@ class CListValue : public CPropValue //PLUGIN_DECLARE_SERIAL (CListValue,CValue) public: - CListValue(PyTypeObject *T = &Type); + CListValue(); virtual ~CListValue(); void AddConfigurationData(CValue* menuvalue); @@ -36,7 +36,7 @@ public: virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue* val); - virtual float GetNumber(); + virtual double GetNumber(); virtual CValue* GetReplica(); public: @@ -46,6 +46,7 @@ public: bool SearchValue(CValue* val); CValue* FindValue(const STR_String & name); + CValue* FindValue(const char *name); void ReleaseAndRemoveAll(); virtual void SetModified(bool bModified); @@ -59,12 +60,21 @@ public: bool CheckEqual(CValue* first,CValue* second); - virtual PyObject* _getattr(const STR_String& attr); + virtual PyObject* py_repr(void) { + PyObject *py_proxy= this->GetProxy(); + PyObject *py_list= PySequence_List(py_proxy); + PyObject *py_string= PyObject_Repr(py_list); + Py_DECREF(py_list); + Py_DECREF(py_proxy); + return py_string; + } - KX_PYMETHOD(CListValue,append); - KX_PYMETHOD(CListValue,reverse); - KX_PYMETHOD(CListValue,index); - KX_PYMETHOD(CListValue,count); + KX_PYMETHOD_O(CListValue,append); + KX_PYMETHOD_NOARGS(CListValue,reverse); + KX_PYMETHOD_O(CListValue,index); + KX_PYMETHOD_O(CListValue,count); + KX_PYMETHOD_VARARGS(CListValue,get); + KX_PYMETHOD_O(CListValue,from_id); private: diff --git a/source/gameengine/Expressions/Makefile b/source/gameengine/Expressions/Makefile index 6736149bbcd..09512c3ae87 100644 --- a/source/gameengine/Expressions/Makefile +++ b/source/gameengine/Expressions/Makefile @@ -37,8 +37,10 @@ CCFLAGS += $(LEVEL_1_CPP_WARNINGS) CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) CPPFLAGS += -I../../blender/makesdna +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I../../kernel/gen_system +CPPFLAGS += -I../../gameengine/SceneGraph diff --git a/source/gameengine/Expressions/Operator1Expr.h b/source/gameengine/Expressions/Operator1Expr.h index 4a1deb0eca3..c2bc68076a0 100644 --- a/source/gameengine/Expressions/Operator1Expr.h +++ b/source/gameengine/Expressions/Operator1Expr.h @@ -46,6 +46,13 @@ public: private: VALUE_OPERATOR m_op; CExpression * m_lhs; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:COperator1Expr"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined(AFX_OPERATOR1EXPR_H__A1653901_BF41_11D1_A51C_00A02472FC58__INCLUDED_) diff --git a/source/gameengine/Expressions/Operator2Expr.h b/source/gameengine/Expressions/Operator2Expr.h index 4064890bbae..bb26b7c03be 100644 --- a/source/gameengine/Expressions/Operator2Expr.h +++ b/source/gameengine/Expressions/Operator2Expr.h @@ -52,7 +52,13 @@ protected: private: VALUE_OPERATOR m_op; - + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:COperator2Expr"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined _OPERATOR2EXPR_H diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index 1eca527151a..1d1d9e6103b 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -50,130 +50,929 @@ #include "stdlib.h" #include "PyObjectPlus.h" #include "STR_String.h" +#include "MT_Vector3.h" /*------------------------------ * PyObjectPlus Type -- Every class, even the abstract one should have a Type ------------------------------*/ + PyTypeObject PyObjectPlus::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /*ob_size*/ + PyVarObject_HEAD_INIT(NULL, 0) "PyObjectPlus", /*tp_name*/ - sizeof(PyObjectPlus), /*tp_basicsize*/ + sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ - PyDestructor, /*tp_dealloc*/ - 0, /*tp_print*/ - __getattr, /*tp_getattr*/ - __setattr, /*tp_setattr*/ - 0, /*tp_compare*/ - __repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call */ + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + NULL // no subtype }; + PyObjectPlus::~PyObjectPlus() { - if (ob_refcnt) - { - _Py_ForgetReference(this); + if(m_proxy) { + BGE_PROXY_REF(m_proxy)= NULL; + Py_DECREF(m_proxy); /* Remove own reference, python may still have 1 */ } // assert(ob_refcnt==0); } -PyObjectPlus::PyObjectPlus(PyTypeObject *T) // constructor + +PyObject *PyObjectPlus::py_base_repr(PyObject *self) // This should be the entry in Type. +{ + PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if(self_plus==NULL) { + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); + return NULL; + } + + return self_plus->py_repr(); +} + + +PyObject * PyObjectPlus::py_base_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyTypeObject *base_type; + PyObjectPlus_Proxy *base = NULL; + + if (!PyArg_ParseTuple(args, "O:Base PyObjectPlus", &base)) + return NULL; + + /* the 'base' PyObject may be subclassed (multiple times even) + * we need to find the first C++ defined class to check 'type' + * is a subclass of the base arguments type. + * + * This way we can share one tp_new function for every PyObjectPlus + * + * eg. + * + * # CustomOb is called 'type' in this C code + * class CustomOb(GameTypes.KX_GameObject): + * pass + * + * # this calls py_base_new(...), the type of 'CustomOb' is checked to be a subclass of the 'cont.owner' type + * ob = CustomOb(cont.owner) + * + * */ + base_type= Py_TYPE(base); + while(base_type && !BGE_PROXY_CHECK_TYPE(base_type)) + base_type= base_type->tp_base; + + if(base_type==NULL || !BGE_PROXY_CHECK_TYPE(base_type)) { + PyErr_SetString(PyExc_TypeError, "can't subclass from a blender game type because the argument given is not a game class or subclass"); + return NULL; + } + + /* use base_type rather then Py_TYPE(base) because we could alredy be subtyped */ + if(!PyType_IsSubtype(type, base_type)) { + PyErr_Format(PyExc_TypeError, "can't subclass blender game type <%s> from <%s> because it is not a subclass", base_type->tp_name, type->tp_name); + return NULL; + } + + /* invalidate the existing base and return a new subclassed one, + * this is a bit dodgy in that it also attaches its self to the existing object + * which is not really 'correct' python OO but for our use its OK. */ + + PyObjectPlus_Proxy *ret = (PyObjectPlus_Proxy *) type->tp_alloc(type, 0); /* starts with 1 ref, used for the return ref' */ + ret->ref= base->ref; + base->ref= NULL; /* invalidate! disallow further access */ + + ret->py_owns= base->py_owns; + + ret->ref->m_proxy= NULL; + + /* 'base' may be free'd after this func finished but not necessarily + * there is no reference to the BGE data now so it will throw an error on access */ + Py_DECREF(base); + + ret->ref->m_proxy= (PyObject *)ret; /* no need to add a ref because one is added when creating. */ + Py_INCREF(ret); /* we return a new ref but m_proxy holds a ref so we need to add one */ + + + /* 'ret' will have 2 references. + * - One ref is needed because ret->ref->m_proxy holds a refcount to the current proxy. + * - Another is needed for returning the value. + * + * So we should be ok with 2 refs, but for some reason this crashes. so adding a new ref... + * */ + + return (PyObject *)ret; +} + +void PyObjectPlus::py_base_dealloc(PyObject *self) // python wrapper { - MT_assert(T != NULL); - this->ob_type = T; - _Py_NewReference(this); + PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if(self_plus) { + if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it */ + self_plus->m_proxy = NULL; /* Need this to stop ~PyObjectPlus from decrefing m_proxy otherwise its decref'd twice and py-debug crashes */ + delete self_plus; + } + + BGE_PROXY_REF(self)= NULL; // not really needed + } + +#if 0 + /* is ok normally but not for subtyping, use tp_free instead. */ + PyObject_DEL( self ); +#else + Py_TYPE(self)->tp_free(self); +#endif }; - + +PyObjectPlus::PyObjectPlus() : SG_QList() // constructor +{ + m_proxy= NULL; +}; + /*------------------------------ * PyObjectPlus Methods -- Every class, even the abstract one should have a Methods ------------------------------*/ PyMethodDef PyObjectPlus::Methods[] = { - {"isA", (PyCFunction) sPy_isA, METH_VARARGS}, {NULL, NULL} /* Sentinel */ }; -/*------------------------------ - * PyObjectPlus Parents -- Every class, even the abstract one should have parents -------------------------------*/ -PyParentObject PyObjectPlus::Parents[] = {&PyObjectPlus::Type, NULL}; +#define attr_invalid (&(PyObjectPlus::Attributes[0])) +PyAttributeDef PyObjectPlus::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("invalid", PyObjectPlus, pyattr_get_invalid), + {NULL} //Sentinel +}; -/*------------------------------ - * PyObjectPlus attributes -- attributes -------------------------------*/ -PyObject *PyObjectPlus::_getattr(const STR_String& attr) -{ - if (attr == "__doc__" && GetType()->tp_doc) - return PyString_FromString(GetType()->tp_doc); - //if (streq(attr, "type")) - // return Py_BuildValue("s", (*(GetParents()))->tp_name); - return Py_FindMethod(Methods, this, const_cast<char *>(attr.ReadPtr())); +PyObject* PyObjectPlus::pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + return PyBool_FromLong(self_v ? 1:0); } -int PyObjectPlus::_delattr(const STR_String& attr) +/* note, this is called as a python 'getset, where the PyAttributeDef is the closure */ +PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef) { - PyErr_SetString(PyExc_AttributeError, "attribute cant be deleted"); - return 1; + void *self= (void *)(BGE_PROXY_REF(self_py)); + if(self==NULL) { + if(attrdef == attr_invalid) + Py_RETURN_TRUE; // dont bother running the function + + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); + return NULL; + } + + + if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY) + { + // fake attribute, ignore + return NULL; + } + if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_FUNCTION) + { + // the attribute has no field correspondance, handover processing to function. + if (attrdef->m_getFunction == NULL) + return NULL; + return (*attrdef->m_getFunction)(self, attrdef); + } + char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset; + if (attrdef->m_length > 1) + { + PyObject* resultlist = PyList_New(attrdef->m_length); + for (unsigned int i=0; i<attrdef->m_length; i++) + { + switch (attrdef->m_type) { + case KX_PYATTRIBUTE_TYPE_BOOL: + { + bool *val = reinterpret_cast<bool*>(ptr); + ptr += sizeof(bool); + PyList_SET_ITEM(resultlist,i,PyLong_FromSsize_t(*val)); + break; + } + case KX_PYATTRIBUTE_TYPE_SHORT: + { + short int *val = reinterpret_cast<short int*>(ptr); + ptr += sizeof(short int); + PyList_SET_ITEM(resultlist,i,PyLong_FromSsize_t(*val)); + break; + } + case KX_PYATTRIBUTE_TYPE_ENUM: + // enum are like int, just make sure the field size is the same + if (sizeof(int) != attrdef->m_size) + { + Py_DECREF(resultlist); + return NULL; + } + // walkthrough + case KX_PYATTRIBUTE_TYPE_INT: + { + int *val = reinterpret_cast<int*>(ptr); + ptr += sizeof(int); + PyList_SET_ITEM(resultlist,i,PyLong_FromSsize_t(*val)); + break; + } + case KX_PYATTRIBUTE_TYPE_FLOAT: + { + float *val = reinterpret_cast<float*>(ptr); + ptr += sizeof(float); + PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble(*val)); + break; + } + default: + // no support for array of complex data + Py_DECREF(resultlist); + return NULL; + } + } + return resultlist; + } + else + { + switch (attrdef->m_type) { + case KX_PYATTRIBUTE_TYPE_BOOL: + { + bool *val = reinterpret_cast<bool*>(ptr); + return PyLong_FromSsize_t(*val); + } + case KX_PYATTRIBUTE_TYPE_SHORT: + { + short int *val = reinterpret_cast<short int*>(ptr); + return PyLong_FromSsize_t(*val); + } + case KX_PYATTRIBUTE_TYPE_ENUM: + // enum are like int, just make sure the field size is the same + if (sizeof(int) != attrdef->m_size) + { + return NULL; + } + // walkthrough + case KX_PYATTRIBUTE_TYPE_INT: + { + int *val = reinterpret_cast<int*>(ptr); + return PyLong_FromSsize_t(*val); + } + case KX_PYATTRIBUTE_TYPE_FLOAT: + { + float *val = reinterpret_cast<float*>(ptr); + return PyFloat_FromDouble(*val); + } + case KX_PYATTRIBUTE_TYPE_VECTOR: + { + MT_Vector3 *val = reinterpret_cast<MT_Vector3*>(ptr); +#ifdef USE_MATHUTILS + float fval[3]= {(*val)[0], (*val)[1], (*val)[2]}; + return newVectorObject(fval, 3, Py_NEW, NULL); +#else + PyObject* resultlist = PyList_New(3); + for (unsigned int i=0; i<3; i++) + { + PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble((*val)[i])); + } + return resultlist; +#endif + } + case KX_PYATTRIBUTE_TYPE_STRING: + { + STR_String *val = reinterpret_cast<STR_String*>(ptr); + return PyUnicode_FromString(*val); + } + default: + return NULL; + } + } } -int PyObjectPlus::_setattr(const STR_String& attr, PyObject *value) +/* note, this is called as a python getset */ +int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef) { - //return PyObject::_setattr(attr,value); - //cerr << "Unknown attribute" << endl; - PyErr_SetString(PyExc_AttributeError, "attribute cant be set"); - return 1; + void *self= (void *)(BGE_PROXY_REF(self_py)); + if(self==NULL) { + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); + return PY_SET_ATTR_FAIL; + } + + void *undoBuffer = NULL; + void *sourceBuffer = NULL; + size_t bufferSize = 0; + + char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset; + if (attrdef->m_length > 1) + { + if (!PySequence_Check(value)) + { + PyErr_Format(PyExc_TypeError, "expected a sequence for attribute \"%s\"", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + if (PySequence_Size(value) != attrdef->m_length) + { + PyErr_Format(PyExc_TypeError, "incorrect number of elements in sequence for attribute \"%s\"", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + switch (attrdef->m_type) + { + case KX_PYATTRIBUTE_TYPE_FUNCTION: + if (attrdef->m_setFunction == NULL) + { + PyErr_Format(PyExc_AttributeError, "function attribute without function for attribute \"%s\", report to blender.org", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + return (*attrdef->m_setFunction)(self, attrdef, value); + case KX_PYATTRIBUTE_TYPE_BOOL: + bufferSize = sizeof(bool); + break; + case KX_PYATTRIBUTE_TYPE_SHORT: + bufferSize = sizeof(short int); + break; + case KX_PYATTRIBUTE_TYPE_ENUM: + case KX_PYATTRIBUTE_TYPE_INT: + bufferSize = sizeof(int); + break; + case KX_PYATTRIBUTE_TYPE_FLOAT: + bufferSize = sizeof(float); + break; + default: + // should not happen + PyErr_Format(PyExc_AttributeError, "Unsupported attribute type for attribute \"%s\", report to blender.org", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + // let's implement a smart undo method + bufferSize *= attrdef->m_length; + undoBuffer = malloc(bufferSize); + sourceBuffer = ptr; + if (undoBuffer) + { + memcpy(undoBuffer, sourceBuffer, bufferSize); + } + for (int i=0; i<attrdef->m_length; i++) + { + PyObject *item = PySequence_GetItem(value, i); /* new ref */ + // we can decrement the reference immediately, the reference count + // is at least 1 because the item is part of an array + Py_DECREF(item); + switch (attrdef->m_type) + { + case KX_PYATTRIBUTE_TYPE_BOOL: + { + bool *var = reinterpret_cast<bool*>(ptr); + ptr += sizeof(bool); + if (PyLong_Check(item)) + { + *var = (PyLong_AsSsize_t(item) != 0); + } + else if (PyBool_Check(item)) + { + *var = (item == Py_True); + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name); + goto UNDO_AND_ERROR; + } + break; + } + case KX_PYATTRIBUTE_TYPE_SHORT: + { + short int *var = reinterpret_cast<short int*>(ptr); + ptr += sizeof(short int); + if (PyLong_Check(item)) + { + long val = PyLong_AsSsize_t(item); + if (attrdef->m_clamp) + { + if (val < attrdef->m_imin) + val = attrdef->m_imin; + else if (val > attrdef->m_imax) + val = attrdef->m_imax; + } + else if (val < attrdef->m_imin || val > attrdef->m_imax) + { + PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name); + goto UNDO_AND_ERROR; + } + *var = (short int)val; + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); + goto UNDO_AND_ERROR; + } + break; + } + case KX_PYATTRIBUTE_TYPE_ENUM: + // enum are equivalent to int, just make sure that the field size matches: + if (sizeof(int) != attrdef->m_size) + { + PyErr_Format(PyExc_AttributeError, "Size check error for attribute, \"%s\", report to blender.org", attrdef->m_name); + goto UNDO_AND_ERROR; + } + // walkthrough + case KX_PYATTRIBUTE_TYPE_INT: + { + int *var = reinterpret_cast<int*>(ptr); + ptr += sizeof(int); + if (PyLong_Check(item)) + { + long val = PyLong_AsSsize_t(item); + if (attrdef->m_clamp) + { + if (val < attrdef->m_imin) + val = attrdef->m_imin; + else if (val > attrdef->m_imax) + val = attrdef->m_imax; + } + else if (val < attrdef->m_imin || val > attrdef->m_imax) + { + PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name); + goto UNDO_AND_ERROR; + } + *var = (int)val; + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); + goto UNDO_AND_ERROR; + } + break; + } + case KX_PYATTRIBUTE_TYPE_FLOAT: + { + float *var = reinterpret_cast<float*>(ptr); + ptr += sizeof(float); + double val = PyFloat_AsDouble(item); + if (val == -1.0 && PyErr_Occurred()) + { + PyErr_Format(PyExc_TypeError, "expected a float for attribute \"%s\"", attrdef->m_name); + goto UNDO_AND_ERROR; + } + else if (attrdef->m_clamp) + { + if (val < attrdef->m_fmin) + val = attrdef->m_fmin; + else if (val > attrdef->m_fmax) + val = attrdef->m_fmax; + } + else if (val < attrdef->m_fmin || val > attrdef->m_fmax) + { + PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name); + goto UNDO_AND_ERROR; + } + *var = (float)val; + break; + } + default: + // should not happen + PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", report to blender.org", attrdef->m_name); + goto UNDO_AND_ERROR; + } + } + // no error, call check function if any + if (attrdef->m_checkFunction != NULL) + { + if ((*attrdef->m_checkFunction)(self, attrdef) != 0) + { + // if the checing function didnt set an error then set a generic one here so we dont set an error with no exception + if (PyErr_Occurred()==0) + PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", reasion unknown", attrdef->m_name); + + // post check returned an error, restore values + UNDO_AND_ERROR: + if (undoBuffer) + { + memcpy(sourceBuffer, undoBuffer, bufferSize); + free(undoBuffer); + } + return PY_SET_ATTR_FAIL; + } + } + if (undoBuffer) + free(undoBuffer); + return PY_SET_ATTR_SUCCESS; + } + else // simple attribute value + { + if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_FUNCTION) + { + if (attrdef->m_setFunction == NULL) + { + PyErr_Format(PyExc_AttributeError, "function attribute without function \"%s\", report to blender.org", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + return (*attrdef->m_setFunction)(self, attrdef, value); + } + if (attrdef->m_checkFunction != NULL || attrdef->m_type == KX_PYATTRIBUTE_TYPE_VECTOR) + { + // post check function is provided, prepare undo buffer + sourceBuffer = ptr; + switch (attrdef->m_type) + { + case KX_PYATTRIBUTE_TYPE_BOOL: + bufferSize = sizeof(bool); + break; + case KX_PYATTRIBUTE_TYPE_SHORT: + bufferSize = sizeof(short); + break; + case KX_PYATTRIBUTE_TYPE_ENUM: + case KX_PYATTRIBUTE_TYPE_INT: + bufferSize = sizeof(int); + break; + case KX_PYATTRIBUTE_TYPE_FLOAT: + bufferSize = sizeof(float); + break; + case KX_PYATTRIBUTE_TYPE_STRING: + sourceBuffer = reinterpret_cast<STR_String*>(ptr)->Ptr(); + if (sourceBuffer) + bufferSize = strlen(reinterpret_cast<char*>(sourceBuffer))+1; + break; + case KX_PYATTRIBUTE_TYPE_VECTOR: + bufferSize = sizeof(MT_Vector3); + break; + default: + PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + if (bufferSize) + { + undoBuffer = malloc(bufferSize); + if (undoBuffer) + { + memcpy(undoBuffer, sourceBuffer, bufferSize); + } + } + } + + switch (attrdef->m_type) + { + case KX_PYATTRIBUTE_TYPE_BOOL: + { + bool *var = reinterpret_cast<bool*>(ptr); + if (PyLong_Check(value)) + { + *var = (PyLong_AsSsize_t(value) != 0); + } + else if (PyBool_Check(value)) + { + *var = (value == Py_True); + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + break; + } + case KX_PYATTRIBUTE_TYPE_SHORT: + { + short int *var = reinterpret_cast<short int*>(ptr); + if (PyLong_Check(value)) + { + long val = PyLong_AsSsize_t(value); + if (attrdef->m_clamp) + { + if (val < attrdef->m_imin) + val = attrdef->m_imin; + else if (val > attrdef->m_imax) + val = attrdef->m_imax; + } + else if (val < attrdef->m_imin || val > attrdef->m_imax) + { + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + *var = (short int)val; + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + break; + } + case KX_PYATTRIBUTE_TYPE_ENUM: + // enum are equivalent to int, just make sure that the field size matches: + if (sizeof(int) != attrdef->m_size) + { + PyErr_Format(PyExc_AttributeError, "attribute size check error for attribute \"%s\", report to blender.org", attrdef->m_name); + goto FREE_AND_ERROR; + } + // walkthrough + case KX_PYATTRIBUTE_TYPE_INT: + { + int *var = reinterpret_cast<int*>(ptr); + if (PyLong_Check(value)) + { + long val = PyLong_AsSsize_t(value); + if (attrdef->m_clamp) + { + if (val < attrdef->m_imin) + val = attrdef->m_imin; + else if (val > attrdef->m_imax) + val = attrdef->m_imax; + } + else if (val < attrdef->m_imin || val > attrdef->m_imax) + { + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + *var = (int)val; + } + else + { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + break; + } + case KX_PYATTRIBUTE_TYPE_FLOAT: + { + float *var = reinterpret_cast<float*>(ptr); + double val = PyFloat_AsDouble(value); + if (val == -1.0 && PyErr_Occurred()) + { + PyErr_Format(PyExc_TypeError, "expected a float for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + else if (attrdef->m_clamp) + { + if (val < attrdef->m_fmin) + val = attrdef->m_fmin; + else if (val > attrdef->m_fmax) + val = attrdef->m_fmax; + } + else if (val < attrdef->m_fmin || val > attrdef->m_fmax) + { + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + *var = (float)val; + break; + } + case KX_PYATTRIBUTE_TYPE_VECTOR: + { + if (!PySequence_Check(value) || PySequence_Size(value) != 3) + { + PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + MT_Vector3 *var = reinterpret_cast<MT_Vector3*>(ptr); + for (int i=0; i<3; i++) + { + PyObject *item = PySequence_GetItem(value, i); /* new ref */ + // we can decrement the reference immediately, the reference count + // is at least 1 because the item is part of an array + Py_DECREF(item); + double val = PyFloat_AsDouble(item); + if (val == -1.0 && PyErr_Occurred()) + { + PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name); + goto RESTORE_AND_ERROR; + } + else if (attrdef->m_clamp) + { + if (val < attrdef->m_fmin) + val = attrdef->m_fmin; + else if (val > attrdef->m_fmax) + val = attrdef->m_fmax; + } + else if (val < attrdef->m_fmin || val > attrdef->m_fmax) + { + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); + goto RESTORE_AND_ERROR; + } + (*var)[i] = (MT_Scalar)val; + } + break; + } + case KX_PYATTRIBUTE_TYPE_STRING: + { + STR_String *var = reinterpret_cast<STR_String*>(ptr); + if (PyUnicode_Check(value)) + { + Py_ssize_t val_len; + char *val = _PyUnicode_AsStringAndSize(value, &val_len); + if (attrdef->m_clamp) + { + if (val_len < attrdef->m_imin) + { + // can't increase the length of the string + PyErr_Format(PyExc_ValueError, "string length too short for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + else if (val_len > attrdef->m_imax) + { + // trim the string + char c = val[attrdef->m_imax]; + val[attrdef->m_imax] = 0; + *var = val; + val[attrdef->m_imax] = c; + break; + } + } else if (val_len < attrdef->m_imin || val_len > attrdef->m_imax) + { + PyErr_Format(PyExc_ValueError, "string length out of range for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + *var = val; + } + else + { + PyErr_Format(PyExc_TypeError, "expected a string for attribute \"%s\"", attrdef->m_name); + goto FREE_AND_ERROR; + } + break; + } + default: + // should not happen + PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name); + goto FREE_AND_ERROR; + } + } + // check if post processing is needed + if (attrdef->m_checkFunction != NULL) + { + if ((*attrdef->m_checkFunction)(self, attrdef) != 0) + { + // restore value + RESTORE_AND_ERROR: + if (undoBuffer) + { + if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_STRING) + { + // special case for STR_String: restore the string + STR_String *var = reinterpret_cast<STR_String*>(ptr); + *var = reinterpret_cast<char*>(undoBuffer); + } + else + { + // other field type have direct values + memcpy(ptr, undoBuffer, bufferSize); + } + } + FREE_AND_ERROR: + if (undoBuffer) + free(undoBuffer); + return 1; + } + } + if (undoBuffer) + free(undoBuffer); + return 0; } + + /*------------------------------ * PyObjectPlus repr -- representations ------------------------------*/ -PyObject *PyObjectPlus::_repr(void) +PyObject *PyObjectPlus::py_repr(void) { PyErr_SetString(PyExc_SystemError, "Representation not overridden by object."); return NULL; } -/*------------------------------ - * PyObjectPlus isA -- the isA functions -------------------------------*/ -bool PyObjectPlus::isA(PyTypeObject *T) // if called with a Type, use "typename" +void PyObjectPlus::ProcessReplica() { - return isA(T->tp_name); + /* Clear the proxy, will be created again if needed with GetProxy() + * otherwise the PyObject will point to the wrong reference */ + m_proxy= NULL; } +/* Sometimes we might want to manually invalidate a BGE type even if + * it hasnt been released by the BGE, say for example when an object + * is removed from a scene, accessing it may cause problems. + * + * In this case the current proxy is made invalid, disowned, + * and will raise an error on access. However if python can get access + * to this class again it will make a new proxy and work as expected. + */ +void PyObjectPlus::InvalidateProxy() // check typename of each parent +{ + if(m_proxy) { + BGE_PROXY_REF(m_proxy)=NULL; + Py_DECREF(m_proxy); + m_proxy= NULL; + } +} -bool PyObjectPlus::isA(const char *mytypename) // check typename of each parent +PyObject *PyObjectPlus::GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp) { - int i; - PyParentObject P; - PyParentObject *Ps = GetParents(); - - for (P = Ps[i=0]; P != NULL; P = Ps[i++]) - { - if (STR_String(P->tp_name) == STR_String(mytypename) ) - return true; - } + if (self->m_proxy==NULL) + { + self->m_proxy = reinterpret_cast<PyObject *>PyObject_NEW( PyObjectPlus_Proxy, tp); + BGE_PROXY_PYOWNS(self->m_proxy) = false; + } + //PyObject_Print(self->m_proxy, stdout, 0); + //printf("ref %d\n", self->m_proxy->ob_refcnt); - return false; + BGE_PROXY_REF(self->m_proxy) = self; /* Its possible this was set to NULL, so set it back here */ + Py_INCREF(self->m_proxy); /* we own one, thos ones fore the return */ + return self->m_proxy; } -PyObject *PyObjectPlus::Py_isA(PyObject *args) // Python wrapper for isA +PyObject *PyObjectPlus::NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool py_owns) { - char *mytypename; - if (!PyArg_ParseTuple(args, "s", &mytypename)) - return NULL; - if(isA(mytypename)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; + if (self->m_proxy) + { + if(py_owns) + { /* Free */ + BGE_PROXY_REF(self->m_proxy) = NULL; + Py_DECREF(self->m_proxy); + self->m_proxy= NULL; + } + else { + Py_INCREF(self->m_proxy); + return self->m_proxy; + } + + } + + GetProxy_Ext(self, tp); + if(py_owns) { + BGE_PROXY_PYOWNS(self->m_proxy) = py_owns; + Py_DECREF(self->m_proxy); /* could avoid thrashing here but for now its ok */ + } + return self->m_proxy; } +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// +/* deprecation warning management */ + +bool PyObjectPlus::m_ignore_deprecation_warnings(false); +void PyObjectPlus::SetDeprecationWarnings(bool ignoreDeprecationWarnings) +{ + m_ignore_deprecation_warnings = ignoreDeprecationWarnings; +} + +void PyDebugLine() +{ + // import sys; print '\t%s:%d' % (sys._getframe(0).f_code.co_filename, sys._getframe(0).f_lineno) + + PyObject *getframe, *frame; + PyObject *f_lineno, *f_code, *co_filename; + + getframe = PySys_GetObject((char *)"_getframe"); // borrowed + if (getframe) { + frame = PyObject_CallObject(getframe, NULL); + if (frame) { + f_lineno= PyObject_GetAttrString(frame, "f_lineno"); + f_code= PyObject_GetAttrString(frame, "f_code"); + if (f_lineno && f_code) { + co_filename= PyObject_GetAttrString(f_code, "co_filename"); + if (co_filename) { + + printf("\t%s:%d\n", _PyUnicode_AsString(co_filename), (int)PyLong_AsSsize_t(f_lineno)); + + Py_DECREF(f_lineno); + Py_DECREF(f_code); + Py_DECREF(co_filename); + Py_DECREF(frame); + return; + } + } + + Py_XDECREF(f_lineno); + Py_XDECREF(f_code); + Py_DECREF(frame); + } + + } + PyErr_Clear(); + printf("\tERROR - Could not access sys._getframe(0).f_lineno or sys._getframe().f_code.co_filename\n"); +} + +void PyObjectPlus::ShowDeprecationWarning_func(const char* old_way,const char* new_way) +{ + printf("Method %s is deprecated, please use %s instead.\n", old_way, new_way); + PyDebugLine(); +} + +void PyObjectPlus::ClearDeprecationWarning() +{ + WarnLink *wlink_next; + WarnLink *wlink = GetDeprecationWarningLinkFirst(); + + while(wlink) + { + wlink->warn_done= false; /* no need to NULL the link, its cleared before adding to the list next time round */ + wlink_next= reinterpret_cast<WarnLink *>(wlink->link); + wlink->link= NULL; + wlink= wlink_next; + } + NullDeprecationWarning(); +} + +WarnLink* m_base_wlink_first= NULL; +WarnLink* m_base_wlink_last= NULL; + +WarnLink* PyObjectPlus::GetDeprecationWarningLinkFirst(void) {return m_base_wlink_first;} +WarnLink* PyObjectPlus::GetDeprecationWarningLinkLast(void) {return m_base_wlink_last;} +void PyObjectPlus::SetDeprecationWarningFirst(WarnLink* wlink) {m_base_wlink_first= wlink;} +void PyObjectPlus::SetDeprecationWarningLinkLast(WarnLink* wlink) {m_base_wlink_last= wlink;} +void PyObjectPlus::NullDeprecationWarning() {m_base_wlink_first= m_base_wlink_last= NULL;} + #endif //NO_EXP_PYTHON_EMBEDDING diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index 3a054454a0b..f9edb7877b0 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -38,142 +38,164 @@ #include "KX_Python.h" #include "STR_String.h" +#include "MT_Vector3.h" +#include "SG_QList.h" /*------------------------------ * Python defines ------------------------------*/ -/* - Py_RETURN_NONE - Python 2.4 macro. - defined here until we switch to 2.4 - also in api2_2x/gen_utils.h -*/ -#ifndef Py_RETURN_NONE -#define Py_RETURN_NONE return Py_BuildValue("O", Py_None) -#endif -#ifndef Py_RETURN_FALSE -#define Py_RETURN_FALSE return PyBool_FromLong(0) -#endif -#ifndef Py_RETURN_TRUE -#define Py_RETURN_TRUE return PyBool_FromLong(1) -#endif - -/* for pre Py 2.5 */ -#if PY_VERSION_HEX < 0x02050000 -typedef int Py_ssize_t; -#define PY_SSIZE_T_MAX INT_MAX -#define PY_SSIZE_T_MIN INT_MIN -#define PY_METHODCHAR char * -#else -/* Py 2.5 and later */ -#define intargfunc ssizeargfunc -#define intintargfunc ssizessizeargfunc -#define PY_METHODCHAR const char * +#ifdef USE_MATHUTILS +extern "C" { +#include "../../blender/python/generic/Mathutils.h" /* so we can have mathutils callbacks */ +} #endif - // some basic python macros -#define Py_Return { Py_INCREF(Py_None); return Py_None;} - static inline void Py_Fatal(const char *M) { - //cout << M << endl; + fprintf(stderr, "%s\n", M); exit(-1); }; + +/* Use with ShowDeprecationWarning macro */ +typedef struct { + bool warn_done; + void *link; +} WarnLink; + +#define ShowDeprecationWarning(old_way, new_way) \ +{ \ + static WarnLink wlink = {false, NULL}; \ + if ((m_ignore_deprecation_warnings || wlink.warn_done)==0) \ + { \ + ShowDeprecationWarning_func(old_way, new_way); \ + \ + WarnLink *wlink_last= GetDeprecationWarningLinkLast(); \ + wlink.warn_done = true; \ + wlink.link = NULL; \ + \ + if(wlink_last) { \ + wlink_last->link= (void *)&(wlink); \ + SetDeprecationWarningLinkLast(&(wlink)); \ + } else { \ + SetDeprecationWarningFirst(&(wlink)); \ + SetDeprecationWarningLinkLast(&(wlink)); \ + } \ + } \ +} \ + + + +typedef struct PyObjectPlus_Proxy { + PyObject_HEAD /* required python macro */ + class PyObjectPlus *ref; + bool py_owns; +} PyObjectPlus_Proxy; + +#define BGE_PROXY_ERROR_MSG "Blender Game Engine data has been freed, cannot use this python variable" +#define BGE_PROXY_REF(_self) (((PyObjectPlus_Proxy *)_self)->ref) +#define BGE_PROXY_PYOWNS(_self) (((PyObjectPlus_Proxy *)_self)->py_owns) + +/* Note, sometimes we dont care what BGE type this is as long as its a proxy */ +#define BGE_PROXY_CHECK_TYPE(_type) ((_type)->tp_dealloc == PyObjectPlus::py_base_dealloc) + +/* Opposite of BGE_PROXY_REF */ +#define BGE_PROXY_FROM_REF(_self) (((PyObjectPlus *)_self)->GetProxy()) + + // This must be the first line of each // PyC++ class -#define Py_Header \ +#define __Py_Header \ public: \ static PyTypeObject Type; \ static PyMethodDef Methods[]; \ - static PyParentObject Parents[]; \ + static PyAttributeDef Attributes[]; \ virtual PyTypeObject *GetType(void) {return &Type;}; \ - virtual PyParentObject *GetParents(void) {return Parents;} - - - // This defines the _getattr_up macro - // which allows attribute and method calls - // to be properly passed up the hierarchy. -#define _getattr_up(Parent) \ - PyObject *rvalue = NULL; \ - if (attr=="__methods__") { \ - PyObject *_attr_string = NULL; \ - PyMethodDef *meth = Methods; \ - rvalue = Parent::_getattr(attr); \ - if (rvalue==NULL) { \ - PyErr_Clear(); \ - rvalue = PyList_New(0); \ - } \ - if (meth) { \ - for (; meth->ml_name != NULL; meth++) { \ - _attr_string = PyString_FromString(meth->ml_name); \ - PyList_Append(rvalue, _attr_string); \ - Py_DECREF(_attr_string); \ - } \ - } \ - } else { \ - rvalue = Py_FindMethod(Methods, this, const_cast<char*>(attr.ReadPtr())); \ - if (rvalue == NULL) { \ - PyErr_Clear(); \ - rvalue = Parent::_getattr(attr); \ - } \ - } \ - return rvalue; \ + virtual PyObject *GetProxy() {return GetProxy_Ext(this, &Type);}; \ + virtual PyObject *NewProxy(bool py_owns) {return NewProxy_Ext(this, &Type, py_owns);}; \ + +#ifdef WITH_CXX_GUARDEDALLOC +#define Py_Header __Py_Header \ + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, Type.tp_name); } \ + void operator delete( void *mem ) { MEM_freeN(mem); } \ + +#else +#define Py_Header __Py_Header +#endif + +/* + * nonzero values are an error for setattr + * however because of the nested lookups we need to know if the errors + * was because the attribute didnt exits of if there was some problem setting the value + */ + +#define PY_SET_ATTR_COERCE_FAIL 2 +#define PY_SET_ATTR_FAIL 1 +#define PY_SET_ATTR_MISSING -1 +#define PY_SET_ATTR_SUCCESS 0 /** * These macros are helpfull when embedding Python routines. The second * macro is one that also requires a documentation string */ #define KX_PYMETHOD(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self, PyObject* args, PyObject* kwds); \ + PyObject* Py##method_name(PyObject* args, PyObject* kwds); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \ - return ((class_name*) self)->Py##method_name(self, args, kwds); \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "() - " BGE_PROXY_ERROR_MSG); return NULL; } \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(args, kwds); \ }; \ #define KX_PYMETHOD_VARARGS(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self, PyObject* args); \ + PyObject* Py##method_name(PyObject* args); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args) { \ - return ((class_name*) self)->Py##method_name(self, args); \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "() - " BGE_PROXY_ERROR_MSG); return NULL; } \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(args); \ }; \ #define KX_PYMETHOD_NOARGS(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self); \ + PyObject* Py##method_name(); \ static PyObject* sPy##method_name( PyObject* self) { \ - return ((class_name*) self)->Py##method_name(self); \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "() - " BGE_PROXY_ERROR_MSG); return NULL; } \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(); \ }; \ #define KX_PYMETHOD_O(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self, PyObject* value); \ + PyObject* Py##method_name(PyObject* value); \ static PyObject* sPy##method_name( PyObject* self, PyObject* value) { \ - return ((class_name*) self)->Py##method_name(self, value); \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "(value) - " BGE_PROXY_ERROR_MSG); return NULL; } \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(value); \ }; \ #define KX_PYMETHOD_DOC(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self, PyObject* args, PyObject* kwds); \ + PyObject* Py##method_name(PyObject* args, PyObject* kwds); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \ - return ((class_name*) self)->Py##method_name(self, args, kwds); \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "(...) - " BGE_PROXY_ERROR_MSG); return NULL; } \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(args, kwds); \ }; \ static const char method_name##_doc[]; \ #define KX_PYMETHOD_DOC_VARARGS(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self, PyObject* args); \ + PyObject* Py##method_name(PyObject* args); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args) { \ - return ((class_name*) self)->Py##method_name(self, args); \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "(...) - " BGE_PROXY_ERROR_MSG); return NULL; } \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(args); \ }; \ static const char method_name##_doc[]; \ #define KX_PYMETHOD_DOC_O(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self, PyObject* value); \ + PyObject* Py##method_name(PyObject* value); \ static PyObject* sPy##method_name( PyObject* self, PyObject* value) { \ - return ((class_name*) self)->Py##method_name(self, value); \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "(value) - " BGE_PROXY_ERROR_MSG); return NULL; } \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(value); \ }; \ static const char method_name##_doc[]; \ #define KX_PYMETHOD_DOC_NOARGS(class_name, method_name) \ - PyObject* Py##method_name(PyObject* self); \ + PyObject* Py##method_name(); \ static PyObject* sPy##method_name( PyObject* self) { \ - return ((class_name*) self)->Py##method_name(self); \ + if(BGE_PROXY_REF(self)==NULL) { PyErr_SetString(PyExc_SystemError, #class_name "." #method_name "() - " BGE_PROXY_ERROR_MSG); return NULL; } \ + return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(); \ }; \ static const char method_name##_doc[]; \ @@ -183,80 +205,260 @@ static inline void Py_Fatal(const char *M) { * Method table macro (with doc) */ #define KX_PYMETHODTABLE(class_name, method_name) \ - {#method_name , (PyCFunction) class_name::sPy##method_name, METH_VARARGS, (PY_METHODCHAR)class_name::method_name##_doc} + {#method_name , (PyCFunction) class_name::sPy##method_name, METH_VARARGS, (const char *)class_name::method_name##_doc} + +#define KX_PYMETHODTABLE_O(class_name, method_name) \ + {#method_name , (PyCFunction) class_name::sPy##method_name, METH_O, (const char *)class_name::method_name##_doc} -#define KX_PYMETHODTABLE_NOARG(class_name, method_name) \ - {#method_name , (PyCFunction) class_name::sPy##method_name, METH_NOARGS, (PY_METHODCHAR)class_name::method_name##_doc} +#define KX_PYMETHODTABLE_NOARGS(class_name, method_name) \ + {#method_name , (PyCFunction) class_name::sPy##method_name, METH_NOARGS, (const char *)class_name::method_name##_doc} /** * Function implementation macro */ #define KX_PYMETHODDEF_DOC(class_name, method_name, doc_string) \ const char class_name::method_name##_doc[] = doc_string; \ -PyObject* class_name::Py##method_name(PyObject*, PyObject* args, PyObject*) +PyObject* class_name::Py##method_name(PyObject* args, PyObject*) + +#define KX_PYMETHODDEF_DOC_VARARGS(class_name, method_name, doc_string) \ +const char class_name::method_name##_doc[] = doc_string; \ +PyObject* class_name::Py##method_name(PyObject* args) + +#define KX_PYMETHODDEF_DOC_O(class_name, method_name, doc_string) \ +const char class_name::method_name##_doc[] = doc_string; \ +PyObject* class_name::Py##method_name(PyObject* value) -#define KX_PYMETHODDEF_DOC_NOARG(class_name, method_name, doc_string) \ +#define KX_PYMETHODDEF_DOC_NOARGS(class_name, method_name, doc_string) \ const char class_name::method_name##_doc[] = doc_string; \ -PyObject* class_name::Py##method_name(PyObject*) +PyObject* class_name::Py##method_name() + +/** + * Attribute management + */ +enum KX_PYATTRIBUTE_TYPE { + KX_PYATTRIBUTE_TYPE_BOOL, + KX_PYATTRIBUTE_TYPE_ENUM, + KX_PYATTRIBUTE_TYPE_SHORT, + KX_PYATTRIBUTE_TYPE_INT, + KX_PYATTRIBUTE_TYPE_FLOAT, + KX_PYATTRIBUTE_TYPE_STRING, + KX_PYATTRIBUTE_TYPE_DUMMY, + KX_PYATTRIBUTE_TYPE_FUNCTION, + KX_PYATTRIBUTE_TYPE_VECTOR, +}; + +enum KX_PYATTRIBUTE_ACCESS { + KX_PYATTRIBUTE_RW, + KX_PYATTRIBUTE_RO +}; + +struct KX_PYATTRIBUTE_DEF; +typedef int (*KX_PYATTRIBUTE_CHECK_FUNCTION)(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); +typedef int (*KX_PYATTRIBUTE_SET_FUNCTION)(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); +typedef PyObject* (*KX_PYATTRIBUTE_GET_FUNCTION)(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + +typedef struct KX_PYATTRIBUTE_DEF { + const char *m_name; // name of the python attribute + KX_PYATTRIBUTE_TYPE m_type; // type of value + KX_PYATTRIBUTE_ACCESS m_access; // read/write access or read-only + int m_imin; // minimum value in case of integer attributes (for string: minimum string length) + int m_imax; // maximum value in case of integer attributes (for string: maximum string length) + float m_fmin; // minimum value in case of float attributes + float m_fmax; // maximum value in case of float attributes + bool m_clamp; // enforce min/max value by clamping + size_t m_offset; // position of field in structure + size_t m_size; // size of field for runtime verification (enum only) + size_t m_length; // length of array, 1=simple attribute + KX_PYATTRIBUTE_CHECK_FUNCTION m_checkFunction; // static function to check the assignment, returns 0 if no error + KX_PYATTRIBUTE_SET_FUNCTION m_setFunction; // static function to check the assignment, returns 0 if no error + KX_PYATTRIBUTE_GET_FUNCTION m_getFunction; // static function to check the assignment, returns 0 if no error + + // The following pointers are just used to have compile time check for attribute type. + // It would have been good to use a union but that would require C99 compatibility + // to initialize specific union fields through designated initializers. + struct { + bool *m_boolPtr; + short int *m_shortPtr; + int *m_intPtr; + float *m_floatPtr; + STR_String *m_stringPtr; + MT_Vector3 *m_vectorPtr; + } m_typeCheck; +} PyAttributeDef; + +#define KX_PYATTRIBUTE_DUMMY(name) \ + { name, KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } + +#define KX_PYATTRIBUTE_BOOL_RW(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_BOOL_RW_CHECK(name,object,field,function) \ + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_BOOL_RO(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } + +// enum field cannot be mapped to pointer (because we would need a pointer for each enum) +// use field size to verify mapping at runtime only, assuming enum size is equal to int size. +#define KX_PYATTRIBUTE_ENUM_RW(name,min,max,clamp,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_ENUM_RW_CHECK(name,min,max,clamp,object,field,function) \ + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_ENUM_RO(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL} } + +#define KX_PYATTRIBUTE_SHORT_RW(name,min,max,clamp,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_RW_CHECK(name,min,max,clamp,object,field,function) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_RO(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_ARRAY_RW(name,min,max,clamp,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name,min,max,clamp,object,field,length,function) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_ARRAY_RO(name,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } +// SHORT_LIST +#define KX_PYATTRIBUTE_SHORT_LIST_RW(name,min,max,clamp,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_LIST_RW_CHECK(name,min,max,clamp,object,field,length,function) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_SHORT_LIST_RO(name,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } + +#define KX_PYATTRIBUTE_INT_RW(name,min,max,clamp,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_RW_CHECK(name,min,max,clamp,object,field,function) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_RO(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_ARRAY_RW(name,min,max,clamp,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name,min,max,clamp,object,field,length,function) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_ARRAY_RO(name,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } +// INT_LIST +#define KX_PYATTRIBUTE_INT_LIST_RW(name,min,max,clamp,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_LIST_RW_CHECK(name,min,max,clamp,object,field,length,function) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_INT_LIST_RO(name,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } + +// always clamp for float +#define KX_PYATTRIBUTE_FLOAT_RW(name,min,max,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_RW_CHECK(name,min,max,object,field,function) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_RO(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW(name,min,max,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL} } +#define KX_PYATTRIBUTE_FLOAT_ARRAY_RO(name,object,field,length) \ + { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL} } + +#define KX_PYATTRIBUTE_STRING_RW(name,min,max,clamp,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } +#define KX_PYATTRIBUTE_STRING_RW_CHECK(name,min,max,clamp,object,field,function) \ + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } +#define KX_PYATTRIBUTE_STRING_RO(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } + +#define KX_PYATTRIBUTE_VECTOR_RW(name,min,max,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field} } +#define KX_PYATTRIBUTE_VECTOR_RW_CHECK(name,min,max,clamp,object,field,function) \ + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field} } +#define KX_PYATTRIBUTE_VECTOR_RO(name,object,field) \ + { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field} } + +#define KX_PYATTRIBUTE_RW_FUNCTION(name,object,getfunction,setfunction) \ + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_RO_FUNCTION(name,object,getfunction) \ + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, 0, 0, 1, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_ARRAY_RW_FUNCTION(name,object,length,getfunction,setfunction) \ + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0,f, false, 0, 0, length, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } +#define KX_PYATTRIBUTE_ARRAY_RO_FUNCTION(name,object,length,getfunction) \ + { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0,f, false, 0, 0, length, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL} } + /*------------------------------ * PyObjectPlus ------------------------------*/ typedef PyTypeObject * PyParentObject; // Define the PyParent Object -class PyObjectPlus : public PyObject +// By making SG_QList the ultimate parent for PyObjectPlus objects, it +// allows to put them in 2 different dynamic lists at the same time +// The use of these links is interesting because they free of memory allocation +// but it's very important not to mess up with them. If you decide that +// the SG_QList or SG_DList component is used for something for a certain class, +// they cannot can be used for anything else at a parent level! +// What these lists are and what they are used for must be carefully documented +// at the level where they are used. +// DON'T MAKE ANY USE OF THESE LIST AT THIS LEVEL, they are already used +// at SCA_IActuator, SCA_ISensor, SCA_IController level which rules out the +// possibility to use them at SCA_ILogicBrick, CValue and PyObjectPlus level. +class PyObjectPlus : public SG_QList { // The PyObjectPlus abstract class Py_Header; // Always start with Py_Header public: - PyObjectPlus(PyTypeObject *T); + PyObjectPlus(); + + PyObject *m_proxy; /* actually a PyObjectPlus_Proxy */ virtual ~PyObjectPlus(); // destructor - static void PyDestructor(PyObject *P) // python wrapper - { - delete ((PyObjectPlus *) P); - }; -// void INCREF(void) { -// Py_INCREF(this); -// }; // incref method -// void DECREF(void) { -// Py_DECREF(this); -// }; // decref method + /* These static functions are referenced by ALL PyObjectPlus_Proxy types + * they take the C++ reference from the PyObjectPlus_Proxy and call + * its own virtual py_repr, py_base_dealloc ,etc. functions. + */ + + static PyObject* py_base_new(PyTypeObject *type, PyObject *args, PyObject *kwds); /* allows subclassing */ + static void py_base_dealloc(PyObject *self); + static PyObject* py_base_repr(PyObject *self); + + /* These are all virtual python methods that are defined in each class + * Our own fake subclassing calls these on each class, then calls the parent */ + virtual PyObject* py_repr(void); + + static PyObject* py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef); + static int py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef); - virtual PyObject *_getattr(const STR_String& attr); // _getattr method - static PyObject *__getattr(PyObject * PyObj, char *attr) // This should be the entry in Type. - { - return ((PyObjectPlus*) PyObj)->_getattr(STR_String(attr)); - } + /* Kindof dumb, always returns True, the false case is checked for, before this function gets accessed */ + static PyObject* pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - virtual int _delattr(const STR_String& attr); - virtual int _setattr(const STR_String& attr, PyObject *value); // _setattr method - static int __setattr(PyObject *PyObj, // This should be the entry in Type. - char *attr, - PyObject *value) - { - if (!value) - return ((PyObjectPlus*) PyObj)->_delattr(attr); - return ((PyObjectPlus*) PyObj)->_setattr(STR_String(attr), value); - } + static PyObject *GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp); + static PyObject *NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool py_owns); - virtual PyObject *_repr(void); // _repr method - static PyObject *__repr(PyObject *PyObj) // This should be the entry in Type. - { - return ((PyObjectPlus*) PyObj)->_repr(); - } + void InvalidateProxy(); + + /** + * Makes sure any internal data owned by this class is deep copied. + */ + virtual void ProcessReplica(); + + + static bool m_ignore_deprecation_warnings; + + static WarnLink* GetDeprecationWarningLinkFirst(void); + static WarnLink* GetDeprecationWarningLinkLast(void); + static void SetDeprecationWarningFirst(WarnLink* wlink); + static void SetDeprecationWarningLinkLast(WarnLink* wlink); + static void NullDeprecationWarning(); + + /** enable/disable display of deprecation warnings */ + static void SetDeprecationWarnings(bool ignoreDeprecationWarnings); + /** Shows a deprecation warning */ + static void ShowDeprecationWarning_func(const char* method,const char* prop); + static void ClearDeprecationWarning(); - // isA methods - bool isA(PyTypeObject *T); - bool isA(const char *mytypename); - PyObject *Py_isA(PyObject *args); - static PyObject *sPy_isA(PyObject *self, PyObject *args, PyObject *kwd) - { - return ((PyObjectPlus*)self)->Py_isA(args); - } }; + +PyObject *py_getattr_dict(PyObject *pydict, PyObject *tp_dict); + #endif // _adr_py_lib_h_ #endif //NO_EXP_PYTHON_EMBEDDING diff --git a/source/gameengine/Expressions/SConscript b/source/gameengine/Expressions/SConscript index 809ac31371e..c819bfb0d3e 100644 --- a/source/gameengine/Expressions/SConscript +++ b/source/gameengine/Expressions/SConscript @@ -3,7 +3,7 @@ Import ('env') sources = env.Glob('*.cpp') -incs ='. #source/kernel/gen_system #intern/string #intern/moto/include' +incs ='. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/SceneGraph #source/blender/blenloader' incs += ' ' + env['BF_PYTHON_INC'] -env.BlenderLib ( 'bf_expressions', sources, Split(incs), [], libtype=['game','player'], priority = [45,125] ) +env.BlenderLib ( 'bf_expressions', sources, Split(incs), [], libtype=['core','player'], priority = [360,80], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/Expressions/StringValue.cpp b/source/gameengine/Expressions/StringValue.cpp index 1ef8c5629a0..a7033fcf11c 100644 --- a/source/gameengine/Expressions/StringValue.cpp +++ b/source/gameengine/Expressions/StringValue.cpp @@ -34,7 +34,7 @@ effect: constructs a new CStringValue m_strString = "[Illegal String constructor call]"; } -CStringValue::CStringValue(STR_String txt,STR_String name,AllocationTYPE alloctype) +CStringValue::CStringValue(const char *txt,const char *name,AllocationTYPE alloctype) /* pre: effect: constructs a new CStringValue containing text txt @@ -113,7 +113,7 @@ this object -float CStringValue::GetNumber() +double CStringValue::GetNumber() { return -1; } @@ -133,7 +133,7 @@ bool CStringValue::IsEqual(const STR_String & other) CValue* CStringValue::GetReplica() { CStringValue* replica = new CStringValue(*this); - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; }; diff --git a/source/gameengine/Expressions/StringValue.h b/source/gameengine/Expressions/StringValue.h index b824d4ef86d..069eb8d9c24 100644 --- a/source/gameengine/Expressions/StringValue.h +++ b/source/gameengine/Expressions/StringValue.h @@ -26,26 +26,33 @@ class CStringValue : public CPropValue public: /// Construction / destruction CStringValue(); - CStringValue (STR_String txt, STR_String name , AllocationTYPE alloctype = CValue::HEAPVALUE); + CStringValue (const char *txt, const char *name , AllocationTYPE alloctype = CValue::HEAPVALUE); virtual ~CStringValue() { }; /// CValue implementation virtual bool IsEqual(const STR_String & other); virtual const STR_String & GetText(); - virtual float GetNumber(); + virtual double GetNumber(); virtual CValue* Calc(VALUE_OPERATOR op, CValue *val); virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); virtual void SetValue(CValue* newval) { m_strString = newval->GetText(); SetModified(true); }; virtual CValue* GetReplica(); virtual PyObject* ConvertValueToPython() { - return PyString_FromString(m_strString.Ptr()); + return PyUnicode_FromString(m_strString.Ptr()); } private: // data member STR_String m_strString; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CStringValue"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp index 7296dfbec10..130317d77e2 100644 --- a/source/gameengine/Expressions/Value.cpp +++ b/source/gameengine/Expressions/Value.cpp @@ -35,139 +35,36 @@ double CValue::m_sZeroVec[3] = {0.0,0.0,0.0}; #ifndef NO_EXP_PYTHON_EMBEDDING -PyObject* cvalue_add(PyObject*v, PyObject*w) -{ - return ((CValue*)v)->Calc(VALUE_ADD_OPERATOR,(CValue*)w); -} -PyObject* cvalue_sub(PyObject*v, PyObject*w) -{ - return ((CValue*)v)->Calc(VALUE_SUB_OPERATOR,(CValue*)w); -} -PyObject* cvalue_mul(PyObject*v, PyObject*w) -{ - return ((CValue*)v)->Calc(VALUE_MUL_OPERATOR,(CValue*)w); -} -PyObject* cvalue_div(PyObject*v, PyObject*w) -{ - return ((CValue*)v)->Calc(VALUE_DIV_OPERATOR,(CValue*)w); -} -PyObject* cvalue_neg(PyObject*v) -{ - return ((CValue*)v)->Calc(VALUE_NEG_OPERATOR,(CValue*)v); -} -PyObject* cvalue_pos(PyObject*v) -{ - return ((CValue*)v)->Calc(VALUE_POS_OPERATOR,(CValue*)v); -} - - -int MyPyCompare (PyObject* v,PyObject* w) -{ - CValue* eqval = ((CValue*)v)->Calc(VALUE_EQL_OPERATOR,(CValue*)w); - STR_String txt = eqval->GetText(); - eqval->Release(); - if (txt=="TRUE") - return 0; - CValue* lessval = ((CValue*)v)->Calc(VALUE_LES_OPERATOR,(CValue*)w); - txt = lessval->GetText(); - lessval->Release(); - if (txt=="TRUE") - return -1; - - return 1; -} - - -int cvalue_coerce(PyObject** pv,PyObject** pw) -{ - if (PyInt_Check(*pw)) { - double db = (double)PyInt_AsLong(*pw); - *pw = new CIntValue((int) db); - Py_INCREF(*pv); - return 0; - } - else if (PyLong_Check(*pw)) { - double db = PyLong_AsDouble(*pw); - *pw = new CFloatValue(db); - Py_INCREF(*pv); - return 0; - } - else if (PyFloat_Check(*pw)) { - double db = PyFloat_AsDouble(*pw); - *pw = new CFloatValue(db); - Py_INCREF(*pv); - return 0; - } else if (PyString_Check(*pw)) { - const STR_String str = PyString_AsString(*pw); - *pw = new CStringValue(str,""); - Py_INCREF(*pv); - return 0; - } - return 1; /* Can't do it */ - -} -static PyNumberMethods cvalue_as_number = { - (binaryfunc)cvalue_add, /*nb_add*/ - (binaryfunc)cvalue_sub, /*nb_subtract*/ - (binaryfunc)cvalue_mul, /*nb_multiply*/ - (binaryfunc)cvalue_div, /*nb_divide*/ - 0,//(binaryfunc)cvalue_remainder, /*nb_remainder*/ - 0,//(binaryfunc)cvalue_divmod, /*nb_divmod*/ - 0,//0,//0,//0,//(ternaryfunc)cvalue_pow, /*nb_power*/ - (unaryfunc)cvalue_neg, /*nb_negative*/ - 0,//(unaryfunc)cvalue_pos, /*nb_positive*/ - 0,//(unaryfunc)cvalue_abs, /*nb_absolute*/ - 0,//(inquiry)cvalue_nonzero, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - (coercion)cvalue_coerce, /*nb_coerce*/ - 0,//(unaryfunc)cvalue_int, /*nb_int*/ - 0,//(unaryfunc)cvalue_long, /*nb_long*/ - 0,//(unaryfunc)cvalue_float, /*nb_float*/ - 0, /*nb_oct*/ - 0, /*nb_hex*/ -}; - - PyTypeObject CValue::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "CValue", - sizeof(CValue), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - &MyPyCompare, - __repr, - &cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject CValue::Parents[] = { - &CValue::Type, - NULL + py_base_repr, + 0, + 0,0,0,0,0, + NULL, + NULL, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &PyObjectPlus::Type, + 0,0,0,0,0,0, + py_base_new }; PyMethodDef CValue::Methods[] = { -// { "printHello", (PyCFunction) CValue::sPyPrintHello, METH_VARARGS}, - { "getName", (PyCFunction) CValue::sPyGetName, METH_NOARGS}, {NULL,NULL} //Sentinel }; -PyObject* CValue::PyGetName(PyObject* self) -{ - return PyString_FromString(this->GetName()); -} - /*#define CVALUE_DEBUG*/ #ifdef CVALUE_DEBUG int gRefCount; @@ -191,8 +88,8 @@ std::vector<SmartCValueRef> gRefList; //int gRefCountValue; #endif -CValue::CValue(PyTypeObject *T) - : PyObjectPlus(T), +CValue::CValue() + : PyObjectPlus(), #else CValue::CValue() : @@ -256,6 +153,9 @@ STR_String CValue::op2str (VALUE_OPERATOR op) STR_String opmsg; switch (op) { + case VALUE_MOD_OPERATOR: + opmsg = " % "; + break; case VALUE_ADD_OPERATOR: opmsg = " + "; break; @@ -312,73 +212,90 @@ STR_String CValue::op2str (VALUE_OPERATOR op) // void CValue::SetProperty(const STR_String & name,CValue* ioProperty) { - // Check if somebody is setting an empty property if (ioProperty==NULL) - { + { // Check if somebody is setting an empty property trace("Warning:trying to set empty property!"); return; } - // Make sure we have a property array - if (m_pNamedPropertyArray == NULL) + if (m_pNamedPropertyArray) + { // Try to replace property (if so -> exit as soon as we replaced it) + CValue* oldval = (*m_pNamedPropertyArray)[name]; + if (oldval) + oldval->Release(); + } + else { // Make sure we have a property array m_pNamedPropertyArray = new std::map<STR_String,CValue *>; - - // Try to replace property (if so -> exit as soon as we replaced it) - CValue* oldval = (*m_pNamedPropertyArray)[name]; - if (oldval) - { - oldval->Release(); } // Add property at end of array (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty); } +void CValue::SetProperty(const char* name,CValue* ioProperty) +{ + if (ioProperty==NULL) + { // Check if somebody is setting an empty property + trace("Warning:trying to set empty property!"); + return; + } + if (m_pNamedPropertyArray) + { // Try to replace property (if so -> exit as soon as we replaced it) + CValue* oldval = (*m_pNamedPropertyArray)[name]; + if (oldval) + oldval->Release(); + } + else { // Make sure we have a property array + m_pNamedPropertyArray = new std::map<STR_String,CValue *>; + } + + // Add property at end of array + (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty); +} // // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName> // CValue* CValue::GetProperty(const STR_String & inName) { - // Check properties, as soon as we found it -> Return a pointer to the property - CValue* result = NULL; - if (m_pNamedPropertyArray) - { - std::map<STR_String,CValue*>::iterator it = (*m_pNamedPropertyArray).find(inName); - if (!( it==m_pNamedPropertyArray->end())) - { - result = (*it).second; - } - + if (m_pNamedPropertyArray) { + std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName); + if (it != m_pNamedPropertyArray->end()) + return (*it).second; } - //for (int i=0; i<m_pValuePropertyArray->size(); i++) - // if ((*m_pValuePropertyArray)[i]->GetName() == inName) - // return (*m_pValuePropertyArray)[i]; - - // Did not find property with name <inName>, return NULL property pointer - return result; + return NULL; } - +CValue* CValue::GetProperty(const char *inName) +{ + if (m_pNamedPropertyArray) { + std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName); + if (it != m_pNamedPropertyArray->end()) + return (*it).second; + } + return NULL; +} // // Get text description of property with name <inName>, returns an empty string if there is no property named <inName> // -STR_String CValue::GetPropertyText(const STR_String & inName,const STR_String& deftext) +const STR_String& CValue::GetPropertyText(const STR_String & inName) { + const static STR_String sEmpty(""); + CValue *property = GetProperty(inName); if (property) return property->GetText(); else - return deftext;//String::sEmpty; + return sEmpty; } float CValue::GetPropertyNumber(const STR_String& inName,float defnumber) { CValue *property = GetProperty(inName); if (property) - return property->GetNumber(); + return property->GetNumber(); else return defnumber; } @@ -388,26 +305,20 @@ float CValue::GetPropertyNumber(const STR_String& inName,float defnumber) // // Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed // -bool CValue::RemoveProperty(const STR_String & inName) +bool CValue::RemoveProperty(const char *inName) { // Check if there are properties at all which can be removed - if (m_pNamedPropertyArray) { - CValue* val = GetProperty(inName); - if (NULL != val) + if (m_pNamedPropertyArray) + { + std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName); + if (it != m_pNamedPropertyArray->end()) { - val->Release(); - m_pNamedPropertyArray->erase(inName); + ((*it).second)->Release(); + m_pNamedPropertyArray->erase(it); return true; } - } - - char err[128]; - if (m_pNamedPropertyArray) - sprintf(err, "attribute \"%s\" dosnt exist", inName.ReadPtr()); - else - sprintf(err, "attribute \"%s\" dosnt exist (no property array)", inName.ReadPtr()); + } - PyErr_SetString(PyExc_AttributeError, err); return false; } @@ -418,8 +329,10 @@ vector<STR_String> CValue::GetPropertyNames() { vector<STR_String> result; if(!m_pNamedPropertyArray) return result; - for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin(); - !(it == m_pNamedPropertyArray->end());it++) + result.reserve(m_pNamedPropertyArray->size()); + + std::map<STR_String,CValue*>::iterator it; + for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++) { result.push_back((*it).first); } @@ -436,8 +349,8 @@ void CValue::ClearProperties() return; // Remove all properties - for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin(); - !(it == m_pNamedPropertyArray->end());it++) + std::map<STR_String,CValue*>::iterator it; + for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++) { CValue* tmpval = (*it).second; //STR_String name = (*it).first; @@ -456,9 +369,11 @@ void CValue::ClearProperties() // void CValue::SetPropertiesModified(bool inModified) { - int numprops = GetPropertyCount(); - for (int i=0; i<numprops; i++) - GetProperty(i)->SetModified(inModified); + if(!m_pNamedPropertyArray) return; + std::map<STR_String,CValue*>::iterator it; + + for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++) + ((*it).second)->SetModified(inModified); } @@ -468,11 +383,13 @@ void CValue::SetPropertiesModified(bool inModified) // bool CValue::IsAnyPropertyModified() { - int numprops = GetPropertyCount(); - for (int i=0;i<numprops;i++) - if (GetProperty(i)->IsModified()) + if(!m_pNamedPropertyArray) return false; + std::map<STR_String,CValue*>::iterator it; + + for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++) + if (((*it).second)->IsModified()) return true; - + return false; } @@ -481,7 +398,6 @@ bool CValue::IsAnyPropertyModified() // // Get property number <inIndex> // - CValue* CValue::GetProperty(int inIndex) { @@ -490,8 +406,8 @@ CValue* CValue::GetProperty(int inIndex) if (m_pNamedPropertyArray) { - for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin(); - !(it == m_pNamedPropertyArray->end());it++) + std::map<STR_String,CValue*>::iterator it; + for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++) { if (count++==inIndex) { @@ -518,27 +434,6 @@ int CValue::GetPropertyCount() } - - - -void CValue::CloneProperties(CValue *replica) -{ - - if (m_pNamedPropertyArray) - { - replica->m_pNamedPropertyArray=NULL; - for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin(); - !(it == m_pNamedPropertyArray->end());it++) - { - CValue *val = (*it).second->GetReplica(); - replica->SetProperty((*it).first,val); - val->Release(); - } - } - - -} - double* CValue::GetVector3(bool bGetTransformedVec) { assertd(false); // don;t get vector from me @@ -549,49 +444,12 @@ double* CValue::GetVector3(bool bGetTransformedVec) /*--------------------------------------------------------------------------------------------------------------------- Reference Counting ---------------------------------------------------------------------------------------------------------------------*/ -// -// Add a reference to this value -// -CValue *CValue::AddRef() -{ - // Increase global reference count, used to see at the end of the program - // if all CValue-derived classes have been dereferenced to 0 - //debug(gRefCountValue++); -#ifdef _DEBUG - //gRefCountValue++; -#endif - m_refcount++; - return this; -} // // Release a reference to this value (when reference count reaches 0, the value is removed from the heap) // -int CValue::Release() -{ - // Decrease global reference count, used to see at the end of the program - // if all CValue-derived classes have been dereferenced to 0 - //debug(gRefCountValue--); -#ifdef _DEBUG - //gRefCountValue--; -#endif - // Decrease local reference count, if it reaches 0 the object should be freed - if (--m_refcount > 0) - { - // Reference count normal, return new reference count - return m_refcount; - } - else - { - // Reference count reached 0, delete ourselves and return 0 -// MT_assert(m_refcount==0, "Reference count reached sub-zero, object released too much"); - delete this; - return 0; - } - -} @@ -612,26 +470,32 @@ void CValue::DisableRefCount() -void CValue::AddDataToReplica(CValue *replica) +void CValue::ProcessReplica() /* was AddDataToReplica in 2.48 */ { - replica->m_refcount = 1; - - //register with Python - _Py_NewReference(replica); - + m_refcount = 1; + #ifdef _DEBUG //gRefCountValue++; #endif - replica->m_ValFlags.RefCountDisabled = false; + PyObjectPlus::ProcessReplica(); - replica->ReplicaSetName(GetName()); + m_ValFlags.RefCountDisabled = false; - //copy all props - CloneProperties(replica); + /* copy all props */ + if (m_pNamedPropertyArray) + { + std::map<STR_String,CValue*> *pOldArray = m_pNamedPropertyArray; + m_pNamedPropertyArray=NULL; + std::map<STR_String,CValue*>::iterator it; + for (it= pOldArray->begin(); (it != pOldArray->end()); it++) + { + CValue *val = (*it).second->GetReplica(); + SetProperty((*it).first,val); + val->Release(); + } + } } - - CValue* CValue::FindIdentifier(const STR_String& identifiername) { @@ -665,47 +529,22 @@ CValue* CValue::FindIdentifier(const STR_String& identifiername) #ifndef NO_EXP_PYTHON_EMBEDDING - -static PyMethodDef CValueMethods[] = -{ - //{ "new", CValue::PyMake , METH_VARARGS}, - { NULL,NULL} // Sentinel +PyAttributeDef CValue::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("name", CValue, pyattr_get_name), + { NULL } //Sentinel }; - -PyObject* CValue::_getattr(const STR_String& attr) -{ - CValue* resultattr = FindIdentifier(attr); - STR_String text; - if (resultattr) - { - if (resultattr->IsError()) - { - resultattr->Release(); - } else - { - // to avoid some compare problems, return a real pythonthing - PyObject* pyconvert = resultattr->ConvertValueToPython(); - if (pyconvert) - { - resultattr->Release(); - return pyconvert; - } else - { - // also check if it's already in pythoninterpreter! - return resultattr; - } - - } - } - _getattr_up(PyObjectPlus); +PyObject * CValue::pyattr_get_name(void * self_v, const KX_PYATTRIBUTE_DEF * attrdef) { + CValue * self = static_cast<CValue *> (self_v); + return PyUnicode_FromString(self->GetName()); } -CValue* CValue::ConvertPythonToValue(PyObject* pyobj) +CValue* CValue::ConvertPythonToValue(PyObject* pyobj, const char *error_prefix) { CValue* vallie = NULL; - + /* refcounting is broking here! - this crashes anyway, just store a python list for KX_GameObject */ +#if 0 if (PyList_Check(pyobj)) { CListValue* listval = new CListValue(); @@ -716,7 +555,7 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj) for (i=0;i<numitems;i++) { PyObject* listitem = PyList_GetItem(pyobj,i); /* borrowed ref */ - CValue* listitemval = ConvertPythonToValue(listitem); + CValue* listitemval = ConvertPythonToValue(listitem, error_prefix); if (listitemval) { listval->Add(listitemval); @@ -736,61 +575,31 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj) } } else +#endif if (PyFloat_Check(pyobj)) { vallie = new CFloatValue( (float)PyFloat_AsDouble(pyobj) ); } else - if (PyInt_Check(pyobj)) + if (PyLong_Check(pyobj)) { - vallie = new CIntValue( (int)PyInt_AS_LONG(pyobj) ); + vallie = new CIntValue( (cInt)PyLong_AsLongLong(pyobj) ); } else - if (PyString_Check(pyobj)) + if (PyUnicode_Check(pyobj)) { - vallie = new CStringValue(PyString_AsString(pyobj),""); + vallie = new CStringValue(_PyUnicode_AsString(pyobj),""); } else - if (pyobj->ob_type==&CValue::Type || pyobj->ob_type==&CListValue::Type) + if (PyObject_TypeCheck(pyobj, &CValue::Type)) /* Note, dont let these get assigned to GameObject props, must check elsewhere */ { - vallie = ((CValue*) pyobj)->AddRef(); + vallie = (static_cast<CValue *>(BGE_PROXY_REF(pyobj)))->AddRef(); } else { /* return an error value from the caller */ - PyErr_SetString(PyExc_TypeError, "This python value could not be assigned to a game engine property"); + PyErr_Format(PyExc_TypeError, "%scould convert python value to a game engine property", error_prefix); } return vallie; } -int CValue::_delattr(const STR_String& attr) -{ - if (!RemoveProperty(attr)) /* sets error */ - return 1; - return 0; -} - -int CValue::_setattr(const STR_String& attr,PyObject* pyobj) -{ - CValue* vallie = ConvertPythonToValue(pyobj); - if (vallie) - { - CValue* oldprop = GetProperty(attr); - - if (oldprop) - { - oldprop->SetValue(vallie); - } else - { - SetProperty(attr,vallie); - } - vallie->Release(); - } else - { - return 1; /* ConvertPythonToValue sets the error message */ - } - - //PyObjectPlus::_setattr(attr,value); - return 0; -}; - PyObject* CValue::ConvertKeysToPython( void ) { PyObject *pylist = PyList_New( 0 ); @@ -798,10 +607,10 @@ PyObject* CValue::ConvertKeysToPython( void ) if (m_pNamedPropertyArray) { - for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin(); - !(it == m_pNamedPropertyArray->end());it++) + std::map<STR_String,CValue*>::iterator it; + for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++) { - pystr = PyString_FromString( (*it).first ); + pystr = PyUnicode_FromString( (*it).first ); PyList_Append(pylist, pystr); Py_DECREF( pystr ); } @@ -809,24 +618,6 @@ PyObject* CValue::ConvertKeysToPython( void ) return pylist; } -/* -PyObject* CValue::PyMake(PyObject* ignored,PyObject* args) -{ - - //if (!PyArg_ParseTuple(args,"s",&name)) return NULL; - Py_RETURN_NONE;//new CValue(); -} -*/ - -extern "C" { - void initCValue(void) - { - Py_InitModule("CValue",CValueMethods); - } -} - - - #endif //NO_EXP_PYTHON_EMBEDDING /////////////////////////////////////////////////////////////////////////////////////////////// @@ -847,6 +638,3 @@ void CValue::SetValue(CValue* newval) // no one should get here assertd(newval->GetNumber() == 10121969); } -/////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////// - diff --git a/source/gameengine/Expressions/Value.h b/source/gameengine/Expressions/Value.h index 74fcdae5756..7d4adcdb64f 100644 --- a/source/gameengine/Expressions/Value.h +++ b/source/gameengine/Expressions/Value.h @@ -42,6 +42,10 @@ #include <map> // array functionality for the propertylist #include "STR_String.h" // STR_String class +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + #ifndef GEN_NO_ASSERT #undef assert #define assert(exp) ((void)NULL) @@ -75,6 +79,7 @@ enum VALUE_OPERATOR { + VALUE_MOD_OPERATOR, // % VALUE_ADD_OPERATOR, // + VALUE_SUB_OPERATOR, // - VALUE_MUL_OPERATOR, // * @@ -172,6 +177,13 @@ public: virtual ~CAction(){ }; virtual void Execute() const =0; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CAction"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; // @@ -214,48 +226,22 @@ public: // Construction / Destruction #ifndef NO_EXP_PYTHON_EMBEDDING - CValue(PyTypeObject *T = &Type); + CValue(); //static PyObject* PyMake(PyObject*,PyObject*); - virtual PyObject *_repr(void) - { - return Py_BuildValue("s",(const char*)GetText()); - } - - - - virtual PyObject* _getattr(const STR_String& attr); - - void SpecialRelease() + virtual PyObject *py_repr(void) { - int i=0; - if (ob_refcnt == 0) - { - _Py_NewReference(this); - - } else - { - i++; - } - Release(); + return PyUnicode_FromString((const char*)GetText()); } - static void PyDestructor(PyObject *P) // python wrapper - { - ((CValue*)P)->SpecialRelease(); - }; virtual PyObject* ConvertValueToPython() { return NULL; } - virtual CValue* ConvertPythonToValue(PyObject* pyobj); - - - virtual int _delattr(const STR_String& attr); - virtual int _setattr(const STR_String& attr,PyObject* value); + virtual CValue* ConvertPythonToValue(PyObject* pyobj, const char *error_prefix); - virtual PyObject* ConvertKeysToPython( void ); + static PyObject * pyattr_get_name(void * self, const KX_PYATTRIBUTE_DEF * attrdef); - KX_PYMETHOD_NOARGS(CValue,GetName); + virtual PyObject* ConvertKeysToPython( void ); #else CValue(); @@ -276,16 +262,58 @@ public: }; /// Reference Counting - int GetRefCount() { return m_refcount; } - virtual CValue* AddRef(); // Add a reference to this value - virtual int Release(); // Release a reference to this value (when reference count reaches 0, the value is removed from the heap) + int GetRefCount() + { + return m_refcount; + } + + // Add a reference to this value + CValue* AddRef() + { + // Increase global reference count, used to see at the end of the program + // if all CValue-derived classes have been dereferenced to 0 + //debug(gRefCountValue++); + #ifdef _DEBUG + //gRefCountValue++; + #endif + m_refcount++; + return this; + } + + // Release a reference to this value (when reference count reaches 0, the value is removed from the heap) + int Release() + { + // Decrease global reference count, used to see at the end of the program + // if all CValue-derived classes have been dereferenced to 0 + //debug(gRefCountValue--); + #ifdef _DEBUG + //gRefCountValue--; + #endif + // Decrease local reference count, if it reaches 0 the object should be freed + if (--m_refcount > 0) + { + // Reference count normal, return new reference count + return m_refcount; + } + else + { + // Reference count reached 0, delete ourselves and return 0 + // MT_assert(m_refcount==0, "Reference count reached sub-zero, object released too much"); + + delete this; + return 0; + } + } + /// Property Management virtual void SetProperty(const STR_String& name,CValue* ioProperty); // Set property <ioProperty>, overwrites and releases a previous property with the same name if needed - virtual CValue* GetProperty(const STR_String & inName); // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName> - STR_String GetPropertyText(const STR_String & inName,const STR_String& deftext=""); // Get text description of property with name <inName>, returns an empty string if there is no property named <inName> + virtual void SetProperty(const char* name,CValue* ioProperty); + virtual CValue* GetProperty(const char* inName); // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName> + virtual CValue* GetProperty(const STR_String & inName); + const STR_String& GetPropertyText(const STR_String & inName); // Get text description of property with name <inName>, returns an empty string if there is no property named <inName> float GetPropertyNumber(const STR_String& inName,float defnumber); - virtual bool RemoveProperty(const STR_String & inName); // Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed + virtual bool RemoveProperty(const char *inName); // Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed virtual vector<STR_String> GetPropertyNames(); virtual void ClearProperties(); // Clear all properties @@ -295,7 +323,6 @@ public: virtual CValue* GetProperty(int inIndex); // Get property number <inIndex> virtual int GetPropertyCount(); // Get the amount of properties assiocated with this value - virtual void CloneProperties(CValue* replica); virtual CValue* FindIdentifier(const STR_String& identifiername); /** Set the wireframe color of this value depending on the CSG * operator type <op> @@ -303,17 +330,17 @@ public: virtual void SetColorOperator(VALUE_OPERATOR op); virtual const STR_String & GetText() = 0; - virtual float GetNumber() = 0; + virtual double GetNumber() = 0; double* ZeroVector() { return m_sZeroVec; }; virtual double* GetVector3(bool bGetTransformedVec = false); - virtual STR_String GetName() = 0; // Retrieve the name of the value - virtual void SetName(STR_String name) = 0; // Set the name of the value - virtual void ReplicaSetName(STR_String name) = 0; + virtual STR_String& GetName() = 0; // Retrieve the name of the value + virtual void SetName(const char *name) = 0; // Set the name of the value /** Sets the value to this cvalue. * @attention this particular function should never be called. Why not abstract? */ virtual void SetValue(CValue* newval); virtual CValue* GetReplica() =0; + virtual void ProcessReplica(); //virtual CValue* Copy() = 0; @@ -338,10 +365,10 @@ public: virtual void SetCustomFlag2(bool bCustomFlag) { m_ValFlags.CustomFlag2 = bCustomFlag;}; virtual bool IsCustomFlag2() { return m_ValFlags.CustomFlag2;}; - + protected: virtual void DisableRefCount(); // Disable reference counting for this value - virtual void AddDataToReplica(CValue* replica); + //virtual void AddDataToReplica(CValue* replica); virtual ~CValue(); private: // Member variables @@ -389,56 +416,41 @@ public: \ class CPropValue : public CValue { public: - #ifndef NO_EXP_PYTHON_EMBEDDING - CPropValue(PyTypeObject* T=&Type) : - CValue(T), + CPropValue() : + CValue(), #else CPropValue() : #endif //NO_EXP_PYTHON_EMBEDDING - m_pstrNewName(NULL) + m_strNewName() { } virtual ~CPropValue() { - if (m_pstrNewName) - { - delete m_pstrNewName; - m_pstrNewName = NULL; - } } - virtual void SetName(STR_String name) { - if (m_pstrNewName) - { - delete m_pstrNewName; - m_pstrNewName = NULL; - } - if (name.Length()) - m_pstrNewName = new STR_String(name); - } - virtual void ReplicaSetName(STR_String name) { - m_pstrNewName=NULL; - if (name.Length()) - m_pstrNewName = new STR_String(name); + virtual void SetName(const char *name) { + m_strNewName = name; } - virtual STR_String GetName() { + virtual STR_String& GetName() { //STR_String namefromprop = GetPropertyText("Name"); //if (namefromprop.Length() > 0) // return namefromprop; - - if (m_pstrNewName) - { - return *m_pstrNewName; - } - return STR_String(""); + return m_strNewName; }; // name of Value protected: - STR_String* m_pstrNewName; // Identification + STR_String m_strNewName; // Identification + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CPropValue"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined _VALUEBASECLASS_H diff --git a/source/gameengine/Expressions/VectorValue.cpp b/source/gameengine/Expressions/VectorValue.cpp index bea6902eba8..c58c78e6ebe 100644 --- a/source/gameengine/Expressions/VectorValue.cpp +++ b/source/gameengine/Expressions/VectorValue.cpp @@ -48,7 +48,7 @@ CVectorValue::CVectorValue(float x,float y,float z, AllocationTYPE alloctype) m_vec[KX_Z] = m_transformedvec[KX_Z] = z; } -CVectorValue::CVectorValue(double vec[],STR_String name,AllocationTYPE alloctype) { +CVectorValue::CVectorValue(double vec[],const char *name,AllocationTYPE alloctype) { SetCustomFlag1(false);//FancyOutput=false; @@ -156,7 +156,7 @@ this object return ret; } -float CVectorValue::GetNumber() +double CVectorValue::GetNumber() { return m_vec[KX_X]; } @@ -204,7 +204,7 @@ const STR_String & CVectorValue::GetText() CValue* CVectorValue::GetReplica() { CVectorValue* replica = new CVectorValue(*this); - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; }; diff --git a/source/gameengine/Expressions/VectorValue.h b/source/gameengine/Expressions/VectorValue.h index 5d9b2a98891..49fb1e7ea08 100644 --- a/source/gameengine/Expressions/VectorValue.h +++ b/source/gameengine/Expressions/VectorValue.h @@ -32,7 +32,7 @@ public: void SetVector(double newvec[]); void Configure(CValue* menuvalue); virtual double* GetVector3(bool bGetTransformedVec=false); - virtual float GetNumber(); + virtual double GetNumber(); CValue* Calc(VALUE_OPERATOR op, CValue *val) { return val->CalcFinal(VALUE_VECTOR_TYPE, op, this); @@ -41,7 +41,7 @@ public: CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); - CVectorValue(double vec[],STR_String name,AllocationTYPE alloctype=CValue::HEAPVALUE); + CVectorValue(double vec[],const char *name,AllocationTYPE alloctype=CValue::HEAPVALUE); CVectorValue() {}; CVectorValue(double vec[],AllocationTYPE alloctype=CValue::HEAPVALUE); @@ -79,6 +79,13 @@ public: protected: double m_vec[3]; double m_transformedvec[3]; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CVectorValue"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined _VECTORVALUE_H diff --git a/source/gameengine/Expressions/VoidValue.h b/source/gameengine/Expressions/VoidValue.h index 4bde0254787..50ec4ff1ee7 100644 --- a/source/gameengine/Expressions/VoidValue.h +++ b/source/gameengine/Expressions/VoidValue.h @@ -47,7 +47,7 @@ public: /// Value -> String or number virtual const STR_String & GetText(); // Get string description of void value (unimplemented) - virtual float GetNumber() { return -1; } + virtual double GetNumber() { return -1; } /// Value calculation virtual CValue* Calc(VALUE_OPERATOR op, CValue *val); @@ -59,6 +59,13 @@ public: /// Data members bool m_bDeleteOnDestruct; void* m_pAnything; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CVoidValue"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // !defined _VOIDVALUE_H diff --git a/source/gameengine/GameLogic/CMakeLists.txt b/source/gameengine/GameLogic/CMakeLists.txt index a7519196d50..601585f79d6 100644 --- a/source/gameengine/GameLogic/CMakeLists.txt +++ b/source/gameengine/GameLogic/CMakeLists.txt @@ -27,15 +27,21 @@ FILE(GLOB SRC *.cpp Joystick/*.cpp) SET(INC - . - ../../../source/kernel/gen_system - ../../../intern/string - ../../../source/gameengine/Expressions - ../../../intern/moto/include - ../../../source/gameengine/Rasterizer - ${PYTHON_INC} - ${SDL_INC} + . + ../../../source/kernel/gen_system + ../../../intern/string + ../../../source/gameengine/Expressions + ../../../source/gameengine/SceneGraph + ../../../intern/moto/include + ../../../source/gameengine/Rasterizer + ${PYTHON_INC} ) +IF(WITH_SDL) + SET(INC ${INC} ${SDL_INCLUDE_DIR}) +ELSE(WITH_SDL) + ADD_DEFINITIONS(-DDISABLE_SDL) +ENDIF(WITH_SDL) + BLENDERLIB(bf_logic "${SRC}" "${INC}") #env.BlenderLib ( 'bf_logic', sources, Split(incs), [], libtype=['game','player'], priority=[30, 110] ) diff --git a/source/gameengine/GameLogic/Joystick/Makefile b/source/gameengine/GameLogic/Joystick/Makefile index 7016f1ed16f..02def1cec62 100644 --- a/source/gameengine/GameLogic/Joystick/Makefile +++ b/source/gameengine/GameLogic/Joystick/Makefile @@ -40,5 +40,5 @@ CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) CPPFLAGS += $(NAN_SDLCFLAGS) - +CPPFLAGS += -I../../SceneGraph CPPFLAGS += -I../../../kernel/gen_system diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp index e8e29fb2769..6140702534c 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp @@ -29,6 +29,7 @@ #endif #include <stdio.h> +#include <stdlib.h> #include "SCA_Joystick.h" #include "SCA_JoystickPrivate.h" @@ -36,21 +37,21 @@ SCA_Joystick::SCA_Joystick(short int index) : m_joyindex(index), - m_axis10(0), - m_axis11(0), - m_axis20(0), - m_axis21(0), m_prec(3200), - m_buttonnum(-2), - m_hatdir(-2), + m_axismax(-1), + m_buttonmax(-1), + m_hatmax(-1), m_isinit(0), m_istrig_axis(0), m_istrig_button(0), - m_istrig_hat(0), - m_axismax(-1), - m_buttonmax(-1), - m_hatmax(-1) + m_istrig_hat(0) { + for(int i=0; i<JOYAXIS_MAX; i++) + m_axis_array[i]= 0; + + for(int i=0; i<JOYHAT_MAX; i++) + m_hat_array[i]= 0; + #ifndef DISABLE_SDL m_private = new PrivateData(); #endif @@ -66,6 +67,7 @@ SCA_Joystick::~SCA_Joystick() } SCA_Joystick *SCA_Joystick::m_instance[JOYINDEX_MAX]; +int SCA_Joystick::m_joynum = 0; int SCA_Joystick::m_refCount = 0; SCA_Joystick *SCA_Joystick::GetInstance( short int joyindex ) @@ -86,6 +88,9 @@ SCA_Joystick *SCA_Joystick::GetInstance( short int joyindex ) echo("Error-Initializing-SDL: " << SDL_GetError()); return NULL; } + + m_joynum = SDL_NumJoysticks(); + for (i=0; i<JOYINDEX_MAX; i++) { m_instance[i] = new SCA_Joystick(i); m_instance[i]->CreateJoystickDevice(); @@ -125,57 +130,42 @@ void SCA_Joystick::cSetPrecision(int val) } -bool SCA_Joystick::aAnyAxisIsPositive(int axis) +bool SCA_Joystick::aAxisPairIsPositive(int axis) { - bool result; - int res = pAxisTest(axis); - res > m_prec? result = true: result = false; - return result; -} - -bool SCA_Joystick::aRightAxisIsPositive(int axis) -{ - bool result; - int res = pGetAxis(axis,1); - res > m_prec? result = true: result = false; - return result; + return (pAxisTest(axis) > m_prec) ? true:false; } - -bool SCA_Joystick::aUpAxisIsPositive(int axis) +bool SCA_Joystick::aAxisPairDirectionIsPositive(int axis, int dir) { - bool result; - int res = pGetAxis(axis,0); - res < -m_prec? result = true : result = false; - return result; -} - -bool SCA_Joystick::aLeftAxisIsPositive(int axis) -{ - bool result; - int res = pGetAxis(axis,1); - res < -m_prec ? result = true : result = false; - return result; + int res; + + if (dir==JOYAXIS_UP || dir==JOYAXIS_DOWN) + res = pGetAxis(axis, 1); + else /* JOYAXIS_LEFT || JOYAXIS_RIGHT */ + res = pGetAxis(axis, 0); + + if (dir==JOYAXIS_DOWN || dir==JOYAXIS_RIGHT) + return (res > m_prec) ? true : false; + else /* JOYAXIS_UP || JOYAXIS_LEFT */ + return (res < -m_prec) ? true : false; } - -bool SCA_Joystick::aDownAxisIsPositive(int axis) +bool SCA_Joystick::aAxisIsPositive(int axis_single) { - bool result; - int res = pGetAxis(axis,0); - res > m_prec ? result = true:result = false; - return result; + return abs(m_axis_array[axis_single]) > m_prec ? true:false; } bool SCA_Joystick::aAnyButtonPressIsPositive(void) { - return (m_buttonnum==-2) ? false : true; -} - -bool SCA_Joystick::aAnyButtonReleaseIsPositive(void) -{ - return (m_buttonnum==-2) ? true : false; +#ifndef DISABLE_SDL + /* this is needed for the "all events" option + * so we know if there are no buttons pressed */ + for (int i=0; i<m_buttonmax; i++) + if (SDL_JoystickGetButton(m_private->m_joystick, i)) + return true; +#endif + return false; } bool SCA_Joystick::aButtonPressIsPositive(int button) @@ -202,20 +192,9 @@ bool SCA_Joystick::aButtonReleaseIsPositive(int button) } -bool SCA_Joystick::aHatIsPositive(int dir) +bool SCA_Joystick::aHatIsPositive(int hatnum, int dir) { - bool result; - int res = pGetHat(dir); - res == dir? result = true : result = false; - return result; -} - -int SCA_Joystick::pGetHat(int direction) -{ - if(direction == m_hatdir){ - return m_hatdir; - } - return 0; + return (GetHat(hatnum)==dir) ? true : false; } int SCA_Joystick::GetNumberOfAxes() @@ -238,12 +217,17 @@ int SCA_Joystick::GetNumberOfHats() bool SCA_Joystick::CreateJoystickDevice(void) { #ifdef DISABLE_SDL + m_isinit = true; + m_axismax = m_buttonmax = m_hatmax = 0; return false; #else if(m_isinit == false){ - if (m_joyindex>=SDL_NumJoysticks()) { + if (m_joyindex>=m_joynum) { // don't print a message, because this is done anyway //echo("Joystick-Error: " << SDL_NumJoysticks() << " avaiable joystick(s)"); + + // Need this so python args can return empty lists + m_axismax = m_buttonmax = m_hatmax = 0; return false; } @@ -257,6 +241,15 @@ bool SCA_Joystick::CreateJoystickDevice(void) m_axismax = SDL_JoystickNumAxes(m_private->m_joystick); m_buttonmax = SDL_JoystickNumButtons(m_private->m_joystick); m_hatmax = SDL_JoystickNumHats(m_private->m_joystick); + + if (m_axismax > JOYAXIS_MAX) m_axismax= JOYAXIS_MAX; /* very unlikely */ + else if (m_axismax < 0) m_axismax = 0; + + if (m_hatmax > JOYHAT_MAX) m_hatmax= JOYHAT_MAX; /* very unlikely */ + else if(m_hatmax<0) m_hatmax= 0; + + if(m_buttonmax<0) m_buttonmax= 0; + } return true; #endif @@ -285,31 +278,10 @@ int SCA_Joystick::Connected(void) return 0; } -void SCA_Joystick::pFillAxes() -{ -#ifndef DISABLE_SDL - if(m_axismax == 1){ - m_axis10 = SDL_JoystickGetAxis(m_private->m_joystick, 0); - m_axis11 = SDL_JoystickGetAxis(m_private->m_joystick, 1); - }else if(m_axismax > 1){ - m_axis10 = SDL_JoystickGetAxis(m_private->m_joystick, 0); - m_axis11 = SDL_JoystickGetAxis(m_private->m_joystick, 1); - m_axis20 = SDL_JoystickGetAxis(m_private->m_joystick, 2); - m_axis21 = SDL_JoystickGetAxis(m_private->m_joystick, 3); - }else{ - m_axis10 = m_axis11 = m_axis20 = m_axis21 = 0; - } -#endif -} - - int SCA_Joystick::pGetAxis(int axisnum, int udlr) { #ifndef DISABLE_SDL - if(axisnum == 1 && udlr == 1)return m_axis10; //u/d - if(axisnum == 1 && udlr == 0)return m_axis11; //l/r - if(axisnum == 2 && udlr == 0)return m_axis20; //... - if(axisnum == 2 && udlr == 1)return m_axis21; + return m_axis_array[(axisnum*2)+udlr]; #endif return 0; } @@ -317,13 +289,9 @@ int SCA_Joystick::pGetAxis(int axisnum, int udlr) int SCA_Joystick::pAxisTest(int axisnum) { #ifndef DISABLE_SDL - short i1,i2; - if(axisnum == 1) { - i1 = m_axis10; i2 = m_axis11; - } - else if(axisnum == 2) { - i1 = m_axis20; i2 = m_axis21; - } + short i1= m_axis_array[(axisnum*2)]; + short i2= m_axis_array[(axisnum*2)+1]; + /* long winded way to do * return MAX2(abs(i1), abs(i2)) * avoid abs from math.h */ @@ -335,4 +303,3 @@ int SCA_Joystick::pAxisTest(int axisnum) return 0; #endif } - diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.h b/source/gameengine/GameLogic/Joystick/SCA_Joystick.h index 8335d5538ad..6324b898247 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.h +++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.h @@ -44,6 +44,7 @@ class SCA_Joystick { static SCA_Joystick *m_instance[JOYINDEX_MAX]; + static int m_joynum; static int m_refCount; class PrivateData; @@ -53,36 +54,21 @@ class SCA_Joystick int m_joyindex; /* - *support for 2 axes + *support for JOYAXIS_MAX axes (in pairs) */ + int m_axis_array[JOYAXIS_MAX]; - int m_axis10,m_axis11; - int m_axis20,m_axis21; - + /* + *support for JOYHAT_MAX hats (each is a direction) + */ + int m_hat_array[JOYHAT_MAX]; + /* * Precision or range of the axes */ int m_prec; /* - * multiple axis values stored here - */ - int m_axisnum; - int m_axisvalue; - - /* - * max # of axes avail - */ - /*disabled - int m_axismax; - */ - - /* - * button values stored here - */ - int m_buttonnum; - - /* * max # of buttons avail */ @@ -90,18 +76,6 @@ class SCA_Joystick int m_buttonmax; int m_hatmax; - /* - * hat values stored here - */ - int m_hatnum; - int m_hatdir; - - /* - - * max # of hats avail - disabled - int m_hatmax; - */ /* is the joystick initialized ?*/ bool m_isinit; @@ -120,8 +94,11 @@ class SCA_Joystick void OnButtonUp(SDL_Event *sdl_event); void OnButtonDown(SDL_Event *sdl_event); void OnNothing(SDL_Event *sdl_event); +#if 0 /* not used yet */ void OnBallMotion(SDL_Event *sdl_event){} #endif + +#endif /* * Open the joystick */ @@ -135,24 +112,18 @@ class SCA_Joystick /* * fills the axis mnember values */ - void pFillAxes(void); void pFillButtons(void); /* - * returns m_axis10,m_axis11... + * returns m_axis_array */ int pAxisTest(int axisnum); /* - * returns m_axis10,m_axis11... + * returns m_axis_array */ int pGetAxis(int axisnum, int udlr); - /* - * gets the current hat direction - */ - int pGetHat(int direction); - SCA_Joystick(short int index); ~SCA_Joystick(); @@ -166,17 +137,14 @@ public: /* */ - bool aAnyAxisIsPositive(int axis); - bool aUpAxisIsPositive(int axis); - bool aDownAxisIsPositive(int axis); - bool aLeftAxisIsPositive(int axis); - bool aRightAxisIsPositive(int axis); + bool aAxisPairIsPositive(int axis); + bool aAxisPairDirectionIsPositive(int axis, int dir); /* function assumes joysticks are in axis pairs */ + bool aAxisIsPositive(int axis_single); /* check a single axis only */ bool aAnyButtonPressIsPositive(void); - bool aAnyButtonReleaseIsPositive(void); bool aButtonPressIsPositive(int button); bool aButtonReleaseIsPositive(int button); - bool aHatIsPositive(int dir); + bool aHatIsPositive(int hatnum, int dir); /* * precision is default '3200' which is overridden by input @@ -184,30 +152,12 @@ public: void cSetPrecision(int val); - int GetAxis10(void){ - - return m_axis10; - - } - - int GetAxis11(void){ - return m_axis11; - } - - int GetAxis20(void){ - return m_axis20; - } - - int GetAxis21(void){ - return m_axis21; - } - - int GetButton(void){ - return m_buttonnum; + int GetAxisPosition(int index){ + return m_axis_array[index]; } - int GetHat(void){ - return m_hatdir; + int GetHat(int index){ + return m_hat_array[index]; } int GetThreshold(void){ diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h b/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h index 73ffe1406d9..70619ff337a 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h +++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h @@ -39,5 +39,13 @@ #endif #define JOYINDEX_MAX 8 +#define JOYAXIS_MAX 16 +#define JOYBUT_MAX 18 +#define JOYHAT_MAX 4 + +#define JOYAXIS_RIGHT 0 +#define JOYAXIS_UP 1 +#define JOYAXIS_DOWN 3 +#define JOYAXIS_LEFT 2 #endif diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp index 73ca288861d..53d3be35f92 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp @@ -35,44 +35,37 @@ #ifndef DISABLE_SDL void SCA_Joystick::OnAxisMotion(SDL_Event* sdl_event) { - pFillAxes(); - m_axisnum = sdl_event->jaxis.axis; - m_axisvalue = sdl_event->jaxis.value; + if(sdl_event->jaxis.axis >= JOYAXIS_MAX) + return; + + m_axis_array[sdl_event->jaxis.axis]= sdl_event->jaxis.value; m_istrig_axis = 1; } - +/* See notes below in the event loop */ void SCA_Joystick::OnHatMotion(SDL_Event* sdl_event) { - m_hatdir = sdl_event->jhat.value; - m_hatnum = sdl_event->jhat.hat; + if(sdl_event->jhat.hat >= JOYHAT_MAX) + return; + + m_hat_array[sdl_event->jhat.hat]= sdl_event->jhat.value; m_istrig_hat = 1; } +/* See notes below in the event loop */ void SCA_Joystick::OnButtonUp(SDL_Event* sdl_event) { m_istrig_button = 1; - - /* this is needed for the "all events" option - * so we know if there are no buttons pressed */ - int i; - for (i=0; i<m_buttonmax; i++) { - if (SDL_JoystickGetButton(m_private->m_joystick, i)) { - m_buttonnum = i; - return; - } - } - m_buttonnum = -2; } void SCA_Joystick::OnButtonDown(SDL_Event* sdl_event) { - if(sdl_event->jbutton.button >= 0 || sdl_event->jbutton.button <= m_buttonmax) - { - m_istrig_button = 1; - m_buttonnum = sdl_event->jbutton.button; - } + //if(sdl_event->jbutton.button > m_buttonmax) /* unsigned int so always above 0 */ + // return; + // sdl_event->jbutton.button; + + m_istrig_button = 1; } @@ -81,22 +74,27 @@ void SCA_Joystick::OnNothing(SDL_Event* sdl_event) m_istrig_axis = m_istrig_button = m_istrig_hat = 0; } -/* only handle events for 1 joystick */ - void SCA_Joystick::HandleEvents(void) { SDL_Event sdl_event; int i; - for (i=0; i<JOYINDEX_MAX; i++) { + for (i=0; i<m_joynum; i++) { /* could use JOYINDEX_MAX but no reason to */ if(SCA_Joystick::m_instance[i]) SCA_Joystick::m_instance[i]->OnNothing(&sdl_event); } - if(SDL_PollEvent(&sdl_event)) + while(SDL_PollEvent(&sdl_event)) { /* Note! m_instance[sdl_event.jaxis.which] * will segfault if over JOYINDEX_MAX, not too nice but what are the chances? */ + + /* Note!, with buttons, this wont care which button is pressed, + * only to set 'm_istrig_button', actual pressed buttons are detected by SDL_JoystickGetButton */ + + /* Note!, if you manage to press and release a button within 1 logic tick + * it wont work as it should */ + switch(sdl_event.type) { case SDL_JOYAXISMOTION: @@ -111,9 +109,11 @@ void SCA_Joystick::HandleEvents(void) case SDL_JOYBUTTONDOWN: SCA_Joystick::m_instance[sdl_event.jbutton.which]->OnButtonDown(&sdl_event); break; +#if 0 /* Not used yet */ case SDL_JOYBALLMOTION: SCA_Joystick::m_instance[sdl_event.jball.which]->OnBallMotion(&sdl_event); break; +#endif default: printf("SCA_Joystick::HandleEvents, Unknown SDL event, this should not happen\n"); break; diff --git a/source/gameengine/GameLogic/Makefile b/source/gameengine/GameLogic/Makefile index 355ece6e8bd..a1794a60452 100644 --- a/source/gameengine/GameLogic/Makefile +++ b/source/gameengine/GameLogic/Makefile @@ -39,6 +39,7 @@ include nan_compile.mk CCFLAGS += $(LEVEL_1_CPP_WARNINGS) CPPFLAGS += -I../Expressions +CPPFLAGS += -I../SceneGraph CPPFLAGS += -I../Rasterizer CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include diff --git a/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp b/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp index 9ec4ea00337..9dfb5ddc38f 100644 --- a/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp +++ b/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp @@ -1,5 +1,29 @@ -#include "SCA_IActuator.h" +/** + * SCA_2DFilterActuator.cpp + * + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include "SCA_IActuator.h" #include "SCA_2DFilterActuator.h" #ifdef HAVE_CONFIG_H @@ -18,11 +42,10 @@ SCA_2DFilterActuator::SCA_2DFilterActuator( float float_arg, int int_arg, RAS_IRasterizer* rasterizer, - RAS_IRenderTools* rendertools, - PyTypeObject* T) - : SCA_IActuator(gameobj, T), + RAS_IRenderTools* rendertools) + : SCA_IActuator(gameobj), m_type(type), - m_flag(flag), + m_disableMotionBlur(flag), m_float_arg(float_arg), m_int_arg(int_arg), m_rasterizer(rasterizer), @@ -35,19 +58,11 @@ SCA_2DFilterActuator::SCA_2DFilterActuator( } } -void SCA_2DFilterActuator::SetShaderText(STR_String text) -{ - m_shaderText = text; -} - - CValue* SCA_2DFilterActuator::GetReplica() { SCA_2DFilterActuator* replica = new SCA_2DFilterActuator(*this); replica->ProcessReplica(); - CValue::AddDataToReplica(replica); - return replica; } @@ -63,7 +78,7 @@ bool SCA_2DFilterActuator::Update() if( m_type == RAS_2DFilterManager::RAS_2DFILTER_MOTIONBLUR ) { - if(!m_flag) + if(!m_disableMotionBlur) m_rasterizer->EnableMotionBlur(m_float_arg); else m_rasterizer->DisableMotionBlur(); @@ -74,45 +89,55 @@ bool SCA_2DFilterActuator::Update() { m_rendertools->Update2DFilter(m_propNames, m_gameObj, m_type, m_int_arg, m_shaderText); } - return true; + // once the filter is in place, no need to update it again => disable the actuator + return false; } -PyTypeObject SCA_2DFilterActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "SCA_2DFilterActuator", - sizeof(SCA_2DFilterActuator), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, - __repr, - 0, - 0, - 0, - 0, - 0 -}; +void SCA_2DFilterActuator::SetShaderText(const char *text) +{ + m_shaderText = text; +} + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ -PyParentObject SCA_2DFilterActuator::Parents[] = { - &SCA_2DFilterActuator::Type, - &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL -}; +/* Integration hooks ------------------------------------------------------- */ +PyTypeObject SCA_2DFilterActuator::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "SCA_2DFilterActuator", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_IActuator::Type, + 0,0,0,0,0,0, + py_base_new +}; PyMethodDef SCA_2DFilterActuator::Methods[] = { - /* add python functions to deal with m_msg... */ + /* add python functions to deal with m_msg... */ {NULL,NULL} }; - -PyObject* SCA_2DFilterActuator::_getattr(const STR_String& attr) { - _getattr_up(SCA_IActuator); -} +PyAttributeDef SCA_2DFilterActuator::Attributes[] = { + KX_PYATTRIBUTE_STRING_RW("shaderText", 0, 64000, false, SCA_2DFilterActuator, m_shaderText), + KX_PYATTRIBUTE_SHORT_RW("disableMotionBlur", 0, 1, true, SCA_2DFilterActuator, m_disableMotionBlur), + KX_PYATTRIBUTE_ENUM_RW("mode",RAS_2DFilterManager::RAS_2DFILTER_ENABLED,RAS_2DFilterManager::RAS_2DFILTER_NUMBER_OF_FILTERS,false,SCA_2DFilterActuator,m_type), + KX_PYATTRIBUTE_INT_RW("passNumber", 0, 100, true, SCA_2DFilterActuator, m_int_arg), + KX_PYATTRIBUTE_FLOAT_RW("value", 0.0, 100.0, SCA_2DFilterActuator, m_float_arg), + { NULL } //Sentinel +}; diff --git a/source/gameengine/GameLogic/SCA_2DFilterActuator.h b/source/gameengine/GameLogic/SCA_2DFilterActuator.h index 7ec07cf5b19..c357c4f3e37 100644 --- a/source/gameengine/GameLogic/SCA_2DFilterActuator.h +++ b/source/gameengine/GameLogic/SCA_2DFilterActuator.h @@ -1,3 +1,30 @@ +/** + * SCA_2DFilterActuator.h + * + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + #ifndef __SCA_2DFILETRACTUATOR_H__ #define __SCA_2DFILETRACTUATOR_H__ @@ -13,7 +40,7 @@ private: vector<STR_String> m_propNames; void * m_gameObj; RAS_2DFilterManager::RAS_2DFILTER_MODE m_type; - short m_flag; + short m_disableMotionBlur; float m_float_arg; int m_int_arg; STR_String m_shaderText; @@ -29,16 +56,12 @@ public: float float_arg, int int_arg, RAS_IRasterizer* rasterizer, - RAS_IRenderTools* rendertools, - PyTypeObject* T=&Type - ); + RAS_IRenderTools* rendertools); - void SetShaderText(STR_String text); + void SetShaderText(const char *text); virtual ~SCA_2DFilterActuator(); virtual bool Update(); virtual CValue* GetReplica(); - virtual PyObject* _getattr(const STR_String& attr); - }; #endif diff --git a/source/gameengine/GameLogic/SCA_ANDController.cpp b/source/gameengine/GameLogic/SCA_ANDController.cpp index cfc2d25e0ae..ac9e238bd64 100644 --- a/source/gameengine/GameLogic/SCA_ANDController.cpp +++ b/source/gameengine/GameLogic/SCA_ANDController.cpp @@ -42,10 +42,9 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_ANDController::SCA_ANDController(SCA_IObject* gameobj, - PyTypeObject* T) +SCA_ANDController::SCA_ANDController(SCA_IObject* gameobj) : - SCA_IController(gameobj,T) + SCA_IController(gameobj) { } @@ -66,26 +65,19 @@ void SCA_ANDController::Trigger(SCA_LogicManager* logicmgr) !(is==m_linkedsensors.end());is++) { SCA_ISensor* sensor = *is; - if (!sensor->IsPositiveTrigger()) + if (!sensor->GetState()) { sensorresult = false; break; } } - CValue* newevent = new CBoolValue(sensorresult); - for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin(); !(i==m_linkedactuators.end());i++) { - SCA_IActuator* actua = *i;//m_linkedactuators.at(i); - logicmgr->AddActiveActuator(actua,newevent); + SCA_IActuator* actua = *i; + logicmgr->AddActiveActuator(actua,sensorresult); } - - // every actuator that needs the event, has a it's own reference to it now so - // release it (so to be clear: if there is no actuator, it's deleted right now) - newevent->Release(); - } @@ -94,7 +86,7 @@ CValue* SCA_ANDController::GetReplica() { CValue* replica = new SCA_ANDController(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } @@ -107,38 +99,33 @@ CValue* SCA_ANDController::GetReplica() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_ANDController::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_ANDController", - sizeof(SCA_ANDController), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_ANDController::Parents[] = { - &SCA_ANDController::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IController::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_ANDController::Methods[] = { {NULL,NULL} //Sentinel }; -PyObject* SCA_ANDController::_getattr(const STR_String& attr) { - _getattr_up(SCA_IController); -} +PyAttributeDef SCA_ANDController::Attributes[] = { + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/GameLogic/SCA_ANDController.h b/source/gameengine/GameLogic/SCA_ANDController.h index 376f4a9a876..cb16d7fca01 100644 --- a/source/gameengine/GameLogic/SCA_ANDController.h +++ b/source/gameengine/GameLogic/SCA_ANDController.h @@ -39,17 +39,10 @@ class SCA_ANDController : public SCA_IController Py_Header; //virtual void Trigger(class SCA_LogicManager* logicmgr); public: - SCA_ANDController(SCA_IObject* gameobj,PyTypeObject* T=&Type); + SCA_ANDController(SCA_IObject* gameobj); virtual ~SCA_ANDController(); virtual CValue* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); - - /* --------------------------------------------------------------------- */ - /* Python interface ---------------------------------------------------- */ - /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - }; #endif //__KX_ANDCONTROLLER diff --git a/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp b/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp index 768a3a45937..a80b2af55c8 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp @@ -51,17 +51,19 @@ SCA_ActuatorEventManager::~SCA_ActuatorEventManager() void SCA_ActuatorEventManager::NextFrame() { // check for changed actuator - for (set<SCA_ISensor*>::const_iterator it = m_sensors.begin();!(it==m_sensors.end());it++) + SG_DList::iterator<SCA_ISensor> it(m_sensors); + for (it.begin();!it.end();++it) { - (*it)->Activate(m_logicmgr,NULL); + (*it)->Activate(m_logicmgr); } } void SCA_ActuatorEventManager::UpdateFrame() { // update the state of actuator before executing them - for (set<SCA_ISensor*>::const_iterator it = m_sensors.begin();!(it==m_sensors.end());it++) + SG_DList::iterator<SCA_ActuatorSensor> it(m_sensors); + for (it.begin();!it.end();++it) { - ((SCA_ActuatorSensor*)(*it))->Update(); + (*it)->Update(); } }
\ No newline at end of file diff --git a/source/gameengine/GameLogic/SCA_ActuatorEventManager.h b/source/gameengine/GameLogic/SCA_ActuatorEventManager.h index a7d61627c23..f3884c87a75 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorEventManager.h +++ b/source/gameengine/GameLogic/SCA_ActuatorEventManager.h @@ -45,6 +45,13 @@ public: virtual void NextFrame(); virtual void UpdateFrame(); //SCA_LogicManager* GetLogicManager() { return m_logicmgr;} + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_ActuatorEventManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_ACTUATOREVENTMANAGER diff --git a/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp b/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp index 7c37b237d60..428362a0a24 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp +++ b/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp @@ -40,9 +40,8 @@ SCA_ActuatorSensor::SCA_ActuatorSensor(SCA_EventManager* eventmgr, SCA_IObject* gameobj, - const STR_String& actname, - PyTypeObject* T ) - : SCA_ISensor(gameobj,eventmgr,T), + const STR_String& actname) + : SCA_ISensor(gameobj,eventmgr), m_checkactname(actname) { m_actuator = GetParent()->FindActuator(m_checkactname); @@ -60,7 +59,7 @@ CValue* SCA_ActuatorSensor::GetReplica() { SCA_ActuatorSensor* replica = new SCA_ActuatorSensor(*this); // m_range_expr must be recalculated on replica! - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); replica->Init(); return replica; @@ -89,7 +88,7 @@ SCA_ActuatorSensor::~SCA_ActuatorSensor() -bool SCA_ActuatorSensor::Evaluate(CValue* event) +bool SCA_ActuatorSensor::Evaluate() { if (m_actuator) { @@ -122,75 +121,46 @@ void SCA_ActuatorSensor::Update() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_ActuatorSensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_ActuatorSensor", - sizeof(SCA_ActuatorSensor), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_ActuatorSensor::Parents[] = { - &SCA_ActuatorSensor::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_ActuatorSensor::Methods[] = { - {"getActuator", (PyCFunction) SCA_ActuatorSensor::sPyGetActuator, METH_NOARGS, (PY_METHODCHAR)GetActuator_doc}, - {"setActuator", (PyCFunction) SCA_ActuatorSensor::sPySetActuator, METH_VARARGS, (PY_METHODCHAR)SetActuator_doc}, {NULL,NULL} //Sentinel }; -PyObject* SCA_ActuatorSensor::_getattr(const STR_String& attr) { - _getattr_up(SCA_ISensor); /* implicit return! */ -} - -/* 3. getActuator */ -const char SCA_ActuatorSensor::GetActuator_doc[] = -"getActuator()\n" -"\tReturn the Actuator with which the sensor operates.\n"; -PyObject* SCA_ActuatorSensor::PyGetActuator(PyObject* self) -{ - return PyString_FromString(m_checkactname); -} +PyAttributeDef SCA_ActuatorSensor::Attributes[] = { + KX_PYATTRIBUTE_STRING_RW_CHECK("actuator",0,100,false,SCA_ActuatorSensor,m_checkactname,CheckActuator), + { NULL } //Sentinel +}; -/* 4. setActuator */ -const char SCA_ActuatorSensor::SetActuator_doc[] = -"setActuator(name)\n" -"\t- name: string\n" -"\tSets the Actuator with which to operate. If there is no Actuator\n" -"\tof this name, the call is ignored.\n"; -PyObject* SCA_ActuatorSensor::PySetActuator(PyObject* self, PyObject* args, PyObject* kwds) +int SCA_ActuatorSensor::CheckActuator(void *self, const PyAttributeDef*) { - /* We should query whether the name exists. Or should we create a prop */ - /* on the fly? */ - char *actNameArg = NULL; - - if (!PyArg_ParseTuple(args, "s", &actNameArg)) { - return NULL; - } - - SCA_IActuator* act = GetParent()->FindActuator(STR_String(actNameArg)); + SCA_ActuatorSensor* sensor = reinterpret_cast<SCA_ActuatorSensor*>(self); + SCA_IActuator* act = sensor->GetParent()->FindActuator(sensor->m_checkactname); if (act) { - m_checkactname = actNameArg; - m_actuator = act; - } else { - ; /* error: bad actuator name */ + sensor->m_actuator = act; + return 0; } - Py_Return; + PyErr_SetString(PyExc_AttributeError, "string does not correspond to an actuator"); + return 1; } /* eof */ diff --git a/source/gameengine/GameLogic/SCA_ActuatorSensor.h b/source/gameengine/GameLogic/SCA_ActuatorSensor.h index a71145f6852..1a095148500 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorSensor.h +++ b/source/gameengine/GameLogic/SCA_ActuatorSensor.h @@ -46,13 +46,12 @@ class SCA_ActuatorSensor : public SCA_ISensor public: SCA_ActuatorSensor(class SCA_EventManager* eventmgr, SCA_IObject* gameobj, - const STR_String& actname, - PyTypeObject* T=&Type ); + const STR_String& actname); virtual ~SCA_ActuatorSensor(); virtual CValue* GetReplica(); virtual void Init(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void ReParent(SCA_IObject* parent); void Update(); @@ -60,14 +59,8 @@ public: /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - - /* 3. setProperty */ - KX_PYMETHOD_DOC(SCA_ActuatorSensor,SetActuator); - /* 4. getProperty */ - KX_PYMETHOD_DOC_NOARGS(SCA_ActuatorSensor,GetActuator); + static int CheckActuator(void *self, const PyAttributeDef*); }; #endif diff --git a/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp b/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp index 4cd2dfba994..dd3b55abcc9 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp @@ -51,9 +51,10 @@ SCA_AlwaysEventManager::SCA_AlwaysEventManager(class SCA_LogicManager* logicmgr) void SCA_AlwaysEventManager::NextFrame() { - for (set<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++) + SG_DList::iterator<SCA_ISensor> it(m_sensors); + for (it.begin();!it.end();++it) { - (*i)->Activate(m_logicmgr, NULL); + (*it)->Activate(m_logicmgr); } } diff --git a/source/gameengine/GameLogic/SCA_AlwaysEventManager.h b/source/gameengine/GameLogic/SCA_AlwaysEventManager.h index a619eecddd4..9540e3b71f6 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysEventManager.h +++ b/source/gameengine/GameLogic/SCA_AlwaysEventManager.h @@ -41,6 +41,11 @@ public: virtual void NextFrame(); +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_AlwaysEventManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_ALWAYSEVENTMGR diff --git a/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp b/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp index f9fbf2387c4..35b035f6466 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp +++ b/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp @@ -48,9 +48,8 @@ /* ------------------------------------------------------------------------- */ SCA_AlwaysSensor::SCA_AlwaysSensor(class SCA_EventManager* eventmgr, - SCA_IObject* gameobj, - PyTypeObject* T) - : SCA_ISensor(gameobj,eventmgr, T) + SCA_IObject* gameobj) + : SCA_ISensor(gameobj,eventmgr) { //SetDrawColor(255,0,0); Init(); @@ -72,7 +71,7 @@ CValue* SCA_AlwaysSensor::GetReplica() { CValue* replica = new SCA_AlwaysSensor(*this);//m_float,GetName()); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } @@ -86,7 +85,7 @@ bool SCA_AlwaysSensor::IsPositiveTrigger() -bool SCA_AlwaysSensor::Evaluate(CValue* event) +bool SCA_AlwaysSensor::Evaluate() { /* Nice! :) */ //return true; @@ -105,38 +104,33 @@ bool SCA_AlwaysSensor::Evaluate(CValue* event) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_AlwaysSensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_AlwaysSensor", - sizeof(SCA_AlwaysSensor), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_AlwaysSensor::Parents[] = { - &SCA_AlwaysSensor::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_AlwaysSensor::Methods[] = { {NULL,NULL} //Sentinel }; -PyObject* SCA_AlwaysSensor::_getattr(const STR_String& attr) { - _getattr_up(SCA_ISensor); -} +PyAttributeDef SCA_AlwaysSensor::Attributes[] = { + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/GameLogic/SCA_AlwaysSensor.h b/source/gameengine/GameLogic/SCA_AlwaysSensor.h index 8bf2a8aa98e..d58e05564d1 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysSensor.h +++ b/source/gameengine/GameLogic/SCA_AlwaysSensor.h @@ -39,22 +39,12 @@ class SCA_AlwaysSensor : public SCA_ISensor bool m_alwaysresult; public: SCA_AlwaysSensor(class SCA_EventManager* eventmgr, - SCA_IObject* gameobj, - PyTypeObject* T =&Type); + SCA_IObject* gameobj); virtual ~SCA_AlwaysSensor(); virtual CValue* GetReplica(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void Init(); - - - /* --------------------------------------------------------------------- */ - /* Python interface ---------------------------------------------------- */ - /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - - }; #endif //__KX_ALWAYSSENSOR diff --git a/source/gameengine/GameLogic/SCA_DelaySensor.cpp b/source/gameengine/GameLogic/SCA_DelaySensor.cpp index f15d4c7249f..0f67ddd56a5 100644 --- a/source/gameengine/GameLogic/SCA_DelaySensor.cpp +++ b/source/gameengine/GameLogic/SCA_DelaySensor.cpp @@ -51,12 +51,11 @@ SCA_DelaySensor::SCA_DelaySensor(class SCA_EventManager* eventmgr, SCA_IObject* gameobj, int delay, int duration, - bool repeat, - PyTypeObject* T) - : SCA_ISensor(gameobj,eventmgr, T), + bool repeat) + : SCA_ISensor(gameobj,eventmgr), + m_repeat(repeat), m_delay(delay), - m_duration(duration), - m_repeat(repeat) + m_duration(duration) { Init(); } @@ -77,7 +76,7 @@ CValue* SCA_DelaySensor::GetReplica() { CValue* replica = new SCA_DelaySensor(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } @@ -89,7 +88,7 @@ bool SCA_DelaySensor::IsPositiveTrigger() return (m_invert ? !m_lastResult : m_lastResult); } -bool SCA_DelaySensor::Evaluate(CValue* event) +bool SCA_DelaySensor::Evaluate() { bool trigger = false; bool result; @@ -131,127 +130,36 @@ bool SCA_DelaySensor::Evaluate(CValue* event) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_DelaySensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_DelaySensor", - sizeof(SCA_DelaySensor), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_DelaySensor::Parents[] = { - &SCA_DelaySensor::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_DelaySensor::Methods[] = { - /* setProperty */ - {"setDelay", (PyCFunction) SCA_DelaySensor::sPySetDelay, METH_VARARGS, (PY_METHODCHAR)SetDelay_doc}, - {"setDuration", (PyCFunction) SCA_DelaySensor::sPySetDuration, METH_VARARGS, (PY_METHODCHAR)SetDuration_doc}, - {"setRepeat", (PyCFunction) SCA_DelaySensor::sPySetRepeat, METH_VARARGS, (PY_METHODCHAR)SetRepeat_doc}, - /* getProperty */ - {"getDelay", (PyCFunction) SCA_DelaySensor::sPyGetDelay, METH_NOARGS, (PY_METHODCHAR)GetDelay_doc}, - {"getDuration", (PyCFunction) SCA_DelaySensor::sPyGetDuration, METH_NOARGS, (PY_METHODCHAR)GetDuration_doc}, - {"getRepeat", (PyCFunction) SCA_DelaySensor::sPyGetRepeat, METH_NOARGS, (PY_METHODCHAR)GetRepeat_doc}, {NULL,NULL} //Sentinel }; -PyObject* SCA_DelaySensor::_getattr(const STR_String& attr) { - _getattr_up(SCA_ISensor); -} - -const char SCA_DelaySensor::SetDelay_doc[] = -"setDelay(delay)\n" -"\t- delay: length of the initial OFF period as number of frame\n" -"\t 0 for immediate trigger\n" -"\tSet the initial delay before the positive trigger\n"; -PyObject* SCA_DelaySensor::PySetDelay(PyObject* self, PyObject* args, PyObject* kwds) -{ - int delay; - - if(!PyArg_ParseTuple(args, "i", &delay)) { - return NULL; - } - if (delay < 0) { - PyErr_SetString(PyExc_ValueError, "Delay cannot be negative"); - return NULL; - } - m_delay = delay; - Py_Return; -} - -const char SCA_DelaySensor::SetDuration_doc[] = -"setDuration(duration)\n" -"\t- duration: length of the ON period in number of frame after the initial off period\n" -"\t 0 for no ON period\n" -"\tSet the duration of the ON pulse after initial delay.\n" -"\tIf > 0, a negative trigger is fired at the end of the ON pulse.\n"; -PyObject* SCA_DelaySensor::PySetDuration(PyObject* self, PyObject* args, PyObject* kwds) -{ - int duration; - - if(!PyArg_ParseTuple(args, "i", &duration)) { - return NULL; - } - if (duration < 0) { - PyErr_SetString(PyExc_ValueError, "Duration cannot be negative"); - return NULL; - } - m_duration = duration; - Py_Return; -} - -const char SCA_DelaySensor::SetRepeat_doc[] = -"setRepeat(repeat)\n" -"\t- repeat: 1 if the initial OFF-ON cycle should be repeated indefinately\n" -"\t 0 if the initial OFF-ON cycle should run only once\n" -"\tSet the sensor repeat mode\n"; -PyObject* SCA_DelaySensor::PySetRepeat(PyObject* self, PyObject* args, PyObject* kwds) -{ - int repeat; - - if(!PyArg_ParseTuple(args, "i", &repeat)) { - return NULL; - } - m_repeat = (repeat != 0); - Py_Return; -} - -const char SCA_DelaySensor::GetDelay_doc[] = -"getDelay()\n" -"\tReturn the delay parameter value\n"; -PyObject* SCA_DelaySensor::PyGetDelay(PyObject* self) -{ - return PyInt_FromLong(m_delay); -} - -const char SCA_DelaySensor::GetDuration_doc[] = -"getDuration()\n" -"\tReturn the duration parameter value\n"; -PyObject* SCA_DelaySensor::PyGetDuration(PyObject* self) -{ - return PyInt_FromLong(m_duration); -} - -const char SCA_DelaySensor::GetRepeat_doc[] = -"getRepeat()\n" -"\tReturn the repeat parameter value\n"; -PyObject* SCA_DelaySensor::PyGetRepeat(PyObject* self) -{ - return BoolToPyArg(m_repeat); -} +PyAttributeDef SCA_DelaySensor::Attributes[] = { + KX_PYATTRIBUTE_INT_RW("delay",0,100000,true,SCA_DelaySensor,m_delay), + KX_PYATTRIBUTE_INT_RW("duration",0,100000,true,SCA_DelaySensor,m_duration), + KX_PYATTRIBUTE_BOOL_RW("repeat",SCA_DelaySensor,m_repeat), + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/GameLogic/SCA_DelaySensor.h b/source/gameengine/GameLogic/SCA_DelaySensor.h index a997fabe3cd..187a9179b5d 100644 --- a/source/gameengine/GameLogic/SCA_DelaySensor.h +++ b/source/gameengine/GameLogic/SCA_DelaySensor.h @@ -47,11 +47,10 @@ public: SCA_IObject* gameobj, int delay, int duration, - bool repeat, - PyTypeObject* T =&Type); + bool repeat); virtual ~SCA_DelaySensor(); virtual CValue* GetReplica(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void Init(); @@ -59,17 +58,7 @@ public: /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - /* setProperty */ - KX_PYMETHOD_DOC(SCA_DelaySensor,SetDelay); - KX_PYMETHOD_DOC(SCA_DelaySensor,SetDuration); - KX_PYMETHOD_DOC(SCA_DelaySensor,SetRepeat); - /* getProperty */ - KX_PYMETHOD_DOC_NOARGS(SCA_DelaySensor,GetDelay); - KX_PYMETHOD_DOC_NOARGS(SCA_DelaySensor,GetDuration); - KX_PYMETHOD_DOC_NOARGS(SCA_DelaySensor,GetRepeat); }; diff --git a/source/gameengine/GameLogic/SCA_EventManager.cpp b/source/gameengine/GameLogic/SCA_EventManager.cpp index e4fd0379597..d1301541a0a 100644 --- a/source/gameengine/GameLogic/SCA_EventManager.cpp +++ b/source/gameengine/GameLogic/SCA_EventManager.cpp @@ -28,6 +28,7 @@ #include <assert.h> #include "SCA_EventManager.h" +#include "SCA_ISensor.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -43,16 +44,18 @@ SCA_EventManager::SCA_EventManager(EVENT_MANAGER_TYPE mgrtype) SCA_EventManager::~SCA_EventManager() { + // all sensors should be removed + assert(m_sensors.Empty()); } void SCA_EventManager::RegisterSensor(class SCA_ISensor* sensor) { - m_sensors.insert(sensor); + m_sensors.AddBack(sensor); } void SCA_EventManager::RemoveSensor(class SCA_ISensor* sensor) { - m_sensors.erase(sensor); + sensor->Delink(); } void SCA_EventManager::NextFrame(double curtime, double fixedtime) diff --git a/source/gameengine/GameLogic/SCA_EventManager.h b/source/gameengine/GameLogic/SCA_EventManager.h index 9dbb5a6d24f..424150ffa63 100644 --- a/source/gameengine/GameLogic/SCA_EventManager.h +++ b/source/gameengine/GameLogic/SCA_EventManager.h @@ -33,11 +33,14 @@ #include <set> #include <algorithm> +#include "SG_DList.h" + class SCA_EventManager { protected: // use a set to speed-up insertion/removal - std::set <class SCA_ISensor*> m_sensors; + //std::set <class SCA_ISensor*> m_sensors; + SG_DList m_sensors; public: enum EVENT_MANAGER_TYPE { @@ -68,6 +71,13 @@ public: protected: EVENT_MANAGER_TYPE m_mgrtype; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_EventManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/GameLogic/SCA_ExpressionController.cpp b/source/gameengine/GameLogic/SCA_ExpressionController.cpp index e9a543c9f31..60969300474 100644 --- a/source/gameengine/GameLogic/SCA_ExpressionController.cpp +++ b/source/gameengine/GameLogic/SCA_ExpressionController.cpp @@ -46,10 +46,10 @@ /* ------------------------------------------------------------------------- */ SCA_ExpressionController::SCA_ExpressionController(SCA_IObject* gameobj, - const STR_String& exprtext, - PyTypeObject* T) - :SCA_IController(gameobj,T), - m_exprText(exprtext) + const STR_String& exprtext) + :SCA_IController(gameobj), + m_exprText(exprtext), + m_exprCache(NULL) { } @@ -57,6 +57,8 @@ SCA_ExpressionController::SCA_ExpressionController(SCA_IObject* gameobj, SCA_ExpressionController::~SCA_ExpressionController() { + if (m_exprCache) + m_exprCache->Release(); } @@ -65,25 +67,40 @@ CValue* SCA_ExpressionController::GetReplica() { SCA_ExpressionController* replica = new SCA_ExpressionController(*this); replica->m_exprText = m_exprText; + replica->m_exprCache = NULL; // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } +// Forced deletion of precalculated expression to break reference loop +// Use this function when you know that you won't use the sensor anymore +void SCA_ExpressionController::Delete() +{ + if (m_exprCache) + { + m_exprCache->Release(); + m_exprCache = NULL; + } + Release(); +} + void SCA_ExpressionController::Trigger(SCA_LogicManager* logicmgr) { bool expressionresult = false; - - CParser parser; - parser.SetContext(this->AddRef()); - CExpression* expr = parser.ProcessText(m_exprText); - if (expr) + if (!m_exprCache) + { + CParser parser; + parser.SetContext(this->AddRef()); + m_exprCache = parser.ProcessText(m_exprText); + } + if (m_exprCache) { - CValue* value = expr->Calculate(); + CValue* value = m_exprCache->Calculate(); if (value) { if (value->IsError()) @@ -91,42 +108,20 @@ void SCA_ExpressionController::Trigger(SCA_LogicManager* logicmgr) printf(value->GetText()); } else { - float num = value->GetNumber(); + float num = (float)value->GetNumber(); expressionresult = !MT_fuzzyZero(num); } value->Release(); } - expr->Release(); - } - - /* - - for (vector<SCA_ISensor*>::const_iterator is=m_linkedsensors.begin(); - !(is==m_linkedsensors.end());is++) - { - SCA_ISensor* sensor = *is; - if (!sensor->IsPositiveTrigger()) - { - sensorresult = false; - break; - } } - - */ - - CValue* newevent = new CBoolValue(expressionresult); for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin(); !(i==m_linkedactuators.end());i++) { SCA_IActuator* actua = *i; - logicmgr->AddActiveActuator(actua,newevent); + logicmgr->AddActiveActuator(actua,expressionresult); } - //printf("expr %d.",expressionresult); - // every actuator that needs the event, has a it's own reference to it now so - // release it (so to be clear: if there is no actuator, it's deleted right now) - newevent->Release(); } @@ -142,7 +137,7 @@ CValue* SCA_ExpressionController::FindIdentifier(const STR_String& identifiernam SCA_ISensor* sensor = *is; if (sensor->GetName() == identifiername) { - identifierval = new CBoolValue(sensor->IsPositiveTrigger()); + identifierval = new CBoolValue(sensor->GetState()); //identifierval = sensor->AddRef(); } diff --git a/source/gameengine/GameLogic/SCA_ExpressionController.h b/source/gameengine/GameLogic/SCA_ExpressionController.h index f1db45a19e0..4c1dfcb95a2 100644 --- a/source/gameengine/GameLogic/SCA_ExpressionController.h +++ b/source/gameengine/GameLogic/SCA_ExpressionController.h @@ -38,23 +38,28 @@ class SCA_ExpressionController : public SCA_IController { // Py_Header; STR_String m_exprText; + CExpression* m_exprCache; public: SCA_ExpressionController(SCA_IObject* gameobj, - const STR_String& exprtext, - PyTypeObject* T=&Type ); + const STR_String& exprtext); virtual ~SCA_ExpressionController(); virtual CValue* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); virtual CValue* FindIdentifier(const STR_String& identifiername); + /** + * used to release the expression cache + * so that self references are removed before the controller itself is released + */ + virtual void Delete(); - /* --------------------------------------------------------------------- */ - /* Python interface ---------------------------------------------------- */ - /* --------------------------------------------------------------------- */ - -// virtual PyObject* _getattr(const STR_String& attr); +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_ExpressionController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_EXPRESSIONCONTROLLER diff --git a/source/gameengine/GameLogic/SCA_IActuator.cpp b/source/gameengine/GameLogic/SCA_IActuator.cpp index eeca2d7b44c..0fda75590c1 100644 --- a/source/gameengine/GameLogic/SCA_IActuator.cpp +++ b/source/gameengine/GameLogic/SCA_IActuator.cpp @@ -34,56 +34,15 @@ using namespace std; -SCA_IActuator::SCA_IActuator(SCA_IObject* gameobj, - PyTypeObject* T) : +SCA_IActuator::SCA_IActuator(SCA_IObject* gameobj) : + SCA_ILogicBrick(gameobj), m_links(0), - SCA_ILogicBrick(gameobj,T) + m_posevent(false), + m_negevent(false) { // nothing to do } - - -void SCA_IActuator::AddEvent(CValue* event) -{ - m_events.push_back(event); -} - - - -void SCA_IActuator::RemoveAllEvents() -{ // remove event queue! - for (vector<CValue*>::iterator i=m_events.begin(); !(i==m_events.end());i++) - { - (*i)->Release(); - } - m_events.clear(); -} - - - - - -bool SCA_IActuator::IsNegativeEvent() const -{ - bool bPositiveEvent(false); - bool bNegativeEvent(false); - - for (vector<CValue*>::const_iterator i=m_events.begin(); i!=m_events.end();++i) - { - if ((*i)->GetNumber() == 0.0f) - { - bNegativeEvent = true; - } else { - bPositiveEvent = true; - } - } - - // if at least 1 positive event, return false - - return !bPositiveEvent && bNegativeEvent; -} - bool SCA_IActuator::Update(double curtime, bool frame) { if (frame) @@ -98,9 +57,34 @@ bool SCA_IActuator::Update() return false; } +void SCA_IActuator::Activate(SG_DList& head) +{ + if (QEmpty()) + { + InsertActiveQList(m_gameobj->m_activeActuators); + head.AddBack(&m_gameobj->m_activeActuators); + } +} + +// this function is only used to deactivate actuators outside the logic loop +// e.g. when an object is deleted. +void SCA_IActuator::Deactivate() +{ + if (QDelink()) + { + // the actuator was in the active list + if (m_gameobj->m_activeActuators.QEmpty()) + // the owner object has no more active actuators, remove it from the global list + m_gameobj->m_activeActuators.Delink(); + } +} + + void SCA_IActuator::ProcessReplica() { - m_events.clear(); + SCA_ILogicBrick::ProcessReplica(); + RemoveAllEvents(); + m_linkedcontrollers.clear(); } @@ -119,3 +103,36 @@ void SCA_IActuator::DecLink() m_links = 0; } } + +void SCA_IActuator::LinkToController(SCA_IController* controller) +{ + m_linkedcontrollers.push_back(controller); +} + +void SCA_IActuator::UnlinkController(SCA_IController* controller) +{ + std::vector<class SCA_IController*>::iterator contit; + for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit) + { + if ((*contit) == controller) + { + *contit = m_linkedcontrollers.back(); + m_linkedcontrollers.pop_back(); + return; + } + } + printf("Missing link from actuator %s:%s to controller %s:%s\n", + m_gameobj->GetName().ReadPtr(), GetName().ReadPtr(), + controller->GetParent()->GetName().ReadPtr(), controller->GetName().ReadPtr()); +} + +void SCA_IActuator::UnlinkAllControllers() +{ + std::vector<class SCA_IController*>::iterator contit; + for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit) + { + (*contit)->UnlinkActuator(this); + } + m_linkedcontrollers.clear(); +} + diff --git a/source/gameengine/GameLogic/SCA_IActuator.h b/source/gameengine/GameLogic/SCA_IActuator.h index 7ffb21b5490..00ba8c9ce4e 100644 --- a/source/gameengine/GameLogic/SCA_IActuator.h +++ b/source/gameengine/GameLogic/SCA_IActuator.h @@ -29,25 +29,39 @@ #ifndef __KX_IACTUATOR #define __KX_IACTUATOR -#include "SCA_ILogicBrick.h" +#include "SCA_IController.h" #include <vector> +/* + * Use of SG_DList : None + * Use of SG_QList : element of activated actuator list of their owner + * Head: SCA_IObject::m_activeActuators + */ class SCA_IActuator : public SCA_ILogicBrick { friend class SCA_LogicManager; protected: - std::vector<CValue*> m_events; int m_links; // number of active links to controllers // when 0, the actuator is automatically stopped - void RemoveAllEvents(); + //std::vector<CValue*> m_events; + bool m_posevent; + bool m_negevent; + + std::vector<class SCA_IController*> m_linkedcontrollers; + + void RemoveAllEvents() + { + m_posevent = false; + m_negevent = false; + } + public: /** * This class also inherits the default copy constructors */ - SCA_IActuator(SCA_IObject* gameobj, - PyTypeObject* T =&Type); + SCA_IActuator(SCA_IObject* gameobj); /** * UnlinkObject(...) @@ -75,7 +89,15 @@ public: /** * Add an event to an actuator. */ - void AddEvent(CValue* event); + //void AddEvent(CValue* event) + void AddEvent(bool event) + { + if (event) + m_posevent = true; + else + m_negevent = true; + } + virtual void ProcessReplica(); /** @@ -84,13 +106,34 @@ public: * not immediately clear. But usually refers to key-up events * or events where no action is required. */ - bool IsNegativeEvent() const; + bool IsNegativeEvent() const + { + return !m_posevent && m_negevent; + } + virtual ~SCA_IActuator(); + /** + * remove this actuator from the list of active actuators + */ + virtual void Deactivate(); + virtual void Activate(SG_DList& head); + + void LinkToController(SCA_IController* controller); + void UnlinkController(class SCA_IController* cont); + void UnlinkAllControllers(); + void ClrLink() { m_links=0; } void IncLink() { m_links++; } void DecLink(); bool IsNoLink() const { return !m_links; } + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_IActuator"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_IACTUATOR diff --git a/source/gameengine/GameLogic/SCA_IController.cpp b/source/gameengine/GameLogic/SCA_IController.cpp index 0bd20117f31..7cfd2adc1d0 100644 --- a/source/gameengine/GameLogic/SCA_IController.cpp +++ b/source/gameengine/GameLogic/SCA_IController.cpp @@ -30,16 +30,18 @@ #include "SCA_LogicManager.h" #include "SCA_IActuator.h" #include "SCA_ISensor.h" +#include "PyObjectPlus.h" +#include "../Ketsji/KX_PythonSeq.h" /* not nice, only need for KX_PythonSeq_CreatePyObject */ #ifdef HAVE_CONFIG_H #include <config.h> #endif -SCA_IController::SCA_IController(SCA_IObject* gameobj, - PyTypeObject* T) +SCA_IController::SCA_IController(SCA_IObject* gameobj) : + SCA_ILogicBrick(gameobj), m_statemask(0), - SCA_ILogicBrick(gameobj,T) + m_justActivated(false) { } @@ -47,19 +49,19 @@ SCA_IController::SCA_IController(SCA_IObject* gameobj, SCA_IController::~SCA_IController() { - UnlinkAllActuators(); + //UnlinkAllActuators(); } -const std::vector<class SCA_ISensor*>& SCA_IController::GetLinkedSensors() +std::vector<class SCA_ISensor*>& SCA_IController::GetLinkedSensors() { return m_linkedsensors; } -const std::vector<class SCA_IActuator*>& SCA_IController::GetLinkedActuators() +std::vector<class SCA_IActuator*>& SCA_IController::GetLinkedActuators() { return m_linkedactuators; } @@ -68,13 +70,14 @@ const std::vector<class SCA_IActuator*>& SCA_IController::GetLinkedActuators() void SCA_IController::UnlinkAllSensors() { - if (IsActive()) + std::vector<class SCA_ISensor*>::iterator sensit; + for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) { - std::vector<class SCA_ISensor*>::iterator sensit; - for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) + if (IsActive()) { (*sensit)->DecLink(); } + (*sensit)->UnlinkController(this); } m_linkedsensors.clear(); } @@ -83,34 +86,18 @@ void SCA_IController::UnlinkAllSensors() void SCA_IController::UnlinkAllActuators() { - if (IsActive()) + std::vector<class SCA_IActuator*>::iterator actit; + for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit) { - std::vector<class SCA_IActuator*>::iterator actit; - for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit) + if (IsActive()) { (*actit)->DecLink(); } + (*actit)->UnlinkController(this); } m_linkedactuators.clear(); } - - -/* -void SCA_IController::Trigger(SCA_LogicManager* logicmgr) -{ - //for (int i=0;i<m_linkedactuators.size();i++) - for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin(); - !(i==m_linkedactuators.end());i++) - { - SCA_IActuator* actua = *i;//m_linkedactuators.at(i); - - logicmgr->AddActiveActuator(actua); - } - -} -*/ - void SCA_IController::LinkToActuator(SCA_IActuator* actua) { m_linkedactuators.push_back(actua); @@ -127,18 +114,18 @@ void SCA_IController::UnlinkActuator(class SCA_IActuator* actua) { if ((*actit) == actua) { - break; - } - - } - if (!(actit==m_linkedactuators.end())) - { - if (IsActive()) - { - (*actit)->DecLink(); + if (IsActive()) + { + (*actit)->DecLink(); + } + *actit = m_linkedactuators.back(); + m_linkedactuators.pop_back(); + return; } - m_linkedactuators.erase(actit); } + printf("Missing link from controller %s:%s to actuator %s:%s\n", + m_gameobj->GetName().ReadPtr(), GetName().ReadPtr(), + actua->GetParent()->GetName().ReadPtr(), actua->GetName().ReadPtr()); } void SCA_IController::LinkToSensor(SCA_ISensor* sensor) @@ -157,20 +144,21 @@ void SCA_IController::UnlinkSensor(class SCA_ISensor* sensor) { if ((*sensit) == sensor) { - break; - } - - } - if (!(sensit==m_linkedsensors.end())) - { - if (IsActive()) - { - (*sensit)->DecLink(); + if (IsActive()) + { + sensor->DecLink(); + } + *sensit = m_linkedsensors.back(); + m_linkedsensors.pop_back(); + return; } - m_linkedsensors.erase(sensit); } + printf("Missing link from controller %s:%s to sensor %s:%s\n", + m_gameobj->GetName().ReadPtr(), GetName().ReadPtr(), + sensor->GetParent()->GetName().ReadPtr(), sensor->GetName().ReadPtr()); } + void SCA_IController::ApplyState(unsigned int state) { std::vector<class SCA_IActuator*>::iterator actit; @@ -185,13 +173,13 @@ void SCA_IController::ApplyState(unsigned int state) { (*actit)->IncLink(); } + for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) { (*sensit)->IncLink(); - // remember that this controller just activated that sensor - (*sensit)->AddNewController(this); } SetActive(true); + m_justActivated = true; } } else if (IsActive()) { @@ -204,6 +192,58 @@ void SCA_IController::ApplyState(unsigned int state) (*sensit)->DecLink(); } SetActive(false); + m_justActivated = false; } } +/* Python api */ + +PyTypeObject SCA_IController::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "SCA_IController", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_ILogicBrick::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyMethodDef SCA_IController::Methods[] = { + {NULL,NULL} //Sentinel +}; + +PyAttributeDef SCA_IController::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("state", SCA_IController, pyattr_get_state), + KX_PYATTRIBUTE_RO_FUNCTION("sensors", SCA_IController, pyattr_get_sensors), + KX_PYATTRIBUTE_RO_FUNCTION("actuators", SCA_IController, pyattr_get_actuators), + KX_PYATTRIBUTE_BOOL_RW("useHighPriority",SCA_IController,m_bookmark), + { NULL } //Sentinel +}; + +PyObject* SCA_IController::pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + SCA_IController* self= static_cast<SCA_IController*>(self_v); + return PyLong_FromSsize_t(self->m_statemask); +} + +PyObject* SCA_IController::pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + return KX_PythonSeq_CreatePyObject((static_cast<SCA_IController*>(self_v))->m_proxy, KX_PYGENSEQ_CONT_TYPE_SENSORS); +} + +PyObject* SCA_IController::pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + return KX_PythonSeq_CreatePyObject((static_cast<SCA_IController*>(self_v))->m_proxy, KX_PYGENSEQ_CONT_TYPE_ACTUATORS); +} diff --git a/source/gameengine/GameLogic/SCA_IController.h b/source/gameengine/GameLogic/SCA_IController.h index f67c0942eb4..202921c6986 100644 --- a/source/gameengine/GameLogic/SCA_IController.h +++ b/source/gameengine/GameLogic/SCA_IController.h @@ -30,28 +30,77 @@ #define __KX_ICONTROLLER #include "SCA_ILogicBrick.h" +#include "PyObjectPlus.h" +/* + * Use of SG_DList element: none + * Use of SG_QList element: build ordered list of activated controller on the owner object + * Head: SCA_IObject::m_activeControllers + */ class SCA_IController : public SCA_ILogicBrick { + Py_Header; protected: std::vector<class SCA_ISensor*> m_linkedsensors; std::vector<class SCA_IActuator*> m_linkedactuators; unsigned int m_statemask; + bool m_justActivated; + bool m_bookmark; public: - SCA_IController(SCA_IObject* gameobj,PyTypeObject* T); + SCA_IController(SCA_IObject* gameobj); virtual ~SCA_IController(); virtual void Trigger(class SCA_LogicManager* logicmgr)=0; void LinkToSensor(SCA_ISensor* sensor); void LinkToActuator(SCA_IActuator*); - const std::vector<class SCA_ISensor*>& GetLinkedSensors(); - const std::vector<class SCA_IActuator*>& GetLinkedActuators(); + std::vector<class SCA_ISensor*>& GetLinkedSensors(); + std::vector<class SCA_IActuator*>& GetLinkedActuators(); + void ReserveActuator(int num) + { + m_linkedactuators.reserve(num); + } void UnlinkAllSensors(); void UnlinkAllActuators(); void UnlinkActuator(class SCA_IActuator* actua); void UnlinkSensor(class SCA_ISensor* sensor); void SetState(unsigned int state) { m_statemask = state; } void ApplyState(unsigned int state); - + void Deactivate() + { + // the controller can only be part of a sensor m_newControllers list + Delink(); + } + bool IsJustActivated() + { + return m_justActivated; + } + void ClrJustActivated() + { + m_justActivated = false; + } + void SetBookmark(bool bookmark) + { + m_bookmark = bookmark; + } + void Activate(SG_DList& head) + { + if (QEmpty()) + { + if (m_bookmark) + { + m_gameobj->m_activeBookmarkedControllers.QAddBack(this); + head.AddFront(&m_gameobj->m_activeBookmarkedControllers); + } + else + { + InsertActiveQList(m_gameobj->m_activeControllers); + head.AddBack(&m_gameobj->m_activeControllers); + } + } + } + + static PyObject* pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); }; diff --git a/source/gameengine/GameLogic/SCA_IInputDevice.h b/source/gameengine/GameLogic/SCA_IInputDevice.h index 66ad457aa03..228d7684b0f 100644 --- a/source/gameengine/GameLogic/SCA_IInputDevice.h +++ b/source/gameengine/GameLogic/SCA_IInputDevice.h @@ -33,6 +33,10 @@ #ifndef KX_INPUTDEVICE_H #define KX_INPUTDEVICE_H +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class SCA_InputEvent { @@ -75,7 +79,6 @@ public: KX_TIMER0, KX_TIMER1, KX_TIMER2, - KX_TIMER3, // SYSTEM @@ -303,6 +306,12 @@ public: */ virtual void NextFrame(); + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_InputEvent"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //KX_INPUTDEVICE_H diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp index abd049e9d64..f679d0ee487 100644 --- a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp +++ b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp @@ -35,10 +35,9 @@ SCA_LogicManager* SCA_ILogicBrick::m_sCurrentLogicManager = NULL; -SCA_ILogicBrick::SCA_ILogicBrick(SCA_IObject* gameobj, - PyTypeObject* T) +SCA_ILogicBrick::SCA_ILogicBrick(SCA_IObject* gameobj) : - CValue(T), + CValue(), m_gameobj(gameobj), m_Execute_Priority(0), m_Execute_Ueber_Priority(0), @@ -71,13 +70,6 @@ void SCA_ILogicBrick::SetUeberExecutePriority(int execute_Priority) -SCA_IObject* SCA_ILogicBrick::GetParent() -{ - return m_gameobj; -} - - - void SCA_ILogicBrick::ReParent(SCA_IObject* parent) { m_gameobj = parent; @@ -123,40 +115,24 @@ const STR_String& SCA_ILogicBrick::GetText() -float SCA_ILogicBrick::GetNumber() +double SCA_ILogicBrick::GetNumber() { return -1; } -STR_String SCA_ILogicBrick::GetName() +STR_String& SCA_ILogicBrick::GetName() { return m_name; } -void SCA_ILogicBrick::SetName(STR_String name) -{ - m_name = name; -} - - - -void SCA_ILogicBrick::ReplicaSetName(STR_String name) +void SCA_ILogicBrick::SetName(const char *name) { m_name = name; } - - - -bool SCA_ILogicBrick::IsActive() -{ - return m_bActive; -} - - bool SCA_ILogicBrick::LessComparedTo(SCA_ILogicBrick* other) { @@ -165,22 +141,6 @@ bool SCA_ILogicBrick::LessComparedTo(SCA_ILogicBrick* other) (this->m_Execute_Priority < other->m_Execute_Priority)); } - - -void SCA_ILogicBrick::SetActive(bool active) -{ - m_bActive=active; - if (active) - { - //m_gameobj->SetDebugColor(GetDrawColor()); - } else - { - //m_gameobj->ResetDebugColor(); - } -} - - - void SCA_ILogicBrick::RegisterEvent(CValue* eventval) { if (m_eventval) @@ -217,87 +177,66 @@ CValue* SCA_ILogicBrick::GetEvent() /* python stuff */ PyTypeObject SCA_ILogicBrick::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_ILogicBrick", - sizeof(SCA_ILogicBrick), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - - - -PyParentObject SCA_ILogicBrick::Parents[] = { - &SCA_ILogicBrick::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; - - PyMethodDef SCA_ILogicBrick::Methods[] = { - {"getOwner", (PyCFunction) SCA_ILogicBrick::sPyGetOwner, METH_NOARGS}, - {"getExecutePriority", (PyCFunction) SCA_ILogicBrick::sPySetExecutePriority, METH_NOARGS}, - {"setExecutePriority", (PyCFunction) SCA_ILogicBrick::sPySetExecutePriority, METH_VARARGS}, {NULL,NULL} //Sentinel }; +PyAttributeDef SCA_ILogicBrick::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("owner", SCA_ILogicBrick, pyattr_get_owner), + KX_PYATTRIBUTE_INT_RW("executePriority",0,100000,false,SCA_ILogicBrick,m_Execute_Priority), + KX_PYATTRIBUTE_STRING_RO("name", SCA_ILogicBrick, m_name), + {NULL} //Sentinel +}; - -PyObject* -SCA_ILogicBrick::_getattr(const STR_String& attr) -{ - _getattr_up(CValue); -} - - - -PyObject* SCA_ILogicBrick::PyGetOwner(PyObject* self) +int SCA_ILogicBrick::CheckProperty(void *self, const PyAttributeDef *attrdef) { - CValue* parent = GetParent(); - if (parent) - { - parent->AddRef(); - return parent; + if (attrdef->m_type != KX_PYATTRIBUTE_TYPE_STRING || attrdef->m_length != 1) { + PyErr_SetString(PyExc_AttributeError, "inconsistent check function for attribute type, report to blender.org"); + return 1; } - - printf("ERROR: Python scriptblock without owner\n"); - Py_RETURN_NONE; //Int_FromLong(IsPositiveTrigger()); + SCA_ILogicBrick* brick = reinterpret_cast<SCA_ILogicBrick*>(self); + STR_String* var = reinterpret_cast<STR_String*>((char*)self+attrdef->m_offset); + CValue* prop = brick->GetParent()->FindIdentifier(*var); + bool error = prop->IsError(); + prop->Release(); + if (error) { + PyErr_SetString(PyExc_ValueError, "string does not correspond to a property"); + return 1; + } + return 0; } - - -PyObject* SCA_ILogicBrick::PySetExecutePriority(PyObject* self, - PyObject* args, - PyObject* kwds) +/*Attribute functions */ +PyObject* SCA_ILogicBrick::pyattr_get_owner(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - - int priority=0; - - if (!PyArg_ParseTuple(args, "i", &priority)) { - return NULL; - } + SCA_ILogicBrick* self= static_cast<SCA_ILogicBrick*>(self_v); + CValue* parent = self->GetParent(); - m_Execute_Ueber_Priority = priority; - - Py_Return; -} - - - -PyObject* SCA_ILogicBrick::PyGetExecutePriority(PyObject* self) -{ - return PyInt_FromLong(m_Execute_Ueber_Priority); + if (parent) + return parent->GetProxy(); + + Py_RETURN_NONE; } @@ -312,9 +251,7 @@ bool SCA_ILogicBrick::PyArgToBool(int boolArg) } } - - PyObject* SCA_ILogicBrick::BoolToPyArg(bool boolarg) { - return PyInt_FromLong(boolarg? KX_TRUE: KX_FALSE); + return PyLong_FromSsize_t(boolarg? KX_TRUE: KX_FALSE); } diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.h b/source/gameengine/GameLogic/SCA_ILogicBrick.h index c28711ac0f6..ac533335f0b 100644 --- a/source/gameengine/GameLogic/SCA_ILogicBrick.h +++ b/source/gameengine/GameLogic/SCA_ILogicBrick.h @@ -53,41 +53,84 @@ protected: CValue* GetEvent(); public: - SCA_ILogicBrick(SCA_IObject* gameobj,PyTypeObject* T ); + SCA_ILogicBrick(SCA_IObject* gameobj); virtual ~SCA_ILogicBrick(); void SetExecutePriority(int execute_Priority); void SetUeberExecutePriority(int execute_Priority); - SCA_IObject* GetParent(); + SCA_IObject* GetParent() { return m_gameobj; } + virtual void ReParent(SCA_IObject* parent); virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map); + virtual void Delete() { Release(); } // act as a BoolValue (with value IsPositiveTrigger) virtual CValue* Calc(VALUE_OPERATOR op, CValue *val); virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); virtual const STR_String & GetText(); - virtual float GetNumber(); - virtual STR_String GetName(); - virtual void SetName(STR_String name); - virtual void ReplicaSetName(STR_String name); + virtual double GetNumber(); + virtual STR_String& GetName(); + virtual void SetName(const char *); - bool IsActive(); - void SetActive(bool active) ; + bool IsActive() + { + return m_bActive; + } + + void SetActive(bool active) + { + m_bActive=active; + } + + // insert in a QList at position corresponding to m_Execute_Priority + void InsertActiveQList(SG_QList& head) + { + SG_QList::iterator<SCA_ILogicBrick> it(head); + for(it.begin(); !it.end() && m_Execute_Priority > (*it)->m_Execute_Priority; ++it); + it.add_back(this); + } + + // insert in a QList at position corresponding to m_Execute_Priority + // inside a longer list that contains elements of other objects. + // Sorting is done only between the elements of the same object. + // head is the head of the combined list + // current points to the first element of the object in the list, NULL if none yet + void InsertSelfActiveQList(SG_QList& head, SG_QList** current) + { + if (!*current) + { + // first element can be put anywhere + head.QAddBack(this); + *current = this; + return; + } + // note: we assume current points actually to one o our element, skip the tests + SG_QList::iterator<SCA_ILogicBrick> it(head,*current); + if (m_Execute_Priority <= (*it)->m_Execute_Priority) + { + // this element comes before the first + *current = this; + } + else + { + for(++it; !it.end() && (*it)->m_gameobj == m_gameobj && m_Execute_Priority > (*it)->m_Execute_Priority; ++it); + } + it.add_back(this); + } virtual bool LessComparedTo(SCA_ILogicBrick* other); - - virtual PyObject* _getattr(const STR_String& attr); static class SCA_LogicManager* m_sCurrentLogicManager; // python methods + + static PyObject* pyattr_get_owner(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - KX_PYMETHOD_NOARGS(SCA_ILogicBrick,GetOwner); - KX_PYMETHOD(SCA_ILogicBrick,SetExecutePriority); - KX_PYMETHOD_NOARGS(SCA_ILogicBrick,GetExecutePriority); + // check that attribute is a property + static int CheckProperty(void *self, const PyAttributeDef *attrdef); enum KX_BOOL_TYPE { KX_BOOL_NODEF = 0, diff --git a/source/gameengine/GameLogic/SCA_IObject.cpp b/source/gameengine/GameLogic/SCA_IObject.cpp index b0f8decee26..2bffd029bd4 100644 --- a/source/gameengine/GameLogic/SCA_IObject.cpp +++ b/source/gameengine/GameLogic/SCA_IObject.cpp @@ -39,13 +39,16 @@ #endif MT_Point3 SCA_IObject::m_sDummy=MT_Point3(0,0,0); +SG_QList SCA_IObject::m_activeBookmarkedControllers; -SCA_IObject::SCA_IObject(PyTypeObject* T): m_initState(0), m_state(0), CValue(T) +SCA_IObject::SCA_IObject(): + CValue(), + m_initState(0), + m_state(0), + m_firstState(NULL) { m_suspended = false; } - - SCA_IObject::~SCA_IObject() { @@ -59,7 +62,9 @@ SCA_IObject::~SCA_IObject() SCA_ControllerList::iterator itc; for (itc = m_controllers.begin(); !(itc == m_controllers.end()); ++itc) { - ((CValue*)(*itc))->Release(); + //Use Delete for controller to ensure proper cleaning (expression controller) + (*itc)->Delete(); + //((CValue*)(*itc))->Release(); } SCA_ActuatorList::iterator ita; for (ita = m_registeredActuators.begin(); !(ita==m_registeredActuators.end()); ++ita) @@ -68,7 +73,7 @@ SCA_IObject::~SCA_IObject() } for (ita = m_actuators.begin(); !(ita==m_actuators.end()); ++ita) { - ((CValue*)(*ita))->Release(); + (*ita)->Delete(); } //T_InterpolatorList::iterator i; @@ -77,29 +82,6 @@ SCA_IObject::~SCA_IObject() //} } - - -SCA_ControllerList& SCA_IObject::GetControllers() -{ - return m_controllers; -} - - - -SCA_SensorList& SCA_IObject::GetSensors() -{ - return m_sensors; -} - - - -SCA_ActuatorList& SCA_IObject::GetActuators() -{ - return m_actuators; -} - - - void SCA_IObject::AddSensor(SCA_ISensor* act) { act->AddRef(); @@ -131,7 +113,7 @@ void SCA_IObject::RegisterActuator(SCA_IActuator* act) void SCA_IObject::UnregisterActuator(SCA_IActuator* act) { SCA_ActuatorList::iterator ita; - for (ita = m_registeredActuators.begin(); ita != m_registeredActuators.end(); ita++) + for (ita = m_registeredActuators.begin(); ita != m_registeredActuators.end(); ++ita) { if ((*ita) == act) { (*ita) = m_registeredActuators.back(); @@ -141,20 +123,6 @@ void SCA_IObject::UnregisterActuator(SCA_IActuator* act) } } -void SCA_IObject::SetIgnoreActivityCulling(bool b) -{ - m_ignore_activity_culling = b; -} - - - -bool SCA_IObject::GetIgnoreActivityCulling() -{ - return m_ignore_activity_culling; -} - - - void SCA_IObject::ReParentLogic() { SCA_ActuatorList& oldactuators = GetActuators(); @@ -206,7 +174,7 @@ SCA_ISensor* SCA_IObject::FindSensor(const STR_String& sensorname) { SCA_ISensor* foundsensor = NULL; - for (SCA_SensorList::iterator its = m_sensors.begin();!(its==m_sensors.end());its++) + for (SCA_SensorList::iterator its = m_sensors.begin();!(its==m_sensors.end());++its) { if ((*its)->GetName() == sensorname) { @@ -223,7 +191,7 @@ SCA_IController* SCA_IObject::FindController(const STR_String& controllername) { SCA_IController* foundcontroller = NULL; - for (SCA_ControllerList::iterator itc = m_controllers.begin();!(itc==m_controllers.end());itc++) + for (SCA_ControllerList::iterator itc = m_controllers.begin();!(itc==m_controllers.end());++itc) { if ((*itc)->GetName() == controllername) { @@ -240,7 +208,7 @@ SCA_IActuator* SCA_IObject::FindActuator(const STR_String& actuatorname) { SCA_IActuator* foundactuator = NULL; - for (SCA_ActuatorList::iterator ita = m_actuators.begin();!(ita==m_actuators.end());ita++) + for (SCA_ActuatorList::iterator ita = m_actuators.begin();!(ita==m_actuators.end());++ita) { if ((*ita)->GetName() == actuatorname) { @@ -253,59 +221,6 @@ SCA_IActuator* SCA_IObject::FindActuator(const STR_String& actuatorname) } - -void SCA_IObject::SetCurrentTime(float currentTime) { - //T_InterpolatorList::iterator i; - //for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - // (*i)->Execute(currentTime); - //} -} - - -#if 0 -const MT_Point3& SCA_IObject::ConvertPythonPylist(PyObject* pylist) -{ - bool error = false; - m_sDummy = MT_Vector3(0,0,0); - if (pylist->ob_type == &CListValue::Type) - { - CListValue* listval = (CListValue*) pylist; - int numelem = listval->GetCount(); - if ( numelem <= 3) - { - int index; - for (index = 0;index<numelem;index++) - { - m_sDummy[index] = listval->GetValue(index)->GetNumber(); - } - } else - { - error = true; - } - - } else - { - - // assert the list is long enough... - int numitems = PyList_Size(pylist); - if (numitems <= 3) - { - int index; - for (index=0;index<numitems;index++) - { - m_sDummy[index] = PyFloat_AsDouble(PyList_GetItem(pylist,index)); - } - } - else - { - error = true; - } - - } - return m_sDummy; -} -#endif - void SCA_IObject::Suspend() { if ((!m_ignore_activity_culling) @@ -315,7 +230,7 @@ void SCA_IObject::Suspend() SCA_SensorList::iterator i = m_sensors.begin(); while (i != m_sensors.end()) { (*i)->Suspend(); - i++; + ++i; } } } @@ -330,7 +245,7 @@ void SCA_IObject::Resume(void) SCA_SensorList::iterator i = m_sensors.begin(); while (i != m_sensors.end()) { (*i)->Resume(); - i++; + ++i; } } } @@ -350,7 +265,7 @@ void SCA_IObject::SetState(unsigned int state) if (tmpstate != m_state) { // update the status of the controllers - for (contit = m_controllers.begin(); contit != m_controllers.end(); contit++) + for (contit = m_controllers.begin(); contit != m_controllers.end(); ++contit) { (*contit)->ApplyState(tmpstate); } @@ -358,7 +273,7 @@ void SCA_IObject::SetState(unsigned int state) m_state = state; if (m_state != tmpstate) { - for (contit = m_controllers.begin(); contit != m_controllers.end(); contit++) + for (contit = m_controllers.begin(); contit != m_controllers.end(); ++contit) { (*contit)->ApplyState(m_state); } @@ -373,43 +288,33 @@ void SCA_IObject::SetState(unsigned int state) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_IObject::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_IObject", - sizeof(SCA_IObject), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - - - -PyParentObject SCA_IObject::Parents[] = { - &SCA_IObject::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; - - PyMethodDef SCA_IObject::Methods[] = { //{"setOrientation", (PyCFunction) SCA_IObject::sPySetOrientation, METH_VARARGS}, //{"getOrientation", (PyCFunction) SCA_IObject::sPyGetOrientation, METH_VARARGS}, {NULL,NULL} //Sentinel }; - - -PyObject* SCA_IObject::_getattr(const STR_String& attr) { - _getattr_up(CValue); -} - +PyAttributeDef SCA_IObject::Attributes[] = { + { NULL } //Sentinel +}; diff --git a/source/gameengine/GameLogic/SCA_IObject.h b/source/gameengine/GameLogic/SCA_IObject.h index 38a7ed29dca..3060410dc6b 100644 --- a/source/gameengine/GameLogic/SCA_IObject.h +++ b/source/gameengine/GameLogic/SCA_IObject.h @@ -52,10 +52,30 @@ class SCA_IObject : public CValue Py_Header; protected: + friend class KX_StateActuator; + friend class SCA_IActuator; + friend class SCA_IController; SCA_SensorList m_sensors; SCA_ControllerList m_controllers; SCA_ActuatorList m_actuators; SCA_ActuatorList m_registeredActuators; // actuators that use a pointer to this object + + // SG_Dlist: element of objects with active actuators + // Head: SCA_LogicManager::m_activeActuators + // SG_QList: Head of active actuators list on this object + // Elements: SCA_IActuator + SG_QList m_activeActuators; + // SG_Dlist: element of list os lists with active controllers + // Head: SCA_LogicManager::m_activeControllers + // SG_QList: Head of active controller list on this object + // Elements: SCA_IController + SG_QList m_activeControllers; + // SG_Dlist: element of list of lists of active controllers + // Head: SCA_LogicManager::m_activeControllers + // SG_QList: Head of active bookmarked controller list globally + // Elements: SCA_IController with bookmark option + static SG_QList m_activeBookmarkedControllers; + static class MT_Point3 m_sDummy; /** @@ -78,18 +98,48 @@ protected: */ unsigned int m_state; + /** + * pointer inside state actuator list for sorting + */ + SG_QList* m_firstState; + public: - SCA_IObject(PyTypeObject* T=&Type); + SCA_IObject(); virtual ~SCA_IObject(); - SCA_ControllerList& GetControllers(); - SCA_SensorList& GetSensors(); - SCA_ActuatorList& GetActuators(); + SCA_ControllerList& GetControllers() + { + return m_controllers; + } + SCA_SensorList& GetSensors() + { + return m_sensors; + } + SCA_ActuatorList& GetActuators() + { + return m_actuators; + } + SG_QList& GetActiveActuators() + { + return m_activeActuators; + } void AddSensor(SCA_ISensor* act); + void ReserveSensor(int num) + { + m_sensors.reserve(num); + } void AddController(SCA_IController* act); + void ReserveController(int num) + { + m_controllers.reserve(num); + } void AddActuator(SCA_IActuator* act); + void ReserveActuator(int num) + { + m_actuators.reserve(num); + } void RegisterActuator(SCA_IActuator* act); void UnregisterActuator(SCA_IActuator* act); @@ -97,20 +147,26 @@ public: SCA_IActuator* FindActuator(const STR_String& actuatorname); SCA_IController* FindController(const STR_String& controllername); - void SetCurrentTime(float currentTime); + void SetCurrentTime(float currentTime) {} void ReParentLogic(); /** * Set whether or not to ignore activity culling requests */ - void SetIgnoreActivityCulling(bool b); + void SetIgnoreActivityCulling(bool b) + { + m_ignore_activity_culling = b; + } /** * Set whether or not this object wants to ignore activity culling * requests */ - bool GetIgnoreActivityCulling(); + bool GetIgnoreActivityCulling() + { + return m_ignore_activity_culling; + } /** * Suspend all progress. @@ -143,14 +199,12 @@ public: unsigned int GetState(void) { return m_state; } // const class MT_Point3& ConvertPythonPylist(PyObject* pylist); - - // here come the python forwarded methods - virtual PyObject* _getattr(const STR_String& attr); virtual int GetGameObjectType() {return -1;} typedef enum ObjectTypes { OBJ_ARMATURE=0, + OBJ_CAMERA=1, }ObjectTypes; }; diff --git a/source/gameengine/GameLogic/SCA_IScene.cpp b/source/gameengine/GameLogic/SCA_IScene.cpp index 9fbeb706910..86b176a38b0 100644 --- a/source/gameengine/GameLogic/SCA_IScene.cpp +++ b/source/gameengine/GameLogic/SCA_IScene.cpp @@ -50,7 +50,7 @@ SCA_IScene::SCA_IScene() void SCA_IScene::RemoveAllDebugProperties() { for (std::vector<SCA_DebugProp*>::iterator it = m_debugList.begin(); - !(it==m_debugList.end());it++) + !(it==m_debugList.end());++it) { delete (*it); } diff --git a/source/gameengine/GameLogic/SCA_IScene.h b/source/gameengine/GameLogic/SCA_IScene.h index d18778a37c2..ced9ca94cec 100644 --- a/source/gameengine/GameLogic/SCA_IScene.h +++ b/source/gameengine/GameLogic/SCA_IScene.h @@ -33,6 +33,10 @@ #include "STR_String.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + struct SCA_DebugProp { class CValue* m_obj; @@ -52,14 +56,21 @@ public: int lifespan=0)=0; virtual void RemoveObject(class CValue* gameobj)=0; virtual void DelayedRemoveObject(class CValue* gameobj)=0; - virtual void DelayedReleaseObject(class CValue* gameobj)=0; + //virtual void DelayedReleaseObject(class CValue* gameobj)=0; virtual void ReplaceMesh(class CValue* gameobj, - void* meshobj)=0; + void* meshobj, bool use_gfx, bool use_phys)=0; std::vector<SCA_DebugProp*>& GetDebugProperties(); void AddDebugProperty(class CValue* debugprop, const STR_String &name); void RemoveAllDebugProperties(); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_IScene"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_ISCENE_H diff --git a/source/gameengine/GameLogic/SCA_ISensor.cpp b/source/gameengine/GameLogic/SCA_ISensor.cpp index b10ac676464..497a5d1095a 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.cpp +++ b/source/gameengine/GameLogic/SCA_ISensor.cpp @@ -45,26 +45,27 @@ void SCA_ISensor::ReParent(SCA_IObject* parent) SCA_ILogicBrick::ReParent(parent); // will be done when the sensor is activated //m_eventmgr->RegisterSensor(this); - this->SetActive(false); + //this->SetActive(false); } SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj, - class SCA_EventManager* eventmgr, - PyTypeObject* T ) : - SCA_ILogicBrick(gameobj,T), - m_triggered(false) + class SCA_EventManager* eventmgr) : + SCA_ILogicBrick(gameobj) { m_links = 0; m_suspended = false; m_invert = false; m_level = false; + m_tap = false; m_reset = false; m_pos_ticks = 0; m_neg_ticks = 0; m_pos_pulsemode = false; m_neg_pulsemode = false; m_pulse_frequency = 0; + m_state = false; + m_prev_state = false; m_eventmgr = eventmgr; } @@ -75,6 +76,12 @@ SCA_ISensor::~SCA_ISensor() // intentionally empty } +void SCA_ISensor::ProcessReplica() +{ + SCA_ILogicBrick::ProcessReplica(); + m_linkedcontrollers.clear(); +} + bool SCA_ISensor::IsPositiveTrigger() { bool result = false; @@ -104,9 +111,13 @@ void SCA_ISensor::SetLevel(bool lvl) { m_level = lvl; } +void SCA_ISensor::SetTap(bool tap) { + m_tap = tap; +} -float SCA_ISensor::GetNumber() { - return IsPositiveTrigger(); + +double SCA_ISensor::GetNumber() { + return GetState(); } void SCA_ISensor::Suspend() { @@ -139,96 +150,84 @@ void SCA_ISensor::DecLink() { } } -/* python integration */ - -PyTypeObject SCA_ISensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "SCA_ISensor", - sizeof(SCA_ISensor), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 -}; - -PyParentObject SCA_ISensor::Parents[] = { - &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL -}; -PyMethodDef SCA_ISensor::Methods[] = { - {"isPositive", (PyCFunction) SCA_ISensor::sPyIsPositive, - METH_NOARGS, (PY_METHODCHAR)IsPositive_doc}, - {"isTriggered", (PyCFunction) SCA_ISensor::sPyIsTriggered, - METH_VARARGS, (PY_METHODCHAR)IsTriggered_doc}, - {"getUsePosPulseMode", (PyCFunction) SCA_ISensor::sPyGetUsePosPulseMode, - METH_NOARGS, (PY_METHODCHAR)GetUsePosPulseMode_doc}, - {"setUsePosPulseMode", (PyCFunction) SCA_ISensor::sPySetUsePosPulseMode, - METH_VARARGS, (PY_METHODCHAR)SetUsePosPulseMode_doc}, - {"getFrequency", (PyCFunction) SCA_ISensor::sPyGetFrequency, - METH_NOARGS, (PY_METHODCHAR)GetFrequency_doc}, - {"setFrequency", (PyCFunction) SCA_ISensor::sPySetFrequency, - METH_VARARGS, (PY_METHODCHAR)SetFrequency_doc}, - {"getUseNegPulseMode", (PyCFunction) SCA_ISensor::sPyGetUseNegPulseMode, - METH_NOARGS, (PY_METHODCHAR)GetUseNegPulseMode_doc}, - {"setUseNegPulseMode", (PyCFunction) SCA_ISensor::sPySetUseNegPulseMode, - METH_VARARGS, (PY_METHODCHAR)SetUseNegPulseMode_doc}, - {"getInvert", (PyCFunction) SCA_ISensor::sPyGetInvert, - METH_NOARGS, (PY_METHODCHAR)GetInvert_doc}, - {"setInvert", (PyCFunction) SCA_ISensor::sPySetInvert, - METH_VARARGS, (PY_METHODCHAR)SetInvert_doc}, - {"getLevel", (PyCFunction) SCA_ISensor::sPyGetLevel, - METH_NOARGS, (PY_METHODCHAR)GetLevel_doc}, - {"setLevel", (PyCFunction) SCA_ISensor::sPySetLevel, - METH_VARARGS, (PY_METHODCHAR)SetLevel_doc}, - {"reset", (PyCFunction) SCA_ISensor::sPyReset, - METH_NOARGS, (PY_METHODCHAR)Reset_doc}, - {NULL,NULL} //Sentinel -}; - +void SCA_ISensor::RegisterToManager() +{ + // sensor is just activated, initialize it + Init(); + m_state = false; + m_eventmgr->RegisterSensor(this); +} -PyObject* -SCA_ISensor::_getattr(const STR_String& attr) +void SCA_ISensor::LinkToController(SCA_IController* controller) { - _getattr_up(SCA_ILogicBrick); + m_linkedcontrollers.push_back(controller); } +void SCA_ISensor::UnlinkController(SCA_IController* controller) +{ + std::vector<class SCA_IController*>::iterator contit; + for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit) + { + if ((*contit) == controller) + { + *contit = m_linkedcontrollers.back(); + m_linkedcontrollers.pop_back(); + return; + } + } + printf("Missing link from sensor %s:%s to controller %s:%s\n", + m_gameobj->GetName().ReadPtr(), GetName().ReadPtr(), + controller->GetParent()->GetName().ReadPtr(), controller->GetName().ReadPtr()); +} -void SCA_ISensor::RegisterToManager() +void SCA_ISensor::UnlinkAllControllers() { - // sensor is just activated, initialize it - Init(); - m_newControllers.erase(m_newControllers.begin(), m_newControllers.end()); - m_eventmgr->RegisterSensor(this); + std::vector<class SCA_IController*>::iterator contit; + for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit) + { + (*contit)->UnlinkSensor(this); + } + m_linkedcontrollers.clear(); } void SCA_ISensor::UnregisterToManager() { m_eventmgr->RemoveSensor(this); + m_links = 0; } -void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr, CValue* event) +void SCA_ISensor::ActivateControllers(class SCA_LogicManager* logicmgr) +{ + for(vector<SCA_IController*>::const_iterator c= m_linkedcontrollers.begin(); + c!=m_linkedcontrollers.end();++c) + { + SCA_IController* contr = *c; + if (contr->IsActive()) + logicmgr->AddTriggeredController(contr, this); + } +} + +void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr) { // calculate if a __triggering__ is wanted // don't evaluate a sensor that is not connected to any controller if (m_links && !m_suspended) { - bool result = this->Evaluate(event); + bool result = this->Evaluate(); + // store the state for the rest of the logic system + m_prev_state = m_state; + m_state = this->IsPositiveTrigger(); if (result) { - logicmgr->AddActivatedSensor(this); - // reset these counters so that pulse are synchronized with transition - m_pos_ticks = 0; - m_neg_ticks = 0; + // the sensor triggered this frame + if (m_state || !m_tap) { + ActivateControllers(logicmgr); + // reset these counters so that pulse are synchronized with transition + m_pos_ticks = 0; + m_neg_ticks = 0; + } else + { + result = false; + } } else { /* First, the pulsing behaviour, if pulse mode is @@ -237,206 +236,148 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr, CValue* event) if (m_pos_pulsemode) { m_pos_ticks++; if (m_pos_ticks > m_pulse_frequency) { - if ( this->IsPositiveTrigger() ) + if ( m_state ) { - logicmgr->AddActivatedSensor(this); + ActivateControllers(logicmgr); + result = true; } m_pos_ticks = 0; } } - - if (m_neg_pulsemode) + // negative pulse doesn't make sense in tap mode, skip + if (m_neg_pulsemode && !m_tap) { m_neg_ticks++; if (m_neg_ticks > m_pulse_frequency) { - if (!this->IsPositiveTrigger() ) + if (!m_state ) { - logicmgr->AddActivatedSensor(this); + ActivateControllers(logicmgr); + result = true; } m_neg_ticks = 0; } } } - if (!m_newControllers.empty()) + if (m_tap) { - if (!IsActive() && m_level) + // in tap mode: we send always a negative pulse immediately after a positive pulse + if (!result) { - // This level sensor is connected to at least one controller that was just made - // active but it did not generate an event yet, do it now to those controllers only - for (std::vector<SCA_IController*>::iterator ci=m_newControllers.begin(); - ci != m_newControllers.end(); ci++) + // the sensor did not trigger on this frame + if (m_prev_state) { - logicmgr->AddTriggeredController(*ci, this); + // but it triggered on previous frame => send a negative pulse + ActivateControllers(logicmgr); + result = true; } + // in any case, absence of trigger means sensor off + m_state = false; + } + } + if (!result && m_level) + { + // This level sensor is connected to at least one controller that was just made + // active but it did not generate an event yet, do it now to those controllers only + for(vector<SCA_IController*>::const_iterator c= m_linkedcontrollers.begin(); + c!=m_linkedcontrollers.end();++c) + { + SCA_IController* contr = *c; + if (contr->IsJustActivated()) + logicmgr->AddTriggeredController(contr, this); } - // clear the list. Instead of using clear, which also release the memory, - // use erase, which keeps the memory available for next time. - m_newControllers.erase(m_newControllers.begin(), m_newControllers.end()); } } } +/* ----------------------------------------------- */ +/* Python Functions */ +/* ----------------------------------------------- */ -/* Python functions: */ -const char SCA_ISensor::IsPositive_doc[] = -"isPositive()\n" -"\tReturns whether the sensor is in an active state.\n"; -PyObject* SCA_ISensor::PyIsPositive(PyObject* self) -{ - int retval = IsPositiveTrigger(); - return PyInt_FromLong(retval); -} - -const char SCA_ISensor::IsTriggered_doc[] = -"isTriggered()\n" -"\tReturns whether the sensor has triggered the current controller.\n"; -PyObject* SCA_ISensor::PyIsTriggered(PyObject* self) -{ - // check with the current controller - int retval = 0; - if (SCA_PythonController::m_sCurrentController) - retval = SCA_PythonController::m_sCurrentController->IsTriggered(this); - return PyInt_FromLong(retval); -} - -/** - * getUsePulseMode: getter for the pulse mode (KX_TRUE = on) - */ -const char SCA_ISensor::GetUsePosPulseMode_doc[] = -"getUsePosPulseMode()\n" -"\tReturns whether positive pulse mode is active.\n"; -PyObject* SCA_ISensor::PyGetUsePosPulseMode(PyObject* self) -{ - return BoolToPyArg(m_pos_pulsemode); -} - -/** - * setUsePulseMode: setter for the pulse mode (KX_TRUE = on) - */ -const char SCA_ISensor::SetUsePosPulseMode_doc[] = -"setUsePosPulseMode(pulse?)\n" -"\t - pulse? : Pulse when a positive event occurs?\n" -"\t (KX_TRUE, KX_FALSE)\n" -"\tSet whether to do pulsing when positive pulses occur.\n"; -PyObject* SCA_ISensor::PySetUsePosPulseMode(PyObject* self, PyObject* args, PyObject* kwds) -{ - int pyarg = 0; - if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; } - m_pos_pulsemode = PyArgToBool(pyarg); - Py_Return; -} - -/** - * getFrequency: getter for the pulse mode interval - */ -const char SCA_ISensor::GetFrequency_doc[] = -"getFrequency()\n" -"\tReturns the frequency of the updates in pulse mode.\n" ; -PyObject* SCA_ISensor::PyGetFrequency(PyObject* self) +KX_PYMETHODDEF_DOC_NOARGS(SCA_ISensor, reset, +"reset()\n" +"\tReset sensor internal state, effect depends on the type of sensor and settings.\n" +"\tThe sensor is put in its initial state as if it was just activated.\n") { - return PyInt_FromLong(m_pulse_frequency); + Init(); + m_prev_state = false; + Py_RETURN_NONE; } -/** - * setFrequency: setter for the pulse mode (KX_TRUE = on) - */ -const char SCA_ISensor::SetFrequency_doc[] = -"setFrequency(pulse_frequency)\n" -"\t- pulse_frequency: The frequency of the updates in pulse mode (integer)" -"\tSet the frequency of the updates in pulse mode.\n" -"\tIf the frequency is negative, it is set to 0.\n" ; -PyObject* SCA_ISensor::PySetFrequency(PyObject* self, PyObject* args, PyObject* kwds) -{ - int pulse_frequencyArg = 0; - - if(!PyArg_ParseTuple(args, "i", &pulse_frequencyArg)) { - return NULL; - } - - /* We can do three things here: clip, ignore and raise an exception. */ - /* Exceptions don't work yet, ignoring is not desirable now... */ - if (pulse_frequencyArg < 0) { - pulse_frequencyArg = 0; - }; - m_pulse_frequency = pulse_frequencyArg; - - Py_Return; -} +/* ----------------------------------------------- */ +/* Python Integration Hooks */ +/* ----------------------------------------------- */ +PyTypeObject SCA_ISensor::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "SCA_ISensor", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_ILogicBrick::Type, + 0,0,0,0,0,0, + py_base_new +}; -const char SCA_ISensor::GetInvert_doc[] = -"getInvert()\n" -"\tReturns whether or not pulses from this sensor are inverted.\n" ; -PyObject* SCA_ISensor::PyGetInvert(PyObject* self) -{ - return BoolToPyArg(m_invert); -} +PyMethodDef SCA_ISensor::Methods[] = { + KX_PYMETHODTABLE_NOARGS(SCA_ISensor, reset), + {NULL,NULL} //Sentinel +}; -const char SCA_ISensor::SetInvert_doc[] = -"setInvert(invert?)\n" -"\t- invert?: Invert the event-values? (KX_TRUE, KX_FALSE)\n" -"\tSet whether to invert pulses.\n"; -PyObject* SCA_ISensor::PySetInvert(PyObject* self, PyObject* args, PyObject* kwds) -{ - int pyarg = 0; - if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; } - m_invert = PyArgToBool(pyarg); - Py_Return; -} +PyAttributeDef SCA_ISensor::Attributes[] = { + KX_PYATTRIBUTE_BOOL_RW("usePosPulseMode",SCA_ISensor,m_pos_pulsemode), + KX_PYATTRIBUTE_BOOL_RW("useNegPulseMode",SCA_ISensor,m_neg_pulsemode), + KX_PYATTRIBUTE_INT_RW("frequency",0,100000,true,SCA_ISensor,m_pulse_frequency), + KX_PYATTRIBUTE_BOOL_RW("invert",SCA_ISensor,m_invert), + KX_PYATTRIBUTE_BOOL_RW_CHECK("level",SCA_ISensor,m_level,pyattr_check_level), + KX_PYATTRIBUTE_BOOL_RW_CHECK("tap",SCA_ISensor,m_tap,pyattr_check_tap), + KX_PYATTRIBUTE_RO_FUNCTION("triggered", SCA_ISensor, pyattr_get_triggered), + KX_PYATTRIBUTE_RO_FUNCTION("positive", SCA_ISensor, pyattr_get_positive), + //KX_PYATTRIBUTE_TODO("links"), + //KX_PYATTRIBUTE_TODO("posTicks"), + //KX_PYATTRIBUTE_TODO("negTicks"), + { NULL } //Sentinel +}; -const char SCA_ISensor::GetLevel_doc[] = -"getLevel()\n" -"\tReturns whether this sensor is a level detector or a edge detector.\n" -"\tIt makes a difference only in case of logic state transition (state actuator).\n" -"\tA level detector will immediately generate a pulse, negative or positive\n" -"\tdepending on the sensor condition, as soon as the state is activated.\n" -"\tA edge detector will wait for a state change before generating a pulse.\n"; -PyObject* SCA_ISensor::PyGetLevel(PyObject* self) -{ - return BoolToPyArg(m_level); -} -const char SCA_ISensor::SetLevel_doc[] = -"setLevel(level?)\n" -"\t- level?: Detect level instead of edge? (KX_TRUE, KX_FALSE)\n" -"\tSet whether to detect level or edge transition when entering a state.\n"; -PyObject* SCA_ISensor::PySetLevel(PyObject* self, PyObject* args, PyObject* kwds) +PyObject* SCA_ISensor::pyattr_get_triggered(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - int pyarg = 0; - if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; } - m_level = PyArgToBool(pyarg); - Py_Return; + SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v); + int retval = 0; + if (SCA_PythonController::m_sCurrentController) + retval = SCA_PythonController::m_sCurrentController->IsTriggered(self); + return PyLong_FromSsize_t(retval); } -const char SCA_ISensor::GetUseNegPulseMode_doc[] = -"getUseNegPulseMode()\n" -"\tReturns whether negative pulse mode is active.\n"; -PyObject* SCA_ISensor::PyGetUseNegPulseMode(PyObject* self) +PyObject* SCA_ISensor::pyattr_get_positive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - return BoolToPyArg(m_neg_pulsemode); + SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v); + return PyLong_FromSsize_t(self->GetState()); } -const char SCA_ISensor::SetUseNegPulseMode_doc[] = -"setUseNegPulseMode(pulse?)\n" -"\t - pulse? : Pulse when a negative event occurs?\n" -"\t (KX_TRUE, KX_FALSE)\n" -"\tSet whether to do pulsing when negative pulses occur.\n"; -PyObject* SCA_ISensor::PySetUseNegPulseMode(PyObject* self, PyObject* args, PyObject* kwds) +int SCA_ISensor::pyattr_check_level(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - int pyarg = 0; - if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; } - m_neg_pulsemode = PyArgToBool(pyarg); - Py_Return; + SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v); + if (self->m_level) + self->m_tap = false; + return 0; } -const char SCA_ISensor::Reset_doc[] = -"reset()\n" -"\tReset sensor internal state, effect depends on the type of sensor and settings.\n" -"\tThe sensor is put in its initial state as if it was just activated.\n"; -PyObject* SCA_ISensor::PyReset(PyObject* self) +int SCA_ISensor::pyattr_check_tap(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - Init(); - Py_Return; + SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v); + if (self->m_tap) + self->m_level = false; + return 0; } - /* eof */ diff --git a/source/gameengine/GameLogic/SCA_ISensor.h b/source/gameengine/GameLogic/SCA_ISensor.h index d1872009291..742b05bd88b 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.h +++ b/source/gameengine/GameLogic/SCA_ISensor.h @@ -32,18 +32,22 @@ #ifndef __SCA_ISENSOR #define __SCA_ISENSOR -#include "SCA_ILogicBrick.h" +#include "SCA_IController.h" #include <vector> /** * Interface Class for all logic Sensors. Implements - * pulsemode,pulsefrequency */ + * pulsemode,pulsefrequency + * Use of SG_DList element: link sensors to their respective event manager + * Head: SCA_EventManager::m_sensors + * Use of SG_QList element: not used + */ class SCA_ISensor : public SCA_ILogicBrick { Py_Header; +protected: class SCA_EventManager* m_eventmgr; - bool m_triggered; /** Pulse positive pulses? */ bool m_pos_pulsemode; @@ -66,6 +70,9 @@ class SCA_ISensor : public SCA_ILogicBrick /** detect level instead of edge*/ bool m_level; + /** tap mode */ + bool m_tap; + /** sensor has been reset */ bool m_reset; @@ -75,13 +82,26 @@ class SCA_ISensor : public SCA_ILogicBrick /** number of connections to controller */ int m_links; - /** list of controllers that have just activated this sensor because of a state change */ - std::vector<class SCA_IController*> m_newControllers; + /** current sensor state */ + bool m_state; + + /** previous state (for tap option) */ + bool m_prev_state; + + std::vector<class SCA_IController*> m_linkedcontrollers; public: + + enum sensortype { + ST_NONE = 0, + ST_TOUCH, + ST_NEAR, + ST_RADAR, + // to be updated as needed + }; + SCA_ISensor(SCA_IObject* gameobj, - class SCA_EventManager* eventmgr, - PyTypeObject* T );; + class SCA_EventManager* eventmgr);; ~SCA_ISensor(); virtual void ReParent(SCA_IObject* parent); @@ -89,12 +109,11 @@ public: /* an implementation on this level. It requires an evaluate on the lower */ /* level of individual sensors. Mapping the old activate()s is easy. */ /* The IsPosTrig() also has to change, to keep things consistent. */ - void Activate(class SCA_LogicManager* logicmgr,CValue* event); - virtual bool Evaluate(CValue* event) = 0; + void Activate(class SCA_LogicManager* logicmgr); + virtual bool Evaluate() = 0; virtual bool IsPositiveTrigger(); virtual void Init(); - - virtual PyObject* _getattr(const STR_String& attr); + virtual CValue* GetReplica()=0; /** Set parameters for the pulsing behaviour. @@ -106,20 +125,28 @@ public: bool negmode, int freq); - /** Release sensor - * For property sensor, it is used to release the pre-calculated expression - * so that self references are removed before the sensor itself is released - */ - virtual void Delete() { Release(); } /** Set inversion of pulses on or off. */ void SetInvert(bool inv); /** set the level detection on or off */ void SetLevel(bool lvl); + void SetTap(bool tap); virtual void RegisterToManager(); virtual void UnregisterToManager(); + void ReserveController(int num) + { + m_linkedcontrollers.reserve(num); + } + void LinkToController(SCA_IController* controller); + void UnlinkController(SCA_IController* controller); + void UnlinkAllControllers(); + void ActivateControllers(class SCA_LogicManager* logicmgr); + + virtual void ProcessReplica(); + + virtual double GetNumber(); - virtual float GetNumber(); + virtual sensortype GetSensorType() { return ST_NONE; } /** Stop sensing for a while. */ void Suspend(); @@ -127,11 +154,15 @@ public: /** Is this sensor switched off? */ bool IsSuspended(); + /** get the state of the sensor: positive or negative */ + bool GetState() + { + return m_state; + } + /** Resume sensing. */ void Resume(); - void AddNewController(class SCA_IController* controller) - { m_newControllers.push_back(controller); } void ClrLink() { m_links = 0; } void IncLink() @@ -141,20 +172,12 @@ public: { return !m_links; } /* Python functions: */ - KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,IsPositive); - KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,IsTriggered); - KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,GetUsePosPulseMode); - KX_PYMETHOD_DOC(SCA_ISensor,SetUsePosPulseMode); - KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,GetFrequency); - KX_PYMETHOD_DOC(SCA_ISensor,SetFrequency); - KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,GetUseNegPulseMode); - KX_PYMETHOD_DOC(SCA_ISensor,SetUseNegPulseMode); - KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,GetInvert); - KX_PYMETHOD_DOC(SCA_ISensor,SetInvert); - KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,GetLevel); - KX_PYMETHOD_DOC(SCA_ISensor,SetLevel); - KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,Reset); - + KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,reset); + + static PyObject* pyattr_get_triggered(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_positive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_check_level(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_check_tap(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); }; #endif //__SCA_ISENSOR diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.cpp b/source/gameengine/GameLogic/SCA_JoystickManager.cpp index f3ce549a637..ff8f3b1c81f 100644 --- a/source/gameengine/GameLogic/SCA_JoystickManager.cpp +++ b/source/gameengine/GameLogic/SCA_JoystickManager.cpp @@ -59,20 +59,21 @@ SCA_JoystickManager::~SCA_JoystickManager() void SCA_JoystickManager::NextFrame(double curtime,double deltatime) { - if (m_sensors.size()==0) { + if (m_sensors.Empty()) { return; } else { - set<SCA_ISensor*>::iterator it; + ; #ifndef DISABLE_SDL SCA_Joystick::HandleEvents(); /* Handle all SDL Joystick events */ #endif - for (it = m_sensors.begin(); it != m_sensors.end(); it++) + SG_DList::iterator<SCA_JoystickSensor> it(m_sensors); + for (it.begin();!it.end();++it) { - SCA_JoystickSensor* joysensor = (SCA_JoystickSensor*)(*it); + SCA_JoystickSensor* joysensor = *it; if(!joysensor->IsSuspended()) { - joysensor->Activate(m_logicmgr, NULL); + joysensor->Activate(m_logicmgr); } } } diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.h b/source/gameengine/GameLogic/SCA_JoystickManager.h index d3a7ac95bea..be55e95b033 100644 --- a/source/gameengine/GameLogic/SCA_JoystickManager.h +++ b/source/gameengine/GameLogic/SCA_JoystickManager.h @@ -47,6 +47,12 @@ public: virtual void NextFrame(double curtime,double deltatime); SCA_Joystick* GetJoystickDevice(short int joyindex); + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_JoystickManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp index 8b96840b149..4936b380352 100644 --- a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp +++ b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp @@ -46,10 +46,8 @@ SCA_JoystickSensor::SCA_JoystickSensor(class SCA_JoystickManager* eventmgr, short int joymode, int axis, int axisf,int prec, int button, - int hat, int hatf, bool allevents, - PyTypeObject* T ) - :SCA_ISensor(gameobj,eventmgr,T), - m_pJoystickMgr(eventmgr), + int hat, int hatf, bool allevents) + :SCA_ISensor(gameobj,eventmgr), m_axis(axis), m_axisf(axisf), m_button(button), @@ -87,7 +85,7 @@ CValue* SCA_JoystickSensor::GetReplica() { SCA_JoystickSensor* replica = new SCA_JoystickSensor(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); replica->Init(); return replica; } @@ -102,9 +100,9 @@ bool SCA_JoystickSensor::IsPositiveTrigger() } -bool SCA_JoystickSensor::Evaluate(CValue* event) +bool SCA_JoystickSensor::Evaluate() { - SCA_Joystick *js = m_pJoystickMgr->GetJoystickDevice(m_joyindex); + SCA_Joystick *js = ((SCA_JoystickManager *)m_eventmgr)->GetJoystickDevice(m_joyindex); bool result = false; bool reset = m_reset && m_level; @@ -117,11 +115,15 @@ bool SCA_JoystickSensor::Evaluate(CValue* event) case KX_JOYSENSORMODE_AXIS: { /* what is what! - m_axisf == 0 == right + m_axisf == JOYAXIS_RIGHT, JOYAXIS_UP, JOYAXIS_DOWN, JOYAXIS_LEFT m_axisf == 1 == up m_axisf == 2 == left m_axisf == 3 == down - numberof== m_axis -- max 2 + + numberof== m_axis (1-4), range is half of JOYAXIS_MAX since + it assumes the axis joysticks are axis parirs (0,1), (2,3), etc + also note that this starts at 1 where functions its used + with expect a zero index. */ if (!js->IsTrigAxis() && !reset) /* No events from SDL? - dont bother */ @@ -129,18 +131,7 @@ bool SCA_JoystickSensor::Evaluate(CValue* event) js->cSetPrecision(m_precision); if (m_bAllEvents) { - if(js->aAnyAxisIsPositive(m_axis)){ - m_istrig = 1; - result = true; - }else{ - if(m_istrig){ - m_istrig = 0; - result = true; - } - } - } - else if(m_axisf == 1){ - if(js->aUpAxisIsPositive(m_axis)){ + if(js->aAxisPairIsPositive(m_axis-1)){ /* use zero based axis index internally */ m_istrig = 1; result = true; }else{ @@ -150,8 +141,8 @@ bool SCA_JoystickSensor::Evaluate(CValue* event) } } } - else if(m_axisf == 3){ - if(js->aDownAxisIsPositive(m_axis)){ + else { + if(js->aAxisPairDirectionIsPositive(m_axis-1, m_axisf)){ /* use zero based axis index internally */ m_istrig = 1; result = true; }else{ @@ -161,30 +152,28 @@ bool SCA_JoystickSensor::Evaluate(CValue* event) } } } - else if(m_axisf == 2){ - if(js->aLeftAxisIsPositive(m_axis)){ - m_istrig = 1; - result = true; - }else{ - if(m_istrig){ - m_istrig = 0; - result = true; - } - } - } - else if(m_axisf == 0){ - if(js->aRightAxisIsPositive(m_axis)){ - m_istrig = 1; + break; + } + case KX_JOYSENSORMODE_AXIS_SINGLE: + { + /* Like KX_JOYSENSORMODE_AXIS but dont pair up axis */ + if (!js->IsTrigAxis() && !reset) /* No events from SDL? - dont bother */ + return false; + + /* No need for 'm_bAllEvents' check here since were only checking 1 axis */ + js->cSetPrecision(m_precision); + if(js->aAxisIsPositive(m_axis-1)){ /* use zero based axis index internally */ + m_istrig = 1; + result = true; + }else{ + if(m_istrig){ + m_istrig = 0; result = true; - }else{ - if(m_istrig){ - m_istrig = 0; - result = true; - } } } break; } + case KX_JOYSENSORMODE_BUTTON: { /* what is what! @@ -207,33 +196,20 @@ bool SCA_JoystickSensor::Evaluate(CValue* event) case KX_JOYSENSORMODE_HAT: { /* what is what! - numberof = m_hat -- max 2 + numberof = m_hat -- max 4 direction= m_hatf -- max 12 */ if (!js->IsTrigHat() && !reset) /* No events from SDL? - dont bother */ return false; - if(m_hat == 1){ - if(js->aHatIsPositive(m_hatf)){ - m_istrig = 1; - result = true; - }else{ - if(m_istrig){ - m_istrig = 0; - result = true; - } - } - } - if(m_hat == 2){ - if(js->aHatIsPositive(m_hatf)){ - m_istrig = 1; + if((m_bAllEvents && js->GetHat(m_hat-1)) || js->aHatIsPositive(m_hat-1, m_hatf)) { + m_istrig = 1; + result = true; + }else{ + if(m_istrig){ + m_istrig = 0; result = true; - }else{ - if(m_istrig){ - m_istrig = 0; - result = true; - } } } break; @@ -275,172 +251,57 @@ bool SCA_JoystickSensor::isValid(SCA_JoystickSensor::KX_JOYSENSORMODE m) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_JoystickSensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "SCA_JoystickSensor", - sizeof(SCA_JoystickSensor), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 + PyVarObject_HEAD_INIT(NULL, 0) + "SCA_JoystickSensor", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_ISensor::Type, + 0,0,0,0,0,0, + py_base_new }; - -PyParentObject SCA_JoystickSensor::Parents[] = { - &SCA_JoystickSensor::Type, - &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL -}; - - PyMethodDef SCA_JoystickSensor::Methods[] = { - {"getIndex", (PyCFunction) SCA_JoystickSensor::sPyGetIndex, METH_NOARGS, (PY_METHODCHAR)GetIndex_doc}, - {"setIndex", (PyCFunction) SCA_JoystickSensor::sPySetIndex, METH_O, (PY_METHODCHAR)SetIndex_doc}, - {"getAxis", (PyCFunction) SCA_JoystickSensor::sPyGetAxis, METH_NOARGS, (PY_METHODCHAR)GetAxis_doc}, - {"setAxis", (PyCFunction) SCA_JoystickSensor::sPySetAxis, METH_VARARGS, (PY_METHODCHAR)SetAxis_doc}, - {"getAxisValue", (PyCFunction) SCA_JoystickSensor::sPyGetAxisValue, METH_NOARGS, (PY_METHODCHAR)GetAxisValue_doc}, - {"getThreshold", (PyCFunction) SCA_JoystickSensor::sPyGetThreshold, METH_NOARGS, (PY_METHODCHAR)GetThreshold_doc}, - {"setThreshold", (PyCFunction) SCA_JoystickSensor::sPySetThreshold, METH_VARARGS, (PY_METHODCHAR)SetThreshold_doc}, - {"getButton", (PyCFunction) SCA_JoystickSensor::sPyGetButton, METH_NOARGS, (PY_METHODCHAR)GetButton_doc}, - {"setButton", (PyCFunction) SCA_JoystickSensor::sPySetButton, METH_O, (PY_METHODCHAR)SetButton_doc}, - {"getButtonValue",(PyCFunction) SCA_JoystickSensor::sPyGetButtonValue, METH_NOARGS,(PY_METHODCHAR)GetButtonValue_doc}, - {"getHat", (PyCFunction) SCA_JoystickSensor::sPyGetHat, METH_NOARGS, (PY_METHODCHAR)GetHat_doc}, - {"setHat", (PyCFunction) SCA_JoystickSensor::sPySetHat, METH_VARARGS, (PY_METHODCHAR)SetHat_doc}, - {"getNumAxes", (PyCFunction) SCA_JoystickSensor::sPyNumberOfAxes, METH_NOARGS, (PY_METHODCHAR)NumberOfAxes_doc}, - {"getNumButtons",(PyCFunction) SCA_JoystickSensor::sPyNumberOfButtons,METH_NOARGS, (PY_METHODCHAR)NumberOfButtons_doc}, - {"getNumHats", (PyCFunction) SCA_JoystickSensor::sPyNumberOfHats, METH_NOARGS, (PY_METHODCHAR)NumberOfHats_doc}, - {"isConnected", (PyCFunction) SCA_JoystickSensor::sPyConnected, METH_NOARGS, (PY_METHODCHAR)Connected_doc}, + {"getButtonActiveList",(PyCFunction) SCA_JoystickSensor::sPyGetButtonActiveList, METH_NOARGS,(const char *)GetButtonActiveList_doc}, + {"getButtonStatus",(PyCFunction) SCA_JoystickSensor::sPyGetButtonStatus, METH_VARARGS,(const char *)GetButtonStatus_doc}, {NULL,NULL} //Sentinel }; +PyAttributeDef SCA_JoystickSensor::Attributes[] = { + KX_PYATTRIBUTE_SHORT_RW("index",0,JOYINDEX_MAX-1,true,SCA_JoystickSensor,m_joyindex), + KX_PYATTRIBUTE_INT_RW("threshold",0,32768,true,SCA_JoystickSensor,m_precision), + KX_PYATTRIBUTE_INT_RW("button",0,100,false,SCA_JoystickSensor,m_button), + KX_PYATTRIBUTE_INT_LIST_RW_CHECK("axis",0,3,true,SCA_JoystickSensor,m_axis,2,CheckAxis), + KX_PYATTRIBUTE_INT_LIST_RW_CHECK("hat",0,12,true,SCA_JoystickSensor,m_hat,2,CheckHat), + KX_PYATTRIBUTE_RO_FUNCTION("axisValues", SCA_JoystickSensor, pyattr_get_axis_values), + KX_PYATTRIBUTE_RO_FUNCTION("axisSingle", SCA_JoystickSensor, pyattr_get_axis_single), + KX_PYATTRIBUTE_RO_FUNCTION("hatValues", SCA_JoystickSensor, pyattr_get_hat_values), + KX_PYATTRIBUTE_RO_FUNCTION("hatSingle", SCA_JoystickSensor, pyattr_get_hat_single), + KX_PYATTRIBUTE_RO_FUNCTION("numAxis", SCA_JoystickSensor, pyattr_get_num_axis), + KX_PYATTRIBUTE_RO_FUNCTION("numButtons", SCA_JoystickSensor, pyattr_get_num_buttons), + KX_PYATTRIBUTE_RO_FUNCTION("numHats", SCA_JoystickSensor, pyattr_get_num_hats), + KX_PYATTRIBUTE_RO_FUNCTION("connected", SCA_JoystickSensor, pyattr_get_connected), + //KX_PYATTRIBUTE_TODO("events"), + { NULL } //Sentinel +}; -PyObject* SCA_JoystickSensor::_getattr(const STR_String& attr) { - _getattr_up(SCA_ISensor); -} - - -/* get index ---------------------------------------------------------- */ -const char SCA_JoystickSensor::GetIndex_doc[] = -"getIndex\n" -"\tReturns the joystick index to use.\n"; -PyObject* SCA_JoystickSensor::PyGetIndex( PyObject* self ) { - return PyInt_FromLong(m_joyindex); -} - - -/* set index ---------------------------------------------------------- */ -const char SCA_JoystickSensor::SetIndex_doc[] = -"setIndex\n" -"\tSets the joystick index to use.\n"; -PyObject* SCA_JoystickSensor::PySetIndex( PyObject* self, PyObject* value ) { - int index = PyInt_AsLong( value ); /* -1 on error, will raise an error in this case */ - if (index < 0 || index >= JOYINDEX_MAX) { - PyErr_SetString(PyExc_ValueError, "joystick index out of range or not an int"); - return NULL; - } - - m_joyindex = index; - Py_RETURN_NONE; -} - -/* get axis ---------------------------------------------------------- */ -const char SCA_JoystickSensor::GetAxis_doc[] = -"getAxis\n" -"\tReturns the current axis this sensor reacts to.\n"; -PyObject* SCA_JoystickSensor::PyGetAxis( PyObject* self) { - return Py_BuildValue("[ii]",m_axis, m_axisf); -} - - -/* set axis ---------------------------------------------------------- */ -const char SCA_JoystickSensor::SetAxis_doc[] = -"setAxis\n" -"\tSets the current axis this sensor reacts to.\n"; -PyObject* SCA_JoystickSensor::PySetAxis( PyObject* self, PyObject* args ) { - - int axis,axisflag; - if(!PyArg_ParseTuple(args, "ii", &axis, &axisflag)){ - return NULL; - } - m_axis = axis; - m_axisf = axisflag; - Py_RETURN_NONE; -} - - -/* get axis value ----------------------------------------------------- */ -const char SCA_JoystickSensor::GetAxisValue_doc[] = -"getAxisValue\n" -"\tReturns a list of the values for the current state of each axis.\n"; -PyObject* SCA_JoystickSensor::PyGetAxisValue( PyObject* self) { - SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex); - if(joy) - return Py_BuildValue("[iiii]", joy->GetAxis10(), joy->GetAxis11(), joy->GetAxis20(), joy->GetAxis21()); - else - return Py_BuildValue("[iiii]", 0, 0, 0, 0); -} - - -/* get threshold ----------------------------------------------------- */ -const char SCA_JoystickSensor::GetThreshold_doc[] = -"getThreshold\n" -"\tReturns the threshold of the axis.\n"; -PyObject* SCA_JoystickSensor::PyGetThreshold( PyObject* self) { - return PyInt_FromLong(m_precision); -} - - -/* set threshold ----------------------------------------------------- */ -const char SCA_JoystickSensor::SetThreshold_doc[] = -"setThreshold\n" -"\tSets the threshold of the axis.\n"; -PyObject* SCA_JoystickSensor::PySetThreshold( PyObject* self, PyObject* args ) { - int thresh; - if(!PyArg_ParseTuple(args, "i", &thresh)){ - return NULL; - } - m_precision = thresh; - Py_RETURN_NONE; -} - -/* get button -------------------------------------------------------- */ -const char SCA_JoystickSensor::GetButton_doc[] = -"getButton\n" -"\tReturns the current button this sensor is checking.\n"; -PyObject* SCA_JoystickSensor::PyGetButton( PyObject* self) { - return PyInt_FromLong(m_button); -} - -/* set button -------------------------------------------------------- */ -const char SCA_JoystickSensor::SetButton_doc[] = -"setButton\n" -"\tSets the button the sensor reacts to.\n"; -PyObject* SCA_JoystickSensor::PySetButton( PyObject* self, PyObject* value ) { - int button = PyInt_AsLong(value); - if(button==-1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_ValueError, "expected an int"); - return NULL; - } - m_button = button; - Py_RETURN_NONE; -} - -/* get button value -------------------------------------------------- */ -const char SCA_JoystickSensor::GetButtonValue_doc[] = -"getButtonValue\n" -"\tReturns a list containing the indicies of the current pressed state of each button.\n"; -PyObject* SCA_JoystickSensor::PyGetButtonValue( PyObject* self) { - SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex); +/* get button active list -------------------------------------------------- */ +const char SCA_JoystickSensor::GetButtonActiveList_doc[] = +"getButtonActiveList\n" +"\tReturns a list containing the indicies of the button currently pressed.\n"; +PyObject* SCA_JoystickSensor::PyGetButtonActiveList( ) { + SCA_Joystick *joy = ((SCA_JoystickManager *)m_eventmgr)->GetJoystickDevice(m_joyindex); PyObject *ls = PyList_New(0); PyObject *value; int i; @@ -448,7 +309,7 @@ PyObject* SCA_JoystickSensor::PyGetButtonValue( PyObject* self) { if(joy) { for (i=0; i < joy->GetNumberOfButtons(); i++) { if (joy->aButtonPressIsPositive(i)) { - value = PyInt_FromLong(i); + value = PyLong_FromSsize_t(i); PyList_Append(ls, value); Py_DECREF(value); } @@ -457,62 +318,98 @@ PyObject* SCA_JoystickSensor::PyGetButtonValue( PyObject* self) { return ls; } -/* get hat ----------------------------------------------------------- */ -const char SCA_JoystickSensor::GetHat_doc[] = -"getHat\n" -"\tReturns the current direction of the hat.\n"; -PyObject* SCA_JoystickSensor::PyGetHat( PyObject* self ) { - return Py_BuildValue("[ii]",m_hat, m_hatf); +/* get button status -------------------------------------------------- */ +const char SCA_JoystickSensor::GetButtonStatus_doc[] = +"getButtonStatus(buttonIndex)\n" +"\tReturns a bool of the current pressed state of the specified button.\n"; +PyObject* SCA_JoystickSensor::PyGetButtonStatus( PyObject* args ) { + SCA_Joystick *joy = ((SCA_JoystickManager *)m_eventmgr)->GetJoystickDevice(m_joyindex); + int index; + + if(!PyArg_ParseTuple(args, "i:getButtonStatus", &index)){ + return NULL; + } + if(joy && index >= 0 && index < joy->GetNumberOfButtons()) { + return PyBool_FromLong(joy->aButtonPressIsPositive(index) ? 1 : 0); + } + return PyBool_FromLong(0); } +PyObject* SCA_JoystickSensor::pyattr_get_axis_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + SCA_JoystickSensor* self= static_cast<SCA_JoystickSensor*>(self_v); + SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + + int axis_index= joy->GetNumberOfAxes(); + PyObject *list= PyList_New(axis_index); + + while(axis_index--) { + PyList_SET_ITEM(list, axis_index, PyLong_FromSsize_t(joy->GetAxisPosition(axis_index))); + } + + return list; +} -/* set hat ----------------------------------------------------------- */ -const char SCA_JoystickSensor::SetHat_doc[] = -"setHat\n" -"\tSets the hat the sensor reacts to.\n"; -PyObject* SCA_JoystickSensor::PySetHat( PyObject* self, PyObject* args ) { - int hat,hatflag; - if(!PyArg_ParseTuple(args, "ii", &hat, &hatflag)){ +PyObject* SCA_JoystickSensor::pyattr_get_axis_single(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + SCA_JoystickSensor* self= static_cast<SCA_JoystickSensor*>(self_v); + SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + + if(self->m_joymode != KX_JOYSENSORMODE_AXIS_SINGLE) { + PyErr_SetString(PyExc_TypeError, "val = sensor.axisSingle: Joystick Sensor, not 'Single Axis' type"); return NULL; } - m_hat = hat; - m_hatf = hatflag; - Py_RETURN_NONE; + + return PyLong_FromSsize_t(joy->GetAxisPosition(self->m_axis-1)); } - -/* get # of ----------------------------------------------------- */ -const char SCA_JoystickSensor::NumberOfAxes_doc[] = -"getNumAxes\n" -"\tReturns the number of axes .\n"; -PyObject* SCA_JoystickSensor::PyNumberOfAxes( PyObject* self ) { - SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex); - // when the joystick is null their is 0 exis still. dumb but scripters should use isConnected() - return PyInt_FromLong( joy ? joy->GetNumberOfAxes() : 0 ); +PyObject* SCA_JoystickSensor::pyattr_get_hat_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + SCA_JoystickSensor* self= static_cast<SCA_JoystickSensor*>(self_v); + SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + + int hat_index= joy->GetNumberOfHats(); + PyObject *list= PyList_New(hat_index); + + while(hat_index--) { + PyList_SET_ITEM(list, hat_index, PyLong_FromSsize_t(joy->GetHat(hat_index))); + } + + return list; } +PyObject* SCA_JoystickSensor::pyattr_get_hat_single(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + SCA_JoystickSensor* self= static_cast<SCA_JoystickSensor*>(self_v); + SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + + return PyLong_FromSsize_t(joy->GetHat(self->m_hat-1)); +} -const char SCA_JoystickSensor::NumberOfButtons_doc[] = -"getNumButtons\n" -"\tReturns the number of buttons .\n"; -PyObject* SCA_JoystickSensor::PyNumberOfButtons( PyObject* self ) { - SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex); - return PyInt_FromLong( joy ? joy->GetNumberOfButtons() : 0 ); +PyObject* SCA_JoystickSensor::pyattr_get_num_axis(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + SCA_JoystickSensor* self= static_cast<SCA_JoystickSensor*>(self_v); + SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + return PyLong_FromSsize_t( joy ? joy->GetNumberOfAxes() : 0 ); } +PyObject* SCA_JoystickSensor::pyattr_get_num_buttons(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + SCA_JoystickSensor* self= static_cast<SCA_JoystickSensor*>(self_v); + SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + return PyLong_FromSsize_t( joy ? joy->GetNumberOfButtons() : 0 ); +} -const char SCA_JoystickSensor::NumberOfHats_doc[] = -"getNumHats\n" -"\tReturns the number of hats .\n"; -PyObject* SCA_JoystickSensor::PyNumberOfHats( PyObject* self ) { - SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex); - return PyInt_FromLong( joy ? joy->GetNumberOfHats() : 0 ); +PyObject* SCA_JoystickSensor::pyattr_get_num_hats(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + SCA_JoystickSensor* self= static_cast<SCA_JoystickSensor*>(self_v); + SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + return PyLong_FromSsize_t( joy ? joy->GetNumberOfHats() : 0 ); } -const char SCA_JoystickSensor::Connected_doc[] = -"getConnected\n" -"\tReturns True if a joystick is connected at this joysticks index.\n"; -PyObject* SCA_JoystickSensor::PyConnected( PyObject* self ) { - SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex); +PyObject* SCA_JoystickSensor::pyattr_get_connected(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + SCA_JoystickSensor* self= static_cast<SCA_JoystickSensor*>(self_v); + SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); return PyBool_FromLong( joy ? joy->Connected() : 0 ); } diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.h b/source/gameengine/GameLogic/SCA_JoystickSensor.h index d316ad1119c..b793c591ac1 100644 --- a/source/gameengine/GameLogic/SCA_JoystickSensor.h +++ b/source/gameengine/GameLogic/SCA_JoystickSensor.h @@ -30,18 +30,18 @@ #define __JOYSENSOR_H #include "SCA_ISensor.h" +#include "./Joystick/SCA_JoystickDefines.h" class SCA_JoystickSensor :public SCA_ISensor { Py_Header; - class SCA_JoystickManager* m_pJoystickMgr; /** - * Axis 1-or-2 + * Axis 1-JOYAXIS_MAX, MUST be followed by m_axisf */ int m_axis; /** - * Axis flag to find direction + * Axis flag to find direction, MUST be an int */ int m_axisf; /** @@ -53,11 +53,11 @@ class SCA_JoystickSensor :public SCA_ISensor */ int m_buttonf; /** - * The actual hat + * The actual hat 1-JOYHAT_MAX. MUST be followed by m_hatf */ int m_hat; /** - * Flag to find direction 1-12 + * Flag to find direction 1-12, MUST be an int */ int m_hatf; /** @@ -93,6 +93,7 @@ class SCA_JoystickSensor :public SCA_ISensor KX_JOYSENSORMODE_AXIS, KX_JOYSENSORMODE_BUTTON, KX_JOYSENSORMODE_HAT, + KX_JOYSENSORMODE_AXIS_SINGLE, KX_JOYSENSORMODE_MAX }; bool isValid(KX_JOYSENSORMODE); @@ -104,12 +105,11 @@ public: short int joymode, int axis, int axisf,int prec, int button, - int hat, int hatf, bool allevents, - PyTypeObject* T=&Type ); + int hat, int hatf, bool allevents); virtual ~SCA_JoystickSensor(); virtual CValue* GetReplica(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void Init(); @@ -121,29 +121,39 @@ public: /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); - /* Joystick Index */ - KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetIndex); - KX_PYMETHOD_DOC_O(SCA_JoystickSensor,SetIndex); - /* Axes*/ - KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetAxis); - KX_PYMETHOD_DOC_VARARGS(SCA_JoystickSensor,SetAxis); - KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetAxisValue); - KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetThreshold); - KX_PYMETHOD_DOC_VARARGS(SCA_JoystickSensor,SetThreshold); - /* Buttons */ - KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetButton); - KX_PYMETHOD_DOC_O(SCA_JoystickSensor,SetButton); - KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetButtonValue); - /* Hats */ - KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetHat); - KX_PYMETHOD_DOC_VARARGS(SCA_JoystickSensor,SetHat); - /* number of */ - KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,NumberOfAxes); - KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,NumberOfButtons); - KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,NumberOfHats); - KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,Connected); + KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetButtonActiveList); + KX_PYMETHOD_DOC_VARARGS(SCA_JoystickSensor,GetButtonStatus); + + static PyObject* pyattr_get_axis_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_axis_single(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_hat_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_hat_single(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_num_axis(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_num_buttons(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_num_hats(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_connected(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + + + /* attribute check */ + static int CheckAxis(void *self, const PyAttributeDef*) + { + SCA_JoystickSensor* sensor = reinterpret_cast<SCA_JoystickSensor*>(self); + if (sensor->m_axis < 1) + sensor->m_axis = 1; + else if (sensor->m_axis > JOYAXIS_MAX) + sensor->m_axis = JOYAXIS_MAX; + return 0; + } + static int CheckHat(void *self, const PyAttributeDef*) + { + SCA_JoystickSensor* sensor = reinterpret_cast<SCA_JoystickSensor*>(self); + if (sensor->m_hat < 1) + sensor->m_hat = 1; + else if (sensor->m_hat > JOYHAT_MAX) + sensor->m_hat = JOYHAT_MAX; + return 0; + } }; diff --git a/source/gameengine/GameLogic/SCA_KeyboardManager.cpp b/source/gameengine/GameLogic/SCA_KeyboardManager.cpp index 6a96442b124..279adab94d8 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardManager.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardManager.cpp @@ -62,12 +62,11 @@ void SCA_KeyboardManager::NextFrame() { //const SCA_InputEvent& event = GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode)=0; // cerr << "SCA_KeyboardManager::NextFrame"<< endl; - set<SCA_ISensor*>::iterator it; - for (it=m_sensors.begin(); it != m_sensors.end(); it++) + SG_DList::iterator<SCA_ISensor> it(m_sensors); + for (it.begin();!it.end();++it) { - (*it)->Activate(m_logicmanager,NULL); + (*it)->Activate(m_logicmanager); } - } bool SCA_KeyboardManager::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode) diff --git a/source/gameengine/GameLogic/SCA_KeyboardManager.h b/source/gameengine/GameLogic/SCA_KeyboardManager.h index 8f3cc0ab715..c5553a74aef 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardManager.h +++ b/source/gameengine/GameLogic/SCA_KeyboardManager.h @@ -56,6 +56,13 @@ public: virtual void NextFrame(); SCA_IInputDevice* GetInputDevice(); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_KeyboardManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_KEYBOARDMANAGER diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp index fa39a13679f..d2e3871fec2 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp @@ -48,10 +48,8 @@ SCA_KeyboardSensor::SCA_KeyboardSensor(SCA_KeyboardManager* keybdmgr, bool bAllKeys, const STR_String& targetProp, const STR_String& toggleProp, - SCA_IObject* gameobj, - PyTypeObject* T ) - :SCA_ISensor(gameobj,keybdmgr,T), - m_pKeyboardMgr(keybdmgr), + SCA_IObject* gameobj) + :SCA_ISensor(gameobj,keybdmgr), m_hotkey(hotkey), m_qual(qual), m_qual2(qual2), @@ -85,7 +83,7 @@ CValue* SCA_KeyboardSensor::GetReplica() { SCA_KeyboardSensor* replica = new SCA_KeyboardSensor(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); replica->Init(); return replica; } @@ -118,7 +116,7 @@ bool SCA_KeyboardSensor::TriggerOnAllKeys() -bool SCA_KeyboardSensor::Evaluate(CValue* eventval) +bool SCA_KeyboardSensor::Evaluate() { bool result = false; bool reset = m_reset && m_level; @@ -126,7 +124,7 @@ bool SCA_KeyboardSensor::Evaluate(CValue* eventval) bool qual_change = false; short int m_val_orig = m_val; - SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice(); + SCA_IInputDevice* inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); // cerr << "SCA_KeyboardSensor::Eval event, sensing for "<< m_hotkey << " at device " << inputdev << "\n"; /* See if we need to do logging: togPropState exists and is @@ -148,7 +146,7 @@ bool SCA_KeyboardSensor::Evaluate(CValue* eventval) bool justreleased = false; bool active = false; - for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++) + for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++) { const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); switch (inevent.m_status) @@ -195,6 +193,9 @@ bool SCA_KeyboardSensor::Evaluate(CValue* eventval) } } } + if (m_tap) + // special case for tap mode: only generate event for new activation + result = false; } @@ -352,52 +353,154 @@ void SCA_KeyboardSensor::AddToTargetProp(int keyIndex) } } - + /** - * Determine whether this character can be printed. We cannot use - * the library functions here, because we need to test our own - * keycodes. */ -bool SCA_KeyboardSensor::IsPrintable(int keyIndex) + * Tests whether shift is pressed + */ +bool SCA_KeyboardSensor::IsShifted(void) { - /* only print - * - numerals: KX_ZEROKEY to KX_NINEKEY - * - alphas: KX_AKEY to KX_ZKEY. - * - specials: KX_RETKEY, KX_PADASTERKEY, KX_PADCOMMAKEY to KX_PERIODKEY, - * KX_TABKEY , KX_SEMICOLONKEY to KX_RIGHTBRACKETKEY, - * KX_PAD2 to KX_PADPLUSKEY - * - delete and backspace: also printable in the sense that they modify - * the string - * - retkey: should this be printable? - * - virgule: prints a space... don't know which key that's supposed - * to be... - */ - if ( ((keyIndex >= SCA_IInputDevice::KX_ZEROKEY) - && (keyIndex <= SCA_IInputDevice::KX_NINEKEY)) - || ((keyIndex >= SCA_IInputDevice::KX_AKEY) - && (keyIndex <= SCA_IInputDevice::KX_ZKEY)) - || (keyIndex == SCA_IInputDevice::KX_SPACEKEY) -/* || (keyIndex == KX_RETKEY) */ - || (keyIndex == SCA_IInputDevice::KX_PADASTERKEY) - || (keyIndex == SCA_IInputDevice::KX_TABKEY) - || ((keyIndex >= SCA_IInputDevice::KX_COMMAKEY) - && (keyIndex <= SCA_IInputDevice::KX_PERIODKEY)) - || ((keyIndex >= SCA_IInputDevice::KX_SEMICOLONKEY) - && (keyIndex <= SCA_IInputDevice::KX_RIGHTBRACKETKEY)) - || ((keyIndex >= SCA_IInputDevice::KX_PAD2) - && (keyIndex <= SCA_IInputDevice::KX_PADPLUSKEY)) - || (keyIndex == SCA_IInputDevice::KX_DELKEY) - || (keyIndex == SCA_IInputDevice::KX_BACKSPACEKEY) - ) - { + SCA_IInputDevice* inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); + + if ( (inputdev->GetEventValue(SCA_IInputDevice::KX_RIGHTSHIFTKEY).m_status + == SCA_InputEvent::KX_ACTIVE) + || (inputdev->GetEventValue(SCA_IInputDevice::KX_RIGHTSHIFTKEY).m_status + == SCA_InputEvent::KX_JUSTACTIVATED) + || (inputdev->GetEventValue(SCA_IInputDevice::KX_LEFTSHIFTKEY).m_status + == SCA_InputEvent::KX_ACTIVE) + || (inputdev->GetEventValue(SCA_IInputDevice::KX_LEFTSHIFTKEY).m_status + == SCA_InputEvent::KX_JUSTACTIVATED) + ) { return true; } else { return false; + } +} + +void SCA_KeyboardSensor::LogKeystrokes(void) +{ + SCA_IInputDevice* inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); + int num = inputdev->GetNumActiveEvents(); + + /* weird loop, this one... */ + if (num > 0) + { + + int index = 0; + /* Check on all keys whether they were pushed. This does not + * untangle the ordering, so don't type too fast :) */ + for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++) + { + const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); + if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED) //NO_INPUTSTATUS) + { + if (index < num) + { + AddToTargetProp(i); + index++; + } + } + } + } +} + + +/* ------------------------------------------------------------------------- */ +/* Python Functions */ +/* ------------------------------------------------------------------------- */ + +KX_PYMETHODDEF_DOC_O(SCA_KeyboardSensor, getKeyStatus, +"getKeyStatus(keycode)\n" +"\tGet the given key's status (KX_NO_INPUTSTATUS, KX_JUSTACTIVATED, KX_ACTIVE or KX_JUSTRELEASED).\n") +{ + if (!PyLong_Check(value)) { + PyErr_SetString(PyExc_ValueError, "sensor.getKeyStatus(int): Keyboard Sensor, expected an int"); + return NULL; + } + + int keycode = PyLong_AsSsize_t(value); + + if ((keycode < SCA_IInputDevice::KX_BEGINKEY) + || (keycode > SCA_IInputDevice::KX_ENDKEY)){ + PyErr_SetString(PyExc_AttributeError, "sensor.getKeyStatus(int): Keyboard Sensor, invalid keycode specified!"); + return NULL; } + + SCA_IInputDevice* inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); + const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) keycode); + return PyLong_FromSsize_t(inevent.m_status); +} + +/* ------------------------------------------------------------------------- */ +/* Python Integration Hooks */ +/* ------------------------------------------------------------------------- */ + +PyTypeObject SCA_KeyboardSensor::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "SCA_KeyboardSensor", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_ISensor::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyMethodDef SCA_KeyboardSensor::Methods[] = { + KX_PYMETHODTABLE_O(SCA_KeyboardSensor, getKeyStatus), + {NULL,NULL} //Sentinel +}; + +PyAttributeDef SCA_KeyboardSensor::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("events", SCA_KeyboardSensor, pyattr_get_events), + KX_PYATTRIBUTE_BOOL_RW("useAllKeys",SCA_KeyboardSensor,m_bAllKeys), + KX_PYATTRIBUTE_INT_RW("key",0,SCA_IInputDevice::KX_ENDKEY,true,SCA_KeyboardSensor,m_hotkey), + KX_PYATTRIBUTE_SHORT_RW("hold1",0,SCA_IInputDevice::KX_ENDKEY,true,SCA_KeyboardSensor,m_qual), + KX_PYATTRIBUTE_SHORT_RW("hold2",0,SCA_IInputDevice::KX_ENDKEY,true,SCA_KeyboardSensor,m_qual2), + KX_PYATTRIBUTE_STRING_RW("toggleProperty",0,100,false,SCA_KeyboardSensor,m_toggleprop), + KX_PYATTRIBUTE_STRING_RW("targetProperty",0,100,false,SCA_KeyboardSensor,m_targetprop), + { NULL } //Sentinel +}; + + +PyObject* SCA_KeyboardSensor::pyattr_get_events(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + SCA_KeyboardSensor* self= static_cast<SCA_KeyboardSensor*>(self_v); + + SCA_IInputDevice* inputdev = ((SCA_KeyboardManager *)self->m_eventmgr)->GetInputDevice(); + + PyObject* resultlist = PyList_New(0); + + for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++) + { + const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); + if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) + { + PyObject* keypair = PyList_New(2); + PyList_SET_ITEM(keypair,0,PyLong_FromSsize_t(i)); + PyList_SET_ITEM(keypair,1,PyLong_FromSsize_t(inevent.m_status)); + PyList_Append(resultlist,keypair); + } + } + return resultlist; } + +/* Accessed from python */ + // this code looks ugly, please use an ordinary hashtable -char SCA_KeyboardSensor::ToCharacter(int keyIndex, bool shifted) +char ToCharacter(int keyIndex, bool shifted) { /* numerals */ if ( (keyIndex >= SCA_IInputDevice::KX_ZEROKEY) @@ -423,8 +526,10 @@ char SCA_KeyboardSensor::ToCharacter(int keyIndex, bool shifted) if (keyIndex == SCA_IInputDevice::KX_SPACEKEY) { return ' '; } + if (keyIndex == SCA_IInputDevice::KX_RETKEY || keyIndex == SCA_IInputDevice::KX_PADENTER) { + return '\n'; + } -/* || (keyIndex == SCA_IInputDevice::KX_RETKEY) */ if (keyIndex == SCA_IInputDevice::KX_PADASTERKEY) { return '*'; @@ -460,8 +565,8 @@ char SCA_KeyboardSensor::ToCharacter(int keyIndex, bool shifted) } /* semicolon to rightbracket */ - char semicolontorightbracket[] = ";\'` /\\=[]"; - char semicolontorightbracketshifted[] = ":\"~ \?|+{}"; + char semicolontorightbracket[] = ";\'`/\\=[]"; + char semicolontorightbracketshifted[] = ":\"~\?|+{}"; if ((keyIndex >= SCA_IInputDevice::KX_SEMICOLONKEY) && (keyIndex <= SCA_IInputDevice::KX_RIGHTBRACKETKEY)) { if (shifted) { @@ -480,14 +585,46 @@ char SCA_KeyboardSensor::ToCharacter(int keyIndex, bool shifted) return '!'; } - + + + /** - * Tests whether this is a delete key. - */ -bool SCA_KeyboardSensor::IsDelete(int keyIndex) + * Determine whether this character can be printed. We cannot use + * the library functions here, because we need to test our own + * keycodes. */ +bool IsPrintable(int keyIndex) { - if ( (keyIndex == SCA_IInputDevice::KX_DELKEY) - || (keyIndex == SCA_IInputDevice::KX_BACKSPACEKEY) ) { + /* only print + * - numerals: KX_ZEROKEY to KX_NINEKEY + * - alphas: KX_AKEY to KX_ZKEY. + * - specials: KX_RETKEY, KX_PADASTERKEY, KX_PADCOMMAKEY to KX_PERIODKEY, + * KX_TABKEY , KX_SEMICOLONKEY to KX_RIGHTBRACKETKEY, + * KX_PAD2 to KX_PADPLUSKEY + * - delete and backspace: also printable in the sense that they modify + * the string + * - retkey: should this be printable? + * - virgule: prints a space... don't know which key that's supposed + * to be... + */ + if ( ((keyIndex >= SCA_IInputDevice::KX_ZEROKEY) + && (keyIndex <= SCA_IInputDevice::KX_NINEKEY)) + || ((keyIndex >= SCA_IInputDevice::KX_AKEY) + && (keyIndex <= SCA_IInputDevice::KX_ZKEY)) + || (keyIndex == SCA_IInputDevice::KX_SPACEKEY) + || (keyIndex == SCA_IInputDevice::KX_RETKEY) + || (keyIndex == SCA_IInputDevice::KX_PADENTER) + || (keyIndex == SCA_IInputDevice::KX_PADASTERKEY) + || (keyIndex == SCA_IInputDevice::KX_TABKEY) + || ((keyIndex >= SCA_IInputDevice::KX_COMMAKEY) + && (keyIndex <= SCA_IInputDevice::KX_PERIODKEY)) + || ((keyIndex >= SCA_IInputDevice::KX_SEMICOLONKEY) + && (keyIndex <= SCA_IInputDevice::KX_RIGHTBRACKETKEY)) + || ((keyIndex >= SCA_IInputDevice::KX_PAD2) + && (keyIndex <= SCA_IInputDevice::KX_PADPLUSKEY)) + || (keyIndex == SCA_IInputDevice::KX_DELKEY) + || (keyIndex == SCA_IInputDevice::KX_BACKSPACEKEY) + ) + { return true; } else { return false; @@ -495,304 +632,14 @@ bool SCA_KeyboardSensor::IsDelete(int keyIndex) } /** - * Tests whether shift is pressed + * Tests whether this is a delete key. */ -bool SCA_KeyboardSensor::IsShifted(void) +bool IsDelete(int keyIndex) { - SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice(); - - if ( (inputdev->GetEventValue(SCA_IInputDevice::KX_RIGHTSHIFTKEY).m_status - == SCA_InputEvent::KX_ACTIVE) - || (inputdev->GetEventValue(SCA_IInputDevice::KX_RIGHTSHIFTKEY).m_status - == SCA_InputEvent::KX_JUSTACTIVATED) - || (inputdev->GetEventValue(SCA_IInputDevice::KX_LEFTSHIFTKEY).m_status - == SCA_InputEvent::KX_ACTIVE) - || (inputdev->GetEventValue(SCA_IInputDevice::KX_LEFTSHIFTKEY).m_status - == SCA_InputEvent::KX_JUSTACTIVATED) - ) { + if ( (keyIndex == SCA_IInputDevice::KX_DELKEY) + || (keyIndex == SCA_IInputDevice::KX_BACKSPACEKEY) ) { return true; } else { return false; - } -} - -void SCA_KeyboardSensor::LogKeystrokes(void) -{ - SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice(); - int num = inputdev->GetNumActiveEvents(); - - /* weird loop, this one... */ - if (num > 0) - { - - int index = 0; - /* Check on all keys whether they were pushed. This does not - * untangle the ordering, so don't type too fast :) */ - for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++) - { - const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); - if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED) //NO_INPUTSTATUS) - { - if (index < num) - { - AddToTargetProp(i); - index++; - } - } - } - } -} - - -/* ------------------------------------------------------------------------- */ -/* Python functions : specific */ -/* ------------------------------------------------------------------------- */ - - -PyObject* SCA_KeyboardSensor::PySetAllMode(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - bool allkeys; - - if (!PyArg_ParseTuple(args, "i", &allkeys)) - { - return NULL; - } - - m_bAllKeys = allkeys; - Py_Return -} - - - -PyObject* SCA_KeyboardSensor::sPySetAllMode(PyObject* self, - PyObject* args, - PyObject* kwds) -{ -// printf("sPyIsPositive\n"); - return ((SCA_KeyboardSensor*) self)->PyIsPositive(self); -} - - -/** 1. GetKey : check which key this sensor looks at */ -const char SCA_KeyboardSensor::GetKey_doc[] = -"getKey()\n" -"\tReturn the code of the key this sensor is listening to.\n" ; -PyObject* SCA_KeyboardSensor::PyGetKey(PyObject* self, PyObject* args, PyObject* kwds) -{ - return PyInt_FromLong(m_hotkey); -} - -/** 2. SetKey: change the key to look at */ -const char SCA_KeyboardSensor::SetKey_doc[] = -"setKey(keycode)\n" -"\t- keycode: any code from GameKeys\n" -"\tSet the key this sensor should listen to.\n" ; -PyObject* SCA_KeyboardSensor::PySetKey(PyObject* self, PyObject* args, PyObject* kwds) -{ - int keyCode; - - if(!PyArg_ParseTuple(args, "i", &keyCode)) { - return NULL; - } - - /* Since we have symbolic constants for this in Python, we don't guard */ - /* anything. It's up to the user to provide a sensible number. */ - m_hotkey = keyCode; - - Py_Return; -} - -/** 3. GetHold1 : set the first bucky bit */ -const char SCA_KeyboardSensor::GetHold1_doc[] = -"getHold1()\n" -"\tReturn the code of the first key modifier to the key this \n" -"\tsensor is listening to.\n" ; -PyObject* SCA_KeyboardSensor::PyGetHold1(PyObject* self, PyObject* args, PyObject* kwds) -{ - return PyInt_FromLong(m_qual); -} - -/** 4. SetHold1: change the first bucky bit */ -const char SCA_KeyboardSensor::SetHold1_doc[] = -"setHold1(keycode)\n" -"\t- keycode: any code from GameKeys\n" -"\tSet the first modifier to the key this sensor should listen to.\n" ; -PyObject* SCA_KeyboardSensor::PySetHold1(PyObject* self, PyObject* args, PyObject* kwds) -{ - int keyCode; - - if(!PyArg_ParseTuple(args, "i", &keyCode)) { - return NULL; - } - - /* Since we have symbolic constants for this in Python, we don't guard */ - /* anything. It's up to the user to provide a sensible number. */ - m_qual = keyCode; - - Py_Return; -} - -/** 5. GetHold2 : get the second bucky bit */ -const char SCA_KeyboardSensor::GetHold2_doc[] = -"getHold2()\n" -"\tReturn the code of the second key modifier to the key this \n" -"\tsensor is listening to.\n" ; -PyObject* SCA_KeyboardSensor::PyGetHold2(PyObject* self, PyObject* args, PyObject* kwds) -{ - return PyInt_FromLong(m_qual2); -} - -/** 6. SetHold2: change the second bucky bit */ -const char SCA_KeyboardSensor::SetHold2_doc[] = -"setHold2(keycode)\n" -"\t- keycode: any code from GameKeys\n" -"\tSet the first modifier to the key this sensor should listen to.\n" ; -PyObject* SCA_KeyboardSensor::PySetHold2(PyObject* self, PyObject* args, PyObject* kwds) -{ - int keyCode; - - if(!PyArg_ParseTuple(args, "i", &keyCode)) { - return NULL; - } - - /* Since we have symbolic constants for this in Python, we don't guard */ - /* anything. It's up to the user to provide a sensible number. */ - m_qual2 = keyCode; - - Py_Return; -} - - -const char SCA_KeyboardSensor::GetPressedKeys_doc[] = -"getPressedKeys()\n" -"\tGet a list of pressed keys that have either been pressed, or just released this frame.\n" ; - -PyObject* SCA_KeyboardSensor::PyGetPressedKeys(PyObject* self, PyObject* args, PyObject* kwds) -{ - SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice(); - - int num = inputdev->GetNumJustEvents(); - PyObject* resultlist = PyList_New(num); - - if (num > 0) - { - - int index = 0; - - for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++) - { - const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); - if ((inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED) - || (inevent.m_status == SCA_InputEvent::KX_JUSTRELEASED)) - { - if (index < num) - { - PyObject* keypair = PyList_New(2); - PyList_SetItem(keypair,0,PyInt_FromLong(i)); - PyList_SetItem(keypair,1,PyInt_FromLong(inevent.m_status)); - PyList_SetItem(resultlist,index,keypair); - index++; - } - } - } - if (index>0) return resultlist; - } - - Py_Return; -} - - - -const char SCA_KeyboardSensor::GetCurrentlyPressedKeys_doc[] = -"getCurrentlyPressedKeys()\n" -"\tGet a list of keys that are currently pressed.\n" ; - -PyObject* SCA_KeyboardSensor::PyGetCurrentlyPressedKeys(PyObject* self, PyObject* args, PyObject* kwds) -{ -SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice(); - - int num = inputdev->GetNumActiveEvents(); - PyObject* resultlist = PyList_New(num); - - if (num > 0) - { - int index = 0; - - for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++) - { - const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); - if ( (inevent.m_status == SCA_InputEvent::KX_ACTIVE) - || (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED)) - { - if (index < num) - { - PyObject* keypair = PyList_New(2); - PyList_SetItem(keypair,0,PyInt_FromLong(i)); - PyList_SetItem(keypair,1,PyInt_FromLong(inevent.m_status)); - PyList_SetItem(resultlist,index,keypair); - index++; - } - } - } - - /* why?*/ - if (index > 0) return resultlist; } - - Py_Return; -} - -/* ------------------------------------------------------------------------- */ -/* Python functions : integration hooks */ -/* ------------------------------------------------------------------------- */ - -PyTypeObject SCA_KeyboardSensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "SCA_KeyboardSensor", - sizeof(SCA_KeyboardSensor), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 -}; - -PyParentObject SCA_KeyboardSensor::Parents[] = { - &SCA_KeyboardSensor::Type, - &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL -}; - -PyMethodDef SCA_KeyboardSensor::Methods[] = { - {"getKey", (PyCFunction) SCA_KeyboardSensor::sPyGetKey, METH_VARARGS, (PY_METHODCHAR)GetKey_doc}, - {"setKey", (PyCFunction) SCA_KeyboardSensor::sPySetKey, METH_VARARGS, (PY_METHODCHAR)SetKey_doc}, - {"getHold1", (PyCFunction) SCA_KeyboardSensor::sPyGetHold1, METH_VARARGS, (PY_METHODCHAR)GetHold1_doc}, - {"setHold1", (PyCFunction) SCA_KeyboardSensor::sPySetHold1, METH_VARARGS, (PY_METHODCHAR)SetHold1_doc}, - {"getHold2", (PyCFunction) SCA_KeyboardSensor::sPyGetHold2, METH_VARARGS, (PY_METHODCHAR)GetHold2_doc}, - {"setHold2", (PyCFunction) SCA_KeyboardSensor::sPySetHold2, METH_VARARGS, (PY_METHODCHAR)SetHold2_doc}, -// {"getUseAllKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetUseAllKeys, METH_VARARGS, (PY_METHODCHAR)GetUseAllKeys_doc}, -// {"setUseAllKeys", (PyCFunction) SCA_KeyboardSensor::sPySetUseAllKeys, METH_VARARGS, (PY_METHODCHAR)SetUseAllKeys_doc}, - {"getPressedKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetPressedKeys, METH_VARARGS, (PY_METHODCHAR)GetPressedKeys_doc}, - {"getCurrentlyPressedKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetCurrentlyPressedKeys, METH_VARARGS, (PY_METHODCHAR)GetCurrentlyPressedKeys_doc}, -// {"getKeyEvents", (PyCFunction) SCA_KeyboardSensor::sPyGetKeyEvents, METH_VARARGS, (PY_METHODCHAR)GetKeyEvents_doc}, - {NULL,NULL} //Sentinel -}; - -PyObject* -SCA_KeyboardSensor::_getattr(const STR_String& attr) -{ - _getattr_up(SCA_ISensor); } - diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.h b/source/gameengine/GameLogic/SCA_KeyboardSensor.h index b86f6931d27..d7e0f301a9d 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardSensor.h +++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.h @@ -43,8 +43,6 @@ class SCA_KeyboardSensor : public SCA_ISensor { Py_Header; - class SCA_KeyboardManager* m_pKeyboardMgr; - /** * the key this sensor is sensing for @@ -82,22 +80,6 @@ class SCA_KeyboardSensor : public SCA_ISensor void AddToTargetProp(int keyIndex); /** - * Determine whether this character can be printed. We cannot use - * the library functions here, because we need to test our own - * keycodes. */ - bool IsPrintable(int keyIndex); - - /** - * Transform keycodes to something printable. - */ - char ToCharacter(int keyIndex, bool shifted); - - /** - * Tests whether this is a delete key. - */ - bool IsDelete(int keyIndex); - - /** * Tests whether shift is pressed. */ bool IsShifted(void); @@ -110,15 +92,14 @@ public: bool bAllKeys, const STR_String& targetProp, const STR_String& toggleProp, - SCA_IObject* gameobj, - PyTypeObject* T=&Type ); + SCA_IObject* gameobj); virtual ~SCA_KeyboardSensor(); virtual CValue* GetReplica(); virtual void Init(); short int GetHotkey(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual bool IsPositiveTrigger(); bool TriggerOnAllKeys(); @@ -126,33 +107,33 @@ public: /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); - - - PyObject* PySetAllMode(PyObject* self, - PyObject* args, - PyObject* kwds); - static PyObject* sPySetAllMode(PyObject* self, - PyObject* args, - PyObject* kwds); + // KeyEvents: + KX_PYMETHOD_DOC_NOARGS(SCA_KeyboardSensor,getEventList); + // KeyStatus: + KX_PYMETHOD_DOC_O(SCA_KeyboardSensor,getKeyStatus); - /** 1. GetKey : check which key this sensor looks at */ - KX_PYMETHOD_DOC(SCA_KeyboardSensor,GetKey); - /** 2. SetKey: change the key to look at */ - KX_PYMETHOD_DOC(SCA_KeyboardSensor,SetKey); - /** 3. GetHold1 : set the first bucky bit */ - KX_PYMETHOD_DOC(SCA_KeyboardSensor,GetHold1); - /** 4. SetHold1: change the first bucky bit */ - KX_PYMETHOD_DOC(SCA_KeyboardSensor,SetHold1); - /** 5. GetHold2 : set the second bucky bit */ - KX_PYMETHOD_DOC(SCA_KeyboardSensor,GetHold2); - /** 6. SetHold2: change the second bucky bit */ - KX_PYMETHOD_DOC(SCA_KeyboardSensor,SetHold2); - /** 9. GetPressedKeys: */ - KX_PYMETHOD_DOC(SCA_KeyboardSensor,GetPressedKeys); - /** 9. GetCurrrentlyPressedKeys: */ - KX_PYMETHOD_DOC(SCA_KeyboardSensor,GetCurrentlyPressedKeys); + static PyObject* pyattr_get_events(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); }; + +/** + * Transform keycodes to something printable. + */ +char ToCharacter(int keyIndex, bool shifted); + +/** + * Determine whether this character can be printed. We cannot use + * the library functions here, because we need to test our own + * keycodes. */ +bool IsPrintable(int keyIndex); + +/** + * Tests whether this is a delete key. + */ +bool IsDelete(int keyIndex); + + #endif //__KX_KEYBOARDSENSOR + + diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp index b584b37180f..b782c6dfb93 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.cpp +++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp @@ -49,37 +49,14 @@ SCA_LogicManager::SCA_LogicManager() SCA_LogicManager::~SCA_LogicManager() { - /* AddRef() is not used when the objects are added to m_mapStringToGameObjects - so Release() should not be used either. The memory leak big is fixed - in BL_ConvertBlenderObjects() - - int numgameobj = m_mapStringToGameObjects.size(); - for (int i = 0; i < numgameobj; i++) - { - CValue** gameobjptr = m_mapStringToGameObjects.at(i); - assert(gameobjptr); - if (gameobjptr) - (*gameobjptr)->Release(); - - } - */ - /*for (int i=0;i<m_sensorcontrollermap.size();i++) - { - vector<SCA_IController*>* controllerarray = *(m_sensorcontrollermap[i]); - delete controllerarray; - } - */ - for (vector<SCA_EventManager*>::iterator it = m_eventmanagers.begin();!(it==m_eventmanagers.end());it++) + for (vector<SCA_EventManager*>::iterator it = m_eventmanagers.begin();!(it==m_eventmanagers.end());++it) { delete (*it); } m_eventmanagers.clear(); - m_sensorcontrollermapje.clear(); - m_removedActuators.clear(); - m_activeActuators.clear(); + assert(m_activeActuators.Empty()); } - /* // this kind of fixes bug 398 but breakes games, so better leave it out for now. // a removed object's gameobject (and logicbricks and stuff) didn't get released @@ -171,12 +148,7 @@ void* SCA_LogicManager::FindBlendObjByGameMeshName(const STR_String& gamemeshnam void SCA_LogicManager::RemoveSensor(SCA_ISensor* sensor) { - controllerlist contlist = m_sensorcontrollermapje[sensor]; - for (controllerlist::const_iterator c= contlist.begin();!(c==contlist.end());c++) - { - (*c)->UnlinkSensor(sensor); - } - m_sensorcontrollermapje.erase(sensor); + sensor->UnlinkAllControllers(); sensor->UnregisterToManager(); } @@ -184,35 +156,22 @@ void SCA_LogicManager::RemoveController(SCA_IController* controller) { controller->UnlinkAllSensors(); controller->UnlinkAllActuators(); - std::map<SCA_ISensor*,controllerlist>::iterator sit; - for (sit = m_sensorcontrollermapje.begin();!(sit==m_sensorcontrollermapje.end());++sit) - { - (*sit).second.remove(controller); - } + controller->Deactivate(); } -void SCA_LogicManager::RemoveDestroyedActuator(SCA_IActuator* actuator) +void SCA_LogicManager::RemoveActuator(SCA_IActuator* actuator) { - m_removedActuators.push_back(SmartActuatorPtr(actuator,0)); - // take care that no controller can use this actuator again ! - - std::map<SCA_ISensor*,controllerlist>::const_iterator sit; - for (sit = m_sensorcontrollermapje.begin();!(sit==m_sensorcontrollermapje.end());++sit) - { - controllerlist contlist = (*sit).second; - for (list<SCA_IController*>::const_iterator c= contlist.begin();!(c==contlist.end());c++) - { - (*c)->UnlinkActuator(actuator); - } - } + actuator->UnlinkAllControllers(); + actuator->Deactivate(); + actuator->SetActive(false); } void SCA_LogicManager::RegisterToSensor(SCA_IController* controller,SCA_ISensor* sensor) { - m_sensorcontrollermapje[sensor].push_back(controller); + sensor->LinkToController(controller); controller->LinkToSensor(sensor); } @@ -220,6 +179,7 @@ void SCA_LogicManager::RegisterToSensor(SCA_IController* controller,SCA_ISensor* void SCA_LogicManager::RegisterToActuator(SCA_IController* controller,SCA_IActuator* actua) { + actua->LinkToController(controller); controller->LinkToActuator(actua); } @@ -230,88 +190,62 @@ void SCA_LogicManager::BeginFrame(double curtime, double fixedtime) for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin(); !(ie==m_eventmanagers.end()); ie++) (*ie)->NextFrame(curtime, fixedtime); - // for this frame, look up for activated sensors, and build the collection of triggered controllers - // int numsensors = this->m_activatedsensors.size(); /*unused*/ - - for (vector<SCA_ISensor*>::const_iterator is=m_activatedsensors.begin(); - !(is==m_activatedsensors.end());is++) + for(SG_QList* obj = (SG_QList*)m_triggeredControllerSet.Remove(); + obj != NULL; + obj = (SG_QList*)m_triggeredControllerSet.Remove()) { - SCA_ISensor* sensor = *is; - controllerlist contlist = m_sensorcontrollermapje[sensor]; - for (list<SCA_IController*>::const_iterator c= contlist.begin(); - !(c==contlist.end());c++) + for(SCA_IController* contr = (SCA_IController*)obj->QRemove(); + contr != NULL; + contr = (SCA_IController*)obj->QRemove()) { - SCA_IController* contr = *c;//controllerarray->at(c); - if (contr->IsActive()) - { - m_triggeredControllerSet.insert(SmartControllerPtr(contr,0)); - // So that the controller knows which sensor has activited it. - // Only needed for the python controller though. - if (contr->GetType() == &SCA_PythonController::Type) - { - SCA_PythonController* pythonController = (SCA_PythonController*)contr; - pythonController->AddTriggeredSensor(sensor); - } - } + contr->Trigger(this); + contr->ClrJustActivated(); } - //sensor->SetActive(false); } - - - // int numtriggered = triggeredControllerSet.size(); /*unused*/ - for (set<SmartControllerPtr>::iterator tit=m_triggeredControllerSet.begin(); - !(tit==m_triggeredControllerSet.end());tit++) - { - (*tit)->Trigger(this); - } - m_triggeredControllerSet.clear(); } void SCA_LogicManager::UpdateFrame(double curtime, bool frame) { - vector<SmartActuatorPtr>::iterator ra; - for (ra = m_removedActuators.begin(); !(ra == m_removedActuators.end()); ra++) - { - m_activeActuators.erase(*ra); - (*ra)->SetActive(false); - } - m_removedActuators.clear(); - - // About to run actuators, but before update the sensors for those which depends on actuators for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin(); !(ie==m_eventmanagers.end()); ie++) (*ie)->UpdateFrame(); - for (set<SmartActuatorPtr>::iterator ia = m_activeActuators.begin();!(ia==m_activeActuators.end());ia++) + SG_DList::iterator<SG_QList> io(m_activeActuators); + for (io.begin(); !io.end(); ) { - //SCA_IActuator* actua = *ia; - if (!(*ia)->Update(curtime, frame)) + SG_QList* ahead = *io; + // increment now so that we can remove the current element + ++io; + SG_QList::iterator<SCA_IActuator> ia(*ahead); + for (ia.begin(); !ia.end(); ) { - //*ia = m_activeactuators.back(); - m_removedActuators.push_back(*ia); - - (*ia)->SetActive(false); - //m_activeactuators.pop_back(); - } else if ((*ia)->IsNoLink()) + SCA_IActuator* actua = *ia; + // increment first to allow removal of inactive actuators. + ++ia; + if (!actua->Update(curtime, frame)) + { + // this actuator is not active anymore, remove + actua->QDelink(); + actua->SetActive(false); + } else if (actua->IsNoLink()) + { + // This actuator has no more links but it still active + // make sure it will get a negative event on next frame to stop it + // Do this check after Update() rather than before to make sure + // that all the actuators that are activated at same time than a state + // actuator have a chance to execute. + bool event = false; + actua->RemoveAllEvents(); + actua->AddEvent(event); + } + } + if (ahead->QEmpty()) { - // This actuator has no more links but it still active - // make sure it will get a negative event on next frame to stop it - // Do this check after Update() rather than before to make sure - // that all the actuators that are activated at same time than a state - // actuator have a chance to execute. - CValue* event = new CBoolValue(false); - (*ia)->RemoveAllEvents(); - (*ia)->AddEvent(event); + // no more active controller, remove from main list + ahead->Delink(); } } - - for ( ra = m_removedActuators.begin(); !(ra == m_removedActuators.end()); ra++) - { - m_activeActuators.erase(*ra); - (*ra)->SetActive(false); - } - m_removedActuators.clear(); } @@ -360,41 +294,20 @@ void SCA_LogicManager::RegisterActionName(const STR_String& actname,void* action void SCA_LogicManager::EndFrame() { - for (vector<SCA_ISensor*>::const_iterator is=m_activatedsensors.begin(); - !(is==m_activatedsensors.end());is++) - { - SCA_ISensor* sensor = *is; - sensor->SetActive(false); - } - m_activatedsensors.clear(); - for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin(); !(ie==m_eventmanagers.end());ie++) { (*ie)->EndFrame(); } - - } - -void SCA_LogicManager::AddActivatedSensor(SCA_ISensor* sensor) -{ - // each frame, only add sensor once, and to avoid a seek, or bloated container - // hold a flag in each sensor, with the 'framenr' - if (!sensor->IsActive()) - { - sensor->SetActive(true); - m_activatedsensors.push_back(sensor); - } -} - void SCA_LogicManager::AddTriggeredController(SCA_IController* controller, SCA_ISensor* sensor) { - m_triggeredControllerSet.insert(SmartControllerPtr(controller,0)); + controller->Activate(m_triggeredControllerSet); // so that the controller knows which sensor has activited it // only needed for python controller + // Note that this is safe even if the controller is subclassed. if (controller->GetType() == &SCA_PythonController::Type) { SCA_PythonController* pythonController = (SCA_PythonController*)controller; @@ -402,19 +315,6 @@ void SCA_LogicManager::AddTriggeredController(SCA_IController* controller, SCA_I } } - -void SCA_LogicManager::AddActiveActuator(SCA_IActuator* actua,CValue* event) -{ - if (!actua->IsActive()) - { - actua->SetActive(true); - m_activeActuators.insert(SmartActuatorPtr(actua,0)); - } - actua->AddEvent(event->AddRef()); -} - - - SCA_EventManager* SCA_LogicManager::FindEventManager(int eventmgrtype) { // find an eventmanager of a certain type @@ -432,109 +332,3 @@ SCA_EventManager* SCA_LogicManager::FindEventManager(int eventmgrtype) } return eventmgr; } - - - -SmartActuatorPtr::SmartActuatorPtr(const SmartActuatorPtr& other) -{ - this->m_actuator = other.m_actuator; - this->m_actuator->AddRef(); -} - - - -SmartActuatorPtr::SmartActuatorPtr(SCA_IActuator* actua,int dummy) -: m_actuator(actua) -{ - actua->AddRef(); -} - - - -SmartActuatorPtr::~SmartActuatorPtr() -{ - m_actuator->Release(); -} - - - -bool SmartActuatorPtr::operator <(const SmartActuatorPtr& other) const -{ - - return m_actuator->LessComparedTo(*other); -} - - - -bool SmartActuatorPtr::operator ==(const SmartActuatorPtr& other) const -{ - bool result2 = other->LessComparedTo(m_actuator); - return (m_actuator->LessComparedTo(*other) && result2); -} - - - -SCA_IActuator* SmartActuatorPtr::operator->() const -{ - return m_actuator; -} - - - -SCA_IActuator* SmartActuatorPtr::operator*() const -{ - return m_actuator; -} - - - -SmartControllerPtr::SmartControllerPtr(const SmartControllerPtr& copy) -{ - this->m_controller = copy.m_controller; - this->m_controller->AddRef(); -} - - - -SmartControllerPtr::SmartControllerPtr(SCA_IController* contr,int dummy) -: m_controller(contr) -{ - m_controller->AddRef(); -} - - - -SmartControllerPtr::~SmartControllerPtr() -{ - m_controller->Release(); -} - - - -bool SmartControllerPtr::operator <(const SmartControllerPtr& other) const -{ - return m_controller->LessComparedTo(*other); -} - - - -bool SmartControllerPtr::operator ==(const SmartControllerPtr& other) const -{ - return (m_controller->LessComparedTo(*other) && other->LessComparedTo(m_controller)); -} - - - -SCA_IController* SmartControllerPtr::operator->() const -{ - return m_controller; -} - - - -SCA_IController* SmartControllerPtr::operator*() const -{ - return m_controller; -} - - diff --git a/source/gameengine/GameLogic/SCA_LogicManager.h b/source/gameengine/GameLogic/SCA_LogicManager.h index 50383879d8f..402090357cb 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.h +++ b/source/gameengine/GameLogic/SCA_LogicManager.h @@ -43,11 +43,13 @@ #include "GEN_Map.h" #include "STR_HashedString.h" #include "Value.h" +#include "SG_QList.h" #include "KX_HashedPtr.h" using namespace std; -typedef list<class SCA_IController*> controllerlist; +typedef std::list<class SCA_IController*> controllerlist; +typedef std::map<class SCA_ISensor*,controllerlist > sensormap_t; /** * This manager handles sensor, controllers and actuators. @@ -63,45 +65,19 @@ typedef list<class SCA_IController*> controllerlist; */ #include "SCA_ILogicBrick.h" +#include "SCA_IActuator.h" -// todo: make this into a template, but first I want to think about what exactly to put in -class SmartActuatorPtr -{ - SCA_IActuator* m_actuator; -public: - SmartActuatorPtr(SCA_IActuator* actua,int dummy); - SmartActuatorPtr(const SmartActuatorPtr& other); - virtual ~SmartActuatorPtr(); - bool operator <(const SmartActuatorPtr& other) const; - bool operator ==(const SmartActuatorPtr& other) const; - SCA_IActuator* operator->() const; - SCA_IActuator* operator*() const; - -}; - -class SmartControllerPtr -{ - SCA_IController* m_controller; -public: - SmartControllerPtr(const SmartControllerPtr& copy); - SmartControllerPtr(SCA_IController* contr,int dummy); - virtual ~SmartControllerPtr(); - bool operator <(const SmartControllerPtr& other) const; - bool operator ==(const SmartControllerPtr& other) const; - SCA_IController* operator->() const; - SCA_IController* operator*() const; - -}; class SCA_LogicManager { vector<class SCA_EventManager*> m_eventmanagers; - vector<class SCA_ISensor*> m_activatedsensors; - set<class SmartActuatorPtr> m_activeActuators; - set<class SmartControllerPtr> m_triggeredControllerSet; - - map<SCA_ISensor*,controllerlist > m_sensorcontrollermapje; + // SG_DList: Head of objects having activated actuators + // element: SCA_IObject::m_activeActuators + SG_DList m_activeActuators; + // SG_DList: Head of objects having activated controllers + // element: SCA_IObject::m_activeControllers + SG_DList m_triggeredControllerSet; // need to find better way for this // also known as FactoryManager... @@ -111,11 +87,10 @@ class SCA_LogicManager GEN_Map<STR_HashedString,void*> m_map_gamemeshname_to_blendobj; GEN_Map<CHashedPtr,void*> m_map_blendobj_to_gameobj; - - vector<SmartActuatorPtr> m_removedActuators; public: SCA_LogicManager(); virtual ~SCA_LogicManager(); + //void SetKeyboardManager(SCA_KeyboardManager* keyboardmgr) { m_keyboardmgr=keyboardmgr;} void RegisterEventManager(SCA_EventManager* eventmgr); void RegisterToSensor(SCA_IController* controller, @@ -126,8 +101,13 @@ public: void BeginFrame(double curtime, double fixedtime); void UpdateFrame(double curtime, bool frame); void EndFrame(); - void AddActivatedSensor(SCA_ISensor* sensor); - void AddActiveActuator(SCA_IActuator* sensor,class CValue* event); + void AddActiveActuator(SCA_IActuator* actua,bool event) + { + actua->SetActive(true); + actua->Activate(m_activeActuators); + actua->AddEvent(event); + } + void AddTriggeredController(SCA_IController* controller, SCA_ISensor* sensor); SCA_EventManager* FindEventManager(int eventmgrtype); @@ -138,7 +118,7 @@ public: */ void RemoveSensor(SCA_ISensor* sensor); void RemoveController(SCA_IController* controller); - void RemoveDestroyedActuator(SCA_IActuator* actuator); + void RemoveActuator(SCA_IActuator* actuator); // for the scripting... needs a FactoryManager later (if we would have time... ;) @@ -157,6 +137,13 @@ public: void RegisterGameObj(void* blendobj, CValue* gameobj); void UnregisterGameObj(void* blendobj, CValue* gameobj); CValue* FindGameObjByBlendObj(void* blendobj); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_LogicManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_LOGICMANAGER diff --git a/source/gameengine/GameLogic/SCA_MouseManager.cpp b/source/gameengine/GameLogic/SCA_MouseManager.cpp index ca875dad07c..d407647cec3 100644 --- a/source/gameengine/GameLogic/SCA_MouseManager.cpp +++ b/source/gameengine/GameLogic/SCA_MouseManager.cpp @@ -75,8 +75,8 @@ void SCA_MouseManager::NextFrame() { if (m_mousedevice) { - set<SCA_ISensor*>::iterator it; - for (it=m_sensors.begin(); it!=m_sensors.end(); it++) + SG_DList::iterator<SCA_ISensor> it(m_sensors); + for (it.begin();!it.end();++it) { SCA_MouseSensor* mousesensor = (SCA_MouseSensor*)(*it); // (0,0) is the Upper Left corner in our local window @@ -93,7 +93,7 @@ void SCA_MouseManager::NextFrame() mousesensor->setX(mx); mousesensor->setY(my); - mousesensor->Activate(m_logicmanager,NULL); + mousesensor->Activate(m_logicmanager); } } } diff --git a/source/gameengine/GameLogic/SCA_MouseManager.h b/source/gameengine/GameLogic/SCA_MouseManager.h index efa4c639ce7..ef1533c636b 100644 --- a/source/gameengine/GameLogic/SCA_MouseManager.h +++ b/source/gameengine/GameLogic/SCA_MouseManager.h @@ -63,6 +63,13 @@ public: bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode); virtual void NextFrame(); SCA_IInputDevice* GetInputDevice(); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_MouseManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_MOUSEMANAGER diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.cpp b/source/gameengine/GameLogic/SCA_MouseSensor.cpp index d4952ce4777..9d32682eaa9 100644 --- a/source/gameengine/GameLogic/SCA_MouseSensor.cpp +++ b/source/gameengine/GameLogic/SCA_MouseSensor.cpp @@ -25,7 +25,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): José I. Romero (cleanup and fixes) * * ***** END GPL LICENSE BLOCK ***** */ @@ -49,35 +49,15 @@ SCA_MouseSensor::SCA_MouseSensor(SCA_MouseManager* eventmgr, int startx,int starty, short int mousemode, - SCA_IObject* gameobj, - PyTypeObject* T) - : SCA_ISensor(gameobj,eventmgr, T), - m_pMouseMgr(eventmgr), + SCA_IObject* gameobj) + : SCA_ISensor(gameobj,eventmgr), m_x(startx), m_y(starty) { m_mousemode = mousemode; m_triggermode = true; - switch (m_mousemode) { - case KX_MOUSESENSORMODE_LEFTBUTTON: - m_hotkey = SCA_IInputDevice::KX_LEFTMOUSE; - break; - case KX_MOUSESENSORMODE_MIDDLEBUTTON: - m_hotkey = SCA_IInputDevice::KX_MIDDLEMOUSE; - break; - case KX_MOUSESENSORMODE_RIGHTBUTTON: - m_hotkey = SCA_IInputDevice::KX_RIGHTMOUSE; - break; - case KX_MOUSESENSORMODE_WHEELUP: - m_hotkey = SCA_IInputDevice::KX_WHEELUPMOUSE; - break; - case KX_MOUSESENSORMODE_WHEELDOWN: - m_hotkey = SCA_IInputDevice::KX_WHEELDOWNMOUSE; - break; - default: - ; /* ignore, no hotkey */ - } + UpdateHotkey(this, NULL); Init(); } @@ -92,13 +72,44 @@ SCA_MouseSensor::~SCA_MouseSensor() /* Nothing to be done here. */ } - +int SCA_MouseSensor::UpdateHotkey(void *self, const PyAttributeDef*) +{ + // gosh, this function is so damn stupid + // its here because of a design mistake in the mouse sensor, it should only + // have 3 trigger modes (button, wheel, move), and let the user set the + // hotkey separately, like the other sensors. but instead it has a mode for + // each friggin key and i have to update the hotkey based on it... genius! + SCA_MouseSensor* sensor = reinterpret_cast<SCA_MouseSensor*>(self); + + switch (sensor->m_mousemode) { + case KX_MOUSESENSORMODE_LEFTBUTTON: + sensor->m_hotkey = SCA_IInputDevice::KX_LEFTMOUSE; + break; + case KX_MOUSESENSORMODE_MIDDLEBUTTON: + sensor->m_hotkey = SCA_IInputDevice::KX_MIDDLEMOUSE; + break; + case KX_MOUSESENSORMODE_RIGHTBUTTON: + sensor->m_hotkey = SCA_IInputDevice::KX_RIGHTMOUSE; + break; + case KX_MOUSESENSORMODE_WHEELUP: + sensor->m_hotkey = SCA_IInputDevice::KX_WHEELUPMOUSE; + break; + case KX_MOUSESENSORMODE_WHEELDOWN: + sensor->m_hotkey = SCA_IInputDevice::KX_WHEELDOWNMOUSE; + break; + default: + ; /* ignore, no hotkey */ + } + // return value is used in py_setattro(), + // 0=attribute checked ok (see Attributes array definition) + return 0; +} CValue* SCA_MouseSensor::GetReplica() { SCA_MouseSensor* replica = new SCA_MouseSensor(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); replica->Init(); return replica; @@ -131,21 +142,12 @@ SCA_IInputDevice::KX_EnumInputs SCA_MouseSensor::GetHotKey() -bool SCA_MouseSensor::Evaluate(CValue* event) +bool SCA_MouseSensor::Evaluate() { bool result = false; bool reset = m_reset && m_level; - SCA_IInputDevice* mousedev = m_pMouseMgr->GetInputDevice(); + SCA_IInputDevice* mousedev = ((SCA_MouseManager *)m_eventmgr)->GetInputDevice(); - - -// SCA_ILogicBrick::RegisterEvent(event); -// if (m_mousemode == KX_MOUSESENSORMODE_MOVEMENT) cout << "\nChecking for movement..."; -//CValue* val = event->GetProperty("val"); - - /* both MOUSEX and MOUSEY. Treat all of these as key-presses. */ - /* So, treat KX_MOUSESENSORMODE_POSITION as */ - /* KX_MOUSESENSORMODE_POSITIONX || KX_MOUSESENSORMODE_POSITIONY */ m_reset = false; switch (m_mousemode) { case KX_MOUSESENSORMODE_LEFTBUTTON: @@ -154,43 +156,35 @@ bool SCA_MouseSensor::Evaluate(CValue* event) case KX_MOUSESENSORMODE_WHEELUP: case KX_MOUSESENSORMODE_WHEELDOWN: { - const SCA_InputEvent& event = mousedev->GetEventValue(m_hotkey); - if (event.m_status == SCA_InputEvent::KX_JUSTACTIVATED) - { + const SCA_InputEvent& mevent = mousedev->GetEventValue(m_hotkey); + switch (mevent.m_status){ + case SCA_InputEvent::KX_JUSTACTIVATED: m_val = 1; result = true; - } else - { - if (event.m_status == SCA_InputEvent::KX_JUSTRELEASED) + break; + case SCA_InputEvent::KX_JUSTRELEASED: + m_val = 0; + result = true; + break; + case SCA_InputEvent::KX_ACTIVE: + if (m_val == 0) + { + m_val = 1; + if (m_level) + result = true; + } + break; + default: + if (m_val == 1) { m_val = 0; result = true; - } else - { - if (event.m_status == SCA_InputEvent::KX_ACTIVE) - { - if (m_val == 0) - { - m_val = 1; - if (m_level) - { - result = true; - } - } - } else - { - if (m_val == 1) - { - m_val = 0; - result = true; - } - } } + break; } break; } case KX_MOUSESENSORMODE_MOVEMENT: - { const SCA_InputEvent& eventX = mousedev->GetEventValue(SCA_IInputDevice::KX_MOUSEX); const SCA_InputEvent& eventY = mousedev->GetEventValue(SCA_IInputDevice::KX_MOUSEY); @@ -198,27 +192,26 @@ bool SCA_MouseSensor::Evaluate(CValue* event) if (eventX.m_status == SCA_InputEvent::KX_JUSTACTIVATED || eventY.m_status == SCA_InputEvent::KX_JUSTACTIVATED || eventX.m_status == SCA_InputEvent::KX_ACTIVE || - eventY.m_status == SCA_InputEvent::KX_ACTIVE) - + eventY.m_status == SCA_InputEvent::KX_ACTIVE) { m_val = 1; result = true; - } else - { - if (eventX.m_status == SCA_InputEvent::KX_JUSTRELEASED || + } + else if (eventX.m_status == SCA_InputEvent::KX_JUSTRELEASED || eventY.m_status == SCA_InputEvent::KX_JUSTRELEASED ) + { + m_val = 0; + result = true; + } + else //KX_NO_IMPUTSTATUS + { + if (m_val == 1) { m_val = 0; result = true; - } else - { - if (m_val == 1) - { - m_val = 0; - result = true; - } } } + break; } default: @@ -243,77 +236,70 @@ void SCA_MouseSensor::setY(short y) bool SCA_MouseSensor::isValid(SCA_MouseSensor::KX_MOUSESENSORMODE m) { - bool res = false; + return ((m > KX_MOUSESENSORMODE_NODEF) && (m < KX_MOUSESENSORMODE_MAX)); +} + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ - res = ((m > KX_MOUSESENSORMODE_NODEF) && (m < KX_MOUSESENSORMODE_MAX)); +KX_PYMETHODDEF_DOC_O(SCA_MouseSensor, getButtonStatus, +"getButtonStatus(button)\n" +"\tGet the given button's status (KX_INPUT_NONE, KX_INPUT_NONE, KX_INPUT_JUST_ACTIVATED, KX_INPUT_ACTIVE, KX_INPUT_JUST_RELEASED).\n") +{ + if (PyLong_Check(value)) + { + int button = PyLong_AsSsize_t(value); + + if ((button < SCA_IInputDevice::KX_LEFTMOUSE) + || (button > SCA_IInputDevice::KX_RIGHTMOUSE)){ + PyErr_SetString(PyExc_ValueError, "sensor.getButtonStatus(int): Mouse Sensor, invalid button specified!"); + return NULL; + } + + SCA_IInputDevice* mousedev = ((SCA_MouseManager *)m_eventmgr)->GetInputDevice(); + const SCA_InputEvent& event = mousedev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) button); + return PyLong_FromSsize_t(event.m_status); + } - return res; + Py_RETURN_NONE; } /* ------------------------------------------------------------------------- */ -/* Python functions */ +/* Python Integration Hooks */ /* ------------------------------------------------------------------------- */ -/* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_MouseSensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_MouseSensor", - sizeof(SCA_MouseSensor), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_MouseSensor::Parents[] = { - &SCA_MouseSensor::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_MouseSensor::Methods[] = { - {"getXPosition", (PyCFunction) SCA_MouseSensor::sPyGetXPosition, METH_VARARGS, (PY_METHODCHAR)GetXPosition_doc}, - {"getYPosition", (PyCFunction) SCA_MouseSensor::sPyGetYPosition, METH_VARARGS, (PY_METHODCHAR)GetYPosition_doc}, + KX_PYMETHODTABLE_O(SCA_MouseSensor, getButtonStatus), {NULL,NULL} //Sentinel }; -PyObject* SCA_MouseSensor::_getattr(const STR_String& attr) { - _getattr_up(SCA_ISensor); -} - -/* get x position ---------------------------------------------------------- */ -const char SCA_MouseSensor::GetXPosition_doc[] = -"getXPosition\n" -"\tReturns the x-coordinate of the mouse sensor, in frame coordinates.\n" -"\tThe lower-left corner is the origin. The coordinate is given in\n" -"\tpixels\n"; -PyObject* SCA_MouseSensor::PyGetXPosition(PyObject* self, - PyObject* args, - PyObject* kwds) { - return PyInt_FromLong(m_x); -} - -/* get y position ---------------------------------------------------------- */ -const char SCA_MouseSensor::GetYPosition_doc[] = -"getYPosition\n" -"\tReturns the y-coordinate of the mouse sensor, in frame coordinates.\n" -"\tThe lower-left corner is the origin. The coordinate is given in\n" -"\tpixels\n"; -PyObject* SCA_MouseSensor::PyGetYPosition(PyObject* self, - PyObject* args, - PyObject* kwds) { - return PyInt_FromLong(m_y); -} +PyAttributeDef SCA_MouseSensor::Attributes[] = { + KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",KX_MOUSESENSORMODE_NODEF,KX_MOUSESENSORMODE_MAX-1,true,SCA_MouseSensor,m_mousemode,UpdateHotkey), + KX_PYATTRIBUTE_SHORT_LIST_RO("position",SCA_MouseSensor,m_x,2), + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.h b/source/gameengine/GameLogic/SCA_MouseSensor.h index 26a1c5e3fd2..a679e605428 100644 --- a/source/gameengine/GameLogic/SCA_MouseSensor.h +++ b/source/gameengine/GameLogic/SCA_MouseSensor.h @@ -24,7 +24,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): José I. Romero (cleanup and fixes) * * ***** END GPL LICENSE BLOCK ***** */ @@ -39,7 +39,6 @@ class SCA_MouseSensor : public SCA_ISensor { Py_Header; - class SCA_MouseManager* m_pMouseMgr; /** * Use SCA_IInputDevice values to encode the mouse mode for now. @@ -58,7 +57,7 @@ class SCA_MouseSensor : public SCA_ISensor SCA_IInputDevice::KX_EnumInputs m_hotkey; /** - * valid x coordinate + * valid x coordinate, MUST be followed by y coordinate */ short m_x; @@ -87,15 +86,16 @@ class SCA_MouseSensor : public SCA_ISensor bool isValid(KX_MOUSESENSORMODE); + static int UpdateHotkey(void *self, const PyAttributeDef*); + SCA_MouseSensor(class SCA_MouseManager* keybdmgr, int startx,int starty, short int mousemode, - SCA_IObject* gameobj, - PyTypeObject* T=&Type ); + SCA_IObject* gameobj); virtual ~SCA_MouseSensor(); virtual CValue* GetReplica(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual void Init(); virtual bool IsPositiveTrigger(); short int GetModeKey(); @@ -106,13 +106,9 @@ class SCA_MouseSensor : public SCA_ISensor /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - - /* read x-coordinate */ - KX_PYMETHOD_DOC(SCA_MouseSensor,GetXPosition); - /* read y-coordinate */ - KX_PYMETHOD_DOC(SCA_MouseSensor,GetYPosition); + + // get button status + KX_PYMETHOD_DOC_O(SCA_MouseSensor,getButtonStatus); }; diff --git a/source/gameengine/GameLogic/SCA_NANDController.cpp b/source/gameengine/GameLogic/SCA_NANDController.cpp index 5b869ee8298..c971c06fadd 100644 --- a/source/gameengine/GameLogic/SCA_NANDController.cpp +++ b/source/gameengine/GameLogic/SCA_NANDController.cpp @@ -42,10 +42,9 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_NANDController::SCA_NANDController(SCA_IObject* gameobj, - PyTypeObject* T) +SCA_NANDController::SCA_NANDController(SCA_IObject* gameobj) : - SCA_IController(gameobj,T) + SCA_IController(gameobj) { } @@ -66,26 +65,19 @@ void SCA_NANDController::Trigger(SCA_LogicManager* logicmgr) !(is==m_linkedsensors.end());is++) { SCA_ISensor* sensor = *is; - if (!sensor->IsPositiveTrigger()) + if (!sensor->GetState()) { sensorresult = true; break; } } - CValue* newevent = new CBoolValue(sensorresult); - for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin(); !(i==m_linkedactuators.end());i++) { - SCA_IActuator* actua = *i;//m_linkedactuators.at(i); - logicmgr->AddActiveActuator(actua,newevent); + SCA_IActuator* actua = *i; + logicmgr->AddActiveActuator(actua,sensorresult); } - - // every actuator that needs the event, has a it's own reference to it now so - // release it (so to be clear: if there is no actuator, it's deleted right now) - newevent->Release(); - } @@ -94,7 +86,7 @@ CValue* SCA_NANDController::GetReplica() { CValue* replica = new SCA_NANDController(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } @@ -107,38 +99,33 @@ CValue* SCA_NANDController::GetReplica() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_NANDController::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_NANDController", - sizeof(SCA_NANDController), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_NANDController::Parents[] = { - &SCA_NANDController::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IController::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_NANDController::Methods[] = { {NULL,NULL} //Sentinel }; -PyObject* SCA_NANDController::_getattr(const STR_String& attr) { - _getattr_up(SCA_IController); -} +PyAttributeDef SCA_NANDController::Attributes[] = { + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/GameLogic/SCA_NANDController.h b/source/gameengine/GameLogic/SCA_NANDController.h index 1193ff64f07..36a145e5f2b 100644 --- a/source/gameengine/GameLogic/SCA_NANDController.h +++ b/source/gameengine/GameLogic/SCA_NANDController.h @@ -39,7 +39,7 @@ class SCA_NANDController : public SCA_IController Py_Header; //virtual void Trigger(class SCA_LogicManager* logicmgr); public: - SCA_NANDController(SCA_IObject* gameobj,PyTypeObject* T=&Type); + SCA_NANDController(SCA_IObject* gameobj); virtual ~SCA_NANDController(); virtual CValue* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); @@ -47,9 +47,6 @@ public: /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - }; #endif //__KX_NANDCONTROLLER diff --git a/source/gameengine/GameLogic/SCA_NORController.cpp b/source/gameengine/GameLogic/SCA_NORController.cpp index 2866dec0b74..7a8b09e4bec 100644 --- a/source/gameengine/GameLogic/SCA_NORController.cpp +++ b/source/gameengine/GameLogic/SCA_NORController.cpp @@ -42,10 +42,9 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_NORController::SCA_NORController(SCA_IObject* gameobj, - PyTypeObject* T) +SCA_NORController::SCA_NORController(SCA_IObject* gameobj) : - SCA_IController(gameobj,T) + SCA_IController(gameobj) { } @@ -66,26 +65,19 @@ void SCA_NORController::Trigger(SCA_LogicManager* logicmgr) !(is==m_linkedsensors.end());is++) { SCA_ISensor* sensor = *is; - if (sensor->IsPositiveTrigger()) + if (sensor->GetState()) { sensorresult = false; break; } } - CValue* newevent = new CBoolValue(sensorresult); - for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin(); !(i==m_linkedactuators.end());i++) { - SCA_IActuator* actua = *i;//m_linkedactuators.at(i); - logicmgr->AddActiveActuator(actua,newevent); + SCA_IActuator* actua = *i; + logicmgr->AddActiveActuator(actua,sensorresult); } - - // every actuator that needs the event, has a it's own reference to it now so - // release it (so to be clear: if there is no actuator, it's deleted right now) - newevent->Release(); - } @@ -94,7 +86,7 @@ CValue* SCA_NORController::GetReplica() { CValue* replica = new SCA_NORController(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } @@ -107,38 +99,33 @@ CValue* SCA_NORController::GetReplica() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_NORController::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_NORController", - sizeof(SCA_NORController), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_NORController::Parents[] = { - &SCA_NORController::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IController::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_NORController::Methods[] = { {NULL,NULL} //Sentinel }; -PyObject* SCA_NORController::_getattr(const STR_String& attr) { - _getattr_up(SCA_IController); -} +PyAttributeDef SCA_NORController::Attributes[] = { + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/GameLogic/SCA_NORController.h b/source/gameengine/GameLogic/SCA_NORController.h index aab59e3d46c..b96232375d6 100644 --- a/source/gameengine/GameLogic/SCA_NORController.h +++ b/source/gameengine/GameLogic/SCA_NORController.h @@ -39,17 +39,10 @@ class SCA_NORController : public SCA_IController Py_Header; //virtual void Trigger(class SCA_LogicManager* logicmgr); public: - SCA_NORController(SCA_IObject* gameobj,PyTypeObject* T=&Type); + SCA_NORController(SCA_IObject* gameobj); virtual ~SCA_NORController(); virtual CValue* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); - - /* --------------------------------------------------------------------- */ - /* Python interface ---------------------------------------------------- */ - /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - }; #endif //__KX_NORCONTROLLER diff --git a/source/gameengine/GameLogic/SCA_ORController.cpp b/source/gameengine/GameLogic/SCA_ORController.cpp index 2d4eb31f241..12e2f610986 100644 --- a/source/gameengine/GameLogic/SCA_ORController.cpp +++ b/source/gameengine/GameLogic/SCA_ORController.cpp @@ -42,9 +42,8 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_ORController::SCA_ORController(SCA_IObject* gameobj, - PyTypeObject* T) - :SCA_IController(gameobj, T) +SCA_ORController::SCA_ORController(SCA_IObject* gameobj) + :SCA_IController(gameobj) { } @@ -60,7 +59,7 @@ CValue* SCA_ORController::GetReplica() { CValue* replica = new SCA_ORController(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } @@ -76,21 +75,16 @@ void SCA_ORController::Trigger(SCA_LogicManager* logicmgr) while ( (!sensorresult) && (!(is==m_linkedsensors.end())) ) { sensor = *is; - if (sensor->IsPositiveTrigger()) sensorresult = true; + if (sensor->GetState()) sensorresult = true; is++; } - CValue* newevent = new CBoolValue(sensorresult); - for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin(); !(i==m_linkedactuators.end());i++) { - SCA_IActuator* actua = *i;//m_linkedactuators.at(i); - logicmgr->AddActiveActuator(actua,newevent); + SCA_IActuator* actua = *i; + logicmgr->AddActiveActuator(actua,sensorresult); } - - - newevent->Release(); } /* ------------------------------------------------------------------------- */ @@ -99,38 +93,33 @@ void SCA_ORController::Trigger(SCA_LogicManager* logicmgr) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_ORController::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_ORController", - sizeof(SCA_ORController), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_ORController::Parents[] = { - &SCA_ORController::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IController::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_ORController::Methods[] = { {NULL,NULL} //Sentinel }; -PyObject* SCA_ORController::_getattr(const STR_String& attr) { - _getattr_up(SCA_IController); -} +PyAttributeDef SCA_ORController::Attributes[] = { + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/GameLogic/SCA_ORController.h b/source/gameengine/GameLogic/SCA_ORController.h index beb69aa2af9..09d31a85190 100644 --- a/source/gameengine/GameLogic/SCA_ORController.h +++ b/source/gameengine/GameLogic/SCA_ORController.h @@ -39,17 +39,11 @@ class SCA_ORController : public SCA_IController Py_Header; //virtual void Trigger(class SCA_LogicManager* logicmgr); public: - SCA_ORController(SCA_IObject* gameobj, PyTypeObject* T=&Type); + SCA_ORController(SCA_IObject* gameobj); virtual ~SCA_ORController(); virtual CValue* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); - - /* --------------------------------------------------------------------- */ - /* Python interface ---------------------------------------------------- */ - /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); }; #endif //__KX_ORCONTROLLER diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp index 3b541e87f02..9446487cdb7 100644 --- a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp +++ b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp @@ -42,8 +42,8 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_PropertyActuator::SCA_PropertyActuator(SCA_IObject* gameobj,SCA_IObject* sourceObj,const STR_String& propname,const STR_String& expr,int acttype,PyTypeObject* T ) - : SCA_IActuator(gameobj,T), +SCA_PropertyActuator::SCA_PropertyActuator(SCA_IObject* gameobj,SCA_IObject* sourceObj,const STR_String& propname,const STR_String& expr,int acttype) + : SCA_IActuator(gameobj), m_type(acttype), m_propname(propname), m_exprtxt(expr), @@ -77,11 +77,25 @@ bool SCA_PropertyActuator::Update() CParser parser; parser.SetContext( propowner->AddRef()); - CExpression* userexpr = parser.ProcessText(m_exprtxt); - if (userexpr) + CExpression* userexpr= NULL; + + if (m_type==KX_ACT_PROP_TOGGLE) { - - + /* dont use */ + CValue* newval; + CValue* oldprop = propowner->GetProperty(m_propname); + if (oldprop) + { + newval = new CBoolValue((oldprop->GetNumber()==0.0) ? true:false); + oldprop->SetValue(newval); + } else + { /* as not been assigned, evaluate as false, so assign true */ + newval = new CBoolValue(true); + propowner->SetProperty(m_propname,newval); + } + newval->Release(); + } + else if ((userexpr = parser.ProcessText(m_exprtxt))) { switch (m_type) { @@ -135,6 +149,7 @@ bool SCA_PropertyActuator::Update() } break; } + /* case KX_ACT_PROP_TOGGLE: */ /* accounted for above, no need for userexpr */ default: { @@ -171,11 +186,6 @@ GetReplica() { SCA_PropertyActuator* replica = new SCA_PropertyActuator(*this); replica->ProcessReplica(); - - // this will copy properties and so on... - - CValue::AddDataToReplica(replica); - return replica; }; @@ -218,105 +228,36 @@ void SCA_PropertyActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_PropertyActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_PropertyActuator", - sizeof(SCA_PropertyActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_PropertyActuator::Parents[] = { - &SCA_PropertyActuator::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_PropertyActuator::Methods[] = { - {"setProperty", (PyCFunction) SCA_PropertyActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, - {"getProperty", (PyCFunction) SCA_PropertyActuator::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, - {"setValue", (PyCFunction) SCA_PropertyActuator::sPySetValue, METH_VARARGS, (PY_METHODCHAR)SetValue_doc}, - {"getValue", (PyCFunction) SCA_PropertyActuator::sPyGetValue, METH_VARARGS, (PY_METHODCHAR)GetValue_doc}, {NULL,NULL} //Sentinel }; -PyObject* SCA_PropertyActuator::_getattr(const STR_String& attr) { - _getattr_up(SCA_IActuator); -} - -/* 1. setProperty */ -const char SCA_PropertyActuator::SetProperty_doc[] = -"setProperty(name)\n" -"\t- name: string\n" -"\tSet the property on which to operate. If there is no property\n" -"\tof this name, the call is ignored.\n"; -PyObject* SCA_PropertyActuator::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds) -{ - /* Check whether the name exists first ! */ - char *nameArg; - if (!PyArg_ParseTuple(args, "s", &nameArg)) { - return NULL; - } - - CValue* prop = GetParent()->FindIdentifier(nameArg); - - if (!prop->IsError()) { - m_propname = nameArg; - } else { - ; /* not found ... */ - } - prop->Release(); - - Py_Return; -} - -/* 2. getProperty */ -const char SCA_PropertyActuator::GetProperty_doc[] = -"getProperty(name)\n" -"\tReturn the property on which the actuator operates.\n"; -PyObject* SCA_PropertyActuator::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) -{ - return PyString_FromString(m_propname); -} - -/* 3. setValue */ -const char SCA_PropertyActuator::SetValue_doc[] = -"setValue(value)\n" -"\t- value: string\n" -"\tSet the value with which the actuator operates. If the value\n" -"\tis not compatible with the type of the property, the subsequent\n" -"\t action is ignored.\n"; -PyObject* SCA_PropertyActuator::PySetValue(PyObject* self, PyObject* args, PyObject* kwds) -{ - char *valArg; - if(!PyArg_ParseTuple(args, "s", &valArg)) { - return NULL; - } - - if (valArg) m_exprtxt = valArg; - - Py_Return; -} - -/* 4. getValue */ -const char SCA_PropertyActuator::GetValue_doc[] = -"getValue()\n" -"\tReturns the value with which the actuator operates.\n"; -PyObject* SCA_PropertyActuator::PyGetValue(PyObject* self, PyObject* args, PyObject* kwds) -{ - return PyString_FromString(m_exprtxt); -} +PyAttributeDef SCA_PropertyActuator::Attributes[] = { + KX_PYATTRIBUTE_STRING_RW_CHECK("propName",0,100,false,SCA_PropertyActuator,m_propname,CheckProperty), + KX_PYATTRIBUTE_STRING_RW("value",0,100,false,SCA_PropertyActuator,m_exprtxt), + KX_PYATTRIBUTE_INT_RW("mode", KX_ACT_PROP_NODEF+1, KX_ACT_PROP_MAX-1, false, SCA_PropertyActuator, m_type), /* ATTR_TODO add constents to game logic dict */ + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.h b/source/gameengine/GameLogic/SCA_PropertyActuator.h index 1e435684572..833547a5cd3 100644 --- a/source/gameengine/GameLogic/SCA_PropertyActuator.h +++ b/source/gameengine/GameLogic/SCA_PropertyActuator.h @@ -43,6 +43,7 @@ class SCA_PropertyActuator : public SCA_IActuator KX_ACT_PROP_ASSIGN, KX_ACT_PROP_ADD, KX_ACT_PROP_COPY, + KX_ACT_PROP_TOGGLE, KX_ACT_PROP_MAX }; @@ -63,9 +64,7 @@ public: SCA_IObject* sourceObj, const STR_String& propname, const STR_String& expr, - int acttype, - PyTypeObject* T=&Type - ); + int acttype); ~SCA_PropertyActuator(); @@ -84,16 +83,6 @@ public: /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - - // python wrapped methods - KX_PYMETHOD_DOC(SCA_PropertyActuator,SetProperty); - KX_PYMETHOD_DOC(SCA_PropertyActuator,GetProperty); - KX_PYMETHOD_DOC(SCA_PropertyActuator,SetValue); - KX_PYMETHOD_DOC(SCA_PropertyActuator,GetValue); - - /* 5. - ... setObject, getObject, setProp2, getProp2, setMode, getMode*/ }; diff --git a/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp b/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp index e5e3f9cced5..764465309df 100644 --- a/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp @@ -50,8 +50,9 @@ SCA_PropertyEventManager::~SCA_PropertyEventManager() void SCA_PropertyEventManager::NextFrame() { // check for changed properties - for (set<SCA_ISensor*>::const_iterator it = m_sensors.begin();!(it==m_sensors.end());it++) + SG_DList::iterator<SCA_ISensor> it(m_sensors); + for (it.begin();!it.end();++it) { - (*it)->Activate(m_logicmgr,NULL); + (*it)->Activate(m_logicmgr); } } diff --git a/source/gameengine/GameLogic/SCA_PropertyEventManager.h b/source/gameengine/GameLogic/SCA_PropertyEventManager.h index f166065b198..a9692377df8 100644 --- a/source/gameengine/GameLogic/SCA_PropertyEventManager.h +++ b/source/gameengine/GameLogic/SCA_PropertyEventManager.h @@ -44,6 +44,13 @@ public: virtual ~SCA_PropertyEventManager(); virtual void NextFrame(); //SCA_LogicManager* GetLogicManager() { return m_logicmgr;} + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_PropertyEventManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_PROPERTYEVENTMANAGER diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp index 64e3d49c6cb..9c09c8410fb 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp +++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp @@ -37,6 +37,7 @@ #include "StringValue.h" #include "SCA_EventManager.h" #include "SCA_LogicManager.h" +#include "BoolValue.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -47,9 +48,8 @@ SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr, const STR_String& propname, const STR_String& propval, const STR_String& propmaxval, - KX_PROPSENSOR_TYPE checktype, - PyTypeObject* T ) - : SCA_ISensor(gameobj,eventmgr,T), + KX_PROPSENSOR_TYPE checktype) + : SCA_ISensor(gameobj,eventmgr), m_checktype(checktype), m_checkpropval(propval), m_checkpropmaxval(propmaxval), @@ -111,7 +111,7 @@ CValue* SCA_PropertySensor::GetReplica() { SCA_PropertySensor* replica = new SCA_PropertySensor(*this); // m_range_expr must be recalculated on replica! - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); replica->Init(); replica->m_range_expr = NULL; @@ -152,7 +152,7 @@ SCA_PropertySensor::~SCA_PropertySensor() -bool SCA_PropertySensor::Evaluate(CValue* event) +bool SCA_PropertySensor::Evaluate() { bool result = CheckPropertyCondition(); bool reset = m_reset && m_level; @@ -182,17 +182,14 @@ bool SCA_PropertySensor::CheckPropertyCondition() CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { - STR_String testprop = orgprop->GetText(); + const STR_String& testprop = orgprop->GetText(); // Force strings to upper case, to avoid confusion in // bool tests. It's stupid the prop's identity is lost // on the way here... - if ((testprop == "TRUE") || (testprop == "FALSE")) { - STR_String checkprop = m_checkpropval; - checkprop.Upper(); - result = (testprop == checkprop); - } else { - result = (orgprop->GetText() == m_checkpropval); + if ((&testprop == &CBoolValue::sTrueString) || (&testprop == &CBoolValue::sFalseString)) { + m_checkpropval.Upper(); } + result = (testprop == m_checkpropval); } orgprop->Release(); @@ -232,8 +229,8 @@ bool SCA_PropertySensor::CheckPropertyCondition() CValue* vallie = m_range_expr->Calculate(); if (vallie) { - STR_String errtext = vallie->GetText(); - if (errtext == "TRUE") + const STR_String& errtext = vallie->GetText(); + if (&errtext == &CBoolValue::sTrueString) { result = true; } else @@ -293,11 +290,10 @@ CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername) return GetParent()->FindIdentifier(identifiername); } -bool SCA_PropertySensor::validValueForProperty(char *val, STR_String &prop) +int SCA_PropertySensor::validValueForProperty(void *self, const PyAttributeDef*) { - bool result = true; /* There is no type checking at this moment, unfortunately... */ - return result; + return 0; } /* ------------------------------------------------------------------------- */ @@ -306,144 +302,36 @@ bool SCA_PropertySensor::validValueForProperty(char *val, STR_String &prop) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_PropertySensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_PropertySensor", - sizeof(SCA_PropertySensor), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_PropertySensor::Parents[] = { - &SCA_PropertySensor::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_PropertySensor::Methods[] = { - {"getType", (PyCFunction) SCA_PropertySensor::sPyGetType, METH_VARARGS, (PY_METHODCHAR)GetType_doc}, - {"setType", (PyCFunction) SCA_PropertySensor::sPySetType, METH_VARARGS, (PY_METHODCHAR)SetType_doc}, - {"getProperty", (PyCFunction) SCA_PropertySensor::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, - {"setProperty", (PyCFunction) SCA_PropertySensor::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, - {"getValue", (PyCFunction) SCA_PropertySensor::sPyGetValue, METH_VARARGS, (PY_METHODCHAR)GetValue_doc}, - {"setValue", (PyCFunction) SCA_PropertySensor::sPySetValue, METH_VARARGS, (PY_METHODCHAR)SetValue_doc}, {NULL,NULL} //Sentinel }; -PyObject* SCA_PropertySensor::_getattr(const STR_String& attr) { - _getattr_up(SCA_ISensor); /* implicit return! */ -} - -/* 1. getType */ -const char SCA_PropertySensor::GetType_doc[] = -"getType()\n" -"\tReturns the type of check this sensor performs.\n"; -PyObject* SCA_PropertySensor::PyGetType(PyObject* self, PyObject* args, PyObject* kwds) -{ - return PyInt_FromLong(m_checktype); -} - -/* 2. setType */ -const char SCA_PropertySensor::SetType_doc[] = -"setType(type)\n" -"\t- type: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL,\n" -"\t KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED,\n" -"\t or KX_PROPSENSOR_EXPRESSION.\n" -"\tSet the type of check to perform.\n"; -PyObject* SCA_PropertySensor::PySetType(PyObject* self, PyObject* args, PyObject* kwds) -{ - int typeArg; - - if (!PyArg_ParseTuple(args, "i", &typeArg)) { - return NULL; - } - - if ( (typeArg > KX_PROPSENSOR_NODEF) - && (typeArg < KX_PROPSENSOR_MAX) ) { - m_checktype = typeArg; - } - - Py_Return; -} - -/* 3. getProperty */ -const char SCA_PropertySensor::GetProperty_doc[] = -"getProperty()\n" -"\tReturn the property with which the sensor operates.\n"; -PyObject* SCA_PropertySensor::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) -{ - return PyString_FromString(m_checkpropname); -} - -/* 4. setProperty */ -const char SCA_PropertySensor::SetProperty_doc[] = -"setProperty(name)\n" -"\t- name: string\n" -"\tSets the property with which to operate. If there is no property\n" -"\tof this name, the call is ignored.\n"; -PyObject* SCA_PropertySensor::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds) -{ - /* We should query whether the name exists. Or should we create a prop */ - /* on the fly? */ - char *propNameArg = NULL; - - if (!PyArg_ParseTuple(args, "s", &propNameArg)) { - return NULL; - } - - CValue *prop = FindIdentifier(STR_String(propNameArg)); - if (!prop->IsError()) { - m_checkpropname = propNameArg; - } else { - ; /* error: bad property name */ - } - prop->Release(); - Py_Return; -} - -/* 5. getValue */ -const char SCA_PropertySensor::GetValue_doc[] = -"getValue()\n" -"\tReturns the value with which the sensor operates.\n"; -PyObject* SCA_PropertySensor::PyGetValue(PyObject* self, PyObject* args, PyObject* kwds) -{ - return PyString_FromString(m_checkpropval); -} - -/* 6. setValue */ -const char SCA_PropertySensor::SetValue_doc[] = -"setValue(value)\n" -"\t- value: string\n" -"\tSet the value with which the sensor operates. If the value\n" -"\tis not compatible with the type of the property, the subsequent\n" -"\t action is ignored.\n"; -PyObject* SCA_PropertySensor::PySetValue(PyObject* self, PyObject* args, PyObject* kwds) -{ - /* Here, we need to check whether the value is 'valid' for this property.*/ - /* We know that the property exists, or is NULL. */ - char *propValArg = NULL; - - if(!PyArg_ParseTuple(args, "s", &propValArg)) { - return NULL; - } - - if (validValueForProperty(propValArg, m_checkpropname)) { - m_checkpropval = propValArg; - } - - Py_Return; -} +PyAttributeDef SCA_PropertySensor::Attributes[] = { + KX_PYATTRIBUTE_INT_RW("mode",KX_PROPSENSOR_NODEF,KX_PROPSENSOR_MAX-1,false,SCA_PropertySensor,m_checktype), + KX_PYATTRIBUTE_STRING_RW_CHECK("propName",0,100,false,SCA_PropertySensor,m_checkpropname,CheckProperty), + KX_PYATTRIBUTE_STRING_RW_CHECK("value",0,100,false,SCA_PropertySensor,m_checkpropval,validValueForProperty), + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.h b/source/gameengine/GameLogic/SCA_PropertySensor.h index 6871cb3afdc..a5bbfc8438b 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.h +++ b/source/gameengine/GameLogic/SCA_PropertySensor.h @@ -47,10 +47,6 @@ class SCA_PropertySensor : public SCA_ISensor bool m_recentresult; CExpression* m_range_expr; - /** - * Test whether this is a sensible value (type check) - */ - bool validValueForProperty(char *val, STR_String &prop); protected: public: @@ -71,9 +67,12 @@ public: const STR_String& propname, const STR_String& propval, const STR_String& propmaxval, - KX_PROPSENSOR_TYPE checktype, - PyTypeObject* T=&Type ); + KX_PROPSENSOR_TYPE checktype); + /** + * For property sensor, it is used to release the pre-calculated expression + * so that self references are removed before the sensor itself is released + */ virtual void Delete(); virtual ~SCA_PropertySensor(); virtual CValue* GetReplica(); @@ -81,7 +80,7 @@ public: void PrecalculateRangeExpression(); bool CheckPropertyCondition(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual CValue* FindIdentifier(const STR_String& identifiername); @@ -89,21 +88,10 @@ public: /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); - - /* 1. getType */ - KX_PYMETHOD_DOC(SCA_PropertySensor,GetType); - /* 2. setType */ - KX_PYMETHOD_DOC(SCA_PropertySensor,SetType); - /* 3. setProperty */ - KX_PYMETHOD_DOC(SCA_PropertySensor,SetProperty); - /* 4. getProperty */ - KX_PYMETHOD_DOC(SCA_PropertySensor,GetProperty); - /* 5. getValue */ - KX_PYMETHOD_DOC(SCA_PropertySensor,GetValue); - /* 6. setValue */ - KX_PYMETHOD_DOC(SCA_PropertySensor,SetValue); - + /** + * Test whether this is a sensible value (type check) + */ + static int validValueForProperty(void* self, const PyAttributeDef*); }; #endif diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp index c354ab39747..ecaa8c508db 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.cpp +++ b/source/gameengine/GameLogic/SCA_PythonController.cpp @@ -47,13 +47,17 @@ SCA_PythonController* SCA_PythonController::m_sCurrentController = NULL; -SCA_PythonController::SCA_PythonController(SCA_IObject* gameobj, - PyTypeObject* T) - : SCA_IController(gameobj, T), +SCA_PythonController::SCA_PythonController(SCA_IObject* gameobj, int mode) + : SCA_IController(gameobj), m_bytecode(NULL), + m_function(NULL), + m_function_argc(0), m_bModified(true), + m_debug(false), + m_mode(mode), m_pythondictionary(NULL) { + } /* @@ -74,15 +78,12 @@ int SCA_PythonController::Release() SCA_PythonController::~SCA_PythonController() { - if (m_bytecode) - { - // - //printf("released python byte script\n"); - Py_DECREF(m_bytecode); - } + //printf("released python byte script\n"); - if (m_pythondictionary) - { + Py_XDECREF(m_bytecode); + Py_XDECREF(m_function); + + if (m_pythondictionary) { // break any circular references in the dictionary PyDict_Clear(m_pythondictionary); Py_DECREF(m_pythondictionary); @@ -94,8 +95,12 @@ SCA_PythonController::~SCA_PythonController() CValue* SCA_PythonController::GetReplica() { SCA_PythonController* replica = new SCA_PythonController(*this); - // Copy the compiled bytecode if possible. + + /* why is this needed at all??? - m_bytecode is NULL'd below so this doesnt make sense + * but removing it crashes blender (with YoFrankie). so leave in for now - Campbell */ Py_XINCREF(replica->m_bytecode); + + Py_XINCREF(replica->m_function); // this is ok since its not set to NULL replica->m_bModified = replica->m_bytecode == NULL; // The replica->m_pythondictionary is stolen - replace with a copy. @@ -110,7 +115,7 @@ CValue* SCA_PythonController::GetReplica() */ // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } @@ -140,6 +145,11 @@ void SCA_PythonController::SetDictionary(PyObject* pythondictionary) Py_DECREF(m_pythondictionary); } m_pythondictionary = PyDict_Copy(pythondictionary); /* new reference */ + + /* Without __file__ set the sys.argv[0] is used for the filename + * which ends up with lines from the blender binary being printed in the console */ + PyDict_SetItemString(m_pythondictionary, "__file__", PyUnicode_FromString(m_scriptName.Ptr())); + } int SCA_PythonController::IsTriggered(class SCA_ISensor* sensor) @@ -150,131 +160,223 @@ int SCA_PythonController::IsTriggered(class SCA_ISensor* sensor) return 0; } -#if 0 -static const char* sPyGetCurrentController__doc__; -#endif - - -PyObject* SCA_PythonController::sPyGetCurrentController(PyObject* self) +/* warning, self is not the SCA_PythonController, its a PyObjectPlus_Proxy */ +PyObject* SCA_PythonController::sPyGetCurrentController(PyObject *self) { - m_sCurrentController->AddRef(); - return m_sCurrentController; + if(m_sCurrentController==NULL) + { + PyErr_SetString(PyExc_SystemError, "GameLogic.getCurrentController(), this function is being run outside the python controllers context, or blenders internal state is corrupt."); + return NULL; + } + return m_sCurrentController->GetProxy(); } -#if 0 -static const char* sPyAddActiveActuator__doc__; -#endif - -PyObject* SCA_PythonController::sPyAddActiveActuator( - - PyObject* self, - PyObject* args) +SCA_IActuator* SCA_PythonController::LinkedActuatorFromPy(PyObject *value) { - - PyObject* ob1; - int activate; - if (!PyArg_ParseTuple(args, "Oi", &ob1,&activate)) - return NULL; - // for safety, todo: only allow for registered actuators (pointertable) // we don't want to crash gameengine/blender by python scripts std::vector<SCA_IActuator*> lacts = m_sCurrentController->GetLinkedActuators(); - std::vector<SCA_IActuator*>::iterator it; - bool found = false; - CValue* act = (CValue*)ob1; - - for(it = lacts.begin(); it!= lacts.end(); it++) { - if( static_cast<SCA_IActuator*>(act) == (*it) ) { - found=true; - break; + + if (PyUnicode_Check(value)) { + /* get the actuator from the name */ + char *name= _PyUnicode_AsString(value); + for(it = lacts.begin(); it!= lacts.end(); ++it) { + if( name == (*it)->GetName() ) { + return *it; + } } } - if(found){ - CValue* boolval = new CBoolValue(activate!=0); - m_sCurrentLogicManager->AddActiveActuator((SCA_IActuator*)act,boolval); - boolval->Release(); + else if (PyObject_TypeCheck(value, &SCA_IActuator::Type)) { + PyObjectPlus *value_plus= BGE_PROXY_REF(value); + for(it = lacts.begin(); it!= lacts.end(); ++it) { + if( static_cast<SCA_IActuator*>(value_plus) == (*it) ) { + return *it; + } + } } - Py_RETURN_NONE; + + /* set the exception */ + PyObject *value_str = PyObject_Repr(value); /* new ref */ + PyErr_Format(PyExc_ValueError, "'%s' not in this python controllers actuator list", _PyUnicode_AsString(value_str)); + Py_DECREF(value_str); + + return false; } - const char* SCA_PythonController::sPyGetCurrentController__doc__ = "getCurrentController()"; -const char* SCA_PythonController::sPyAddActiveActuator__doc__= "addActiveActuator(actuator,bool)"; -const char SCA_PythonController::GetActuators_doc[] = "getActuator"; PyTypeObject SCA_PythonController::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "SCA_PythonController", - sizeof(SCA_PythonController), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 -}; - -PyParentObject SCA_PythonController::Parents[] = { - &SCA_PythonController::Type, + PyVarObject_HEAD_INIT(NULL, 0) + "SCA_PythonController", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IController::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; + PyMethodDef SCA_PythonController::Methods[] = { - {"getActuators", (PyCFunction) SCA_PythonController::sPyGetActuators, METH_NOARGS, (PY_METHODCHAR)SCA_PythonController::GetActuators_doc}, - {"getActuator", (PyCFunction) SCA_PythonController::sPyGetActuator, METH_O, (PY_METHODCHAR)SCA_PythonController::GetActuator_doc}, - {"getSensors", (PyCFunction) SCA_PythonController::sPyGetSensors, METH_NOARGS, (PY_METHODCHAR)SCA_PythonController::GetSensors_doc}, - {"getSensor", (PyCFunction) SCA_PythonController::sPyGetSensor, METH_O, (PY_METHODCHAR)SCA_PythonController::GetSensor_doc}, - {"getScript", (PyCFunction) SCA_PythonController::sPyGetScript, METH_NOARGS}, - {"setScript", (PyCFunction) SCA_PythonController::sPySetScript, METH_O}, - {"getState", (PyCFunction) SCA_PythonController::sPyGetState, METH_NOARGS}, + {"activate", (PyCFunction) SCA_PythonController::sPyActivate, METH_O}, + {"deactivate", (PyCFunction) SCA_PythonController::sPyDeActivate, METH_O}, {NULL,NULL} //Sentinel }; +PyAttributeDef SCA_PythonController::Attributes[] = { + KX_PYATTRIBUTE_RW_FUNCTION("script", SCA_PythonController, pyattr_get_script, pyattr_set_script), + KX_PYATTRIBUTE_INT_RO("mode", SCA_PythonController, m_mode), + { NULL } //Sentinel +}; + +void SCA_PythonController::ErrorPrint(const char *error_msg) +{ + // didn't compile, so instead of compile, complain + // something is wrong, tell the user what went wrong + printf("%s - controller \"%s\":\n", error_msg, GetName().Ptr()); + //PyRun_SimpleString(m_scriptText.Ptr()); + PyErr_Print(); + + /* Added in 2.48a, the last_traceback can reference Objects for example, increasing + * their user count. Not to mention holding references to wrapped data. + * This is especially bad when the PyObject for the wrapped data is free'd, after blender + * has alredy dealocated the pointer */ + PySys_SetObject( (char *)"last_traceback", NULL); + PyErr_Clear(); /* just to be sure */ +} + +bool SCA_PythonController::Compile() +{ + //printf("py script modified '%s'\n", m_scriptName.Ptr()); + m_bModified= false; + + // if a script already exists, decref it before replace the pointer to a new script + if (m_bytecode) { + Py_DECREF(m_bytecode); + m_bytecode=NULL; + } + + // recompile the scripttext into bytecode + m_bytecode = Py_CompileString(m_scriptText.Ptr(), m_scriptName.Ptr(), Py_file_input); + + if (m_bytecode) { + return true; + } else { + ErrorPrint("Python error compiling script"); + return false; + } +} + +bool SCA_PythonController::Import() +{ + //printf("py module modified '%s'\n", m_scriptName.Ptr()); + m_bModified= false; + + /* incase we re-import */ + Py_XDECREF(m_function); + m_function= NULL; + + vector<STR_String> py_function_path = m_scriptText.Explode('.'); + + if(py_function_path.size() < 2) { + printf("Python module name formatting error \"%s\":\n\texpected \"SomeModule.Func\", got \"%s\"\n", GetName().Ptr(), m_scriptText.Ptr()); + return false; + } + + PyObject *mod = PyImport_ImportModule((char *)py_function_path[0].Ptr()); + /* Dont reload yet, do this within the loop so packages reload too */ + + if(mod==NULL) { + ErrorPrint("Python module not found"); + return false; + } + /* 'mod' will be DECREF'd as 'base' + * 'm_function' will be left holding a reference that the controller owns */ + + PyObject *base= mod; + + for(unsigned int i=1; i < py_function_path.size(); i++) { + if(m_debug && PyModule_Check(base)) { /* base could be a class */ + Py_DECREF(base); /* getting a new one so dont hold a ref to the old one */ + base= PyImport_ReloadModule(base); + if (base==NULL) { + m_function= NULL; + break; + } + } + + m_function = PyObject_GetAttrString(base, py_function_path[i].Ptr()); + Py_DECREF(base); + base = m_function; /* for the next loop if there is on */ + + if(m_function==NULL) { + break; + } + } + + if(m_function==NULL) { + if(PyErr_Occurred()) + ErrorPrint("Python controller found the module but could not access the function"); + else + printf("Python module error \"%s\":\n \"%s\" module found but function missing\n", GetName().Ptr(), m_scriptText.Ptr()); + return false; + } + + if(!PyCallable_Check(m_function)) { + Py_DECREF(m_function); + printf("Python module function error \"%s\":\n \"%s\" not callable\n", GetName().Ptr(), m_scriptText.Ptr()); + return false; + } + + m_function_argc = 0; /* rare cases this could be a function that isnt defined in python, assume zero args */ + if (PyFunction_Check(m_function)) { + PyObject *py_arg_count = PyObject_GetAttrString(PyFunction_GET_CODE(m_function), "co_argcount"); + if(py_arg_count) { + m_function_argc = PyLong_AsLong(py_arg_count); + Py_DECREF(py_arg_count); + } + else { + PyErr_Clear(); /* unlikely to fail but just incase */ + } + } + + if(m_function_argc > 1) { + Py_DECREF(m_function); + printf("Python module function has \"%s\":\n \"%s\" takes %d args, should be zero or 1 controller arg\n", GetName().Ptr(), m_scriptText.Ptr(), m_function_argc); + return false; + } + + return true; +} void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) { m_sCurrentController = this; m_sCurrentLogicManager = logicmgr; - if (m_bModified) + PyObject *excdict= NULL; + PyObject* resultobj= NULL; + + switch(m_mode) { + case SCA_PYEXEC_SCRIPT: { - // if a script already exists, decref it before replace the pointer to a new script - if (m_bytecode) - { - Py_DECREF(m_bytecode); - m_bytecode=NULL; - } - // recompile the scripttext into bytecode - m_bytecode = Py_CompileString(m_scriptText.Ptr(), m_scriptName.Ptr(), Py_file_input); + if (m_bModified) + if (Compile()==false) // sets m_bModified to false + return; if (!m_bytecode) - { - // didn't compile, so instead of compile, complain - // something is wrong, tell the user what went wrong - printf("Python compile error from controller \"%s\": \n", GetName().Ptr()); - //PyRun_SimpleString(m_scriptText.Ptr()); - PyErr_Print(); - - /* Added in 2.48a, the last_traceback can reference Objects for example, increasing - * their user count. Not to mention holding references to wrapped data. - * This is especially bad when the PyObject for the wrapped data is free'd, after blender - * has alredy dealocated the pointer */ - PySys_SetObject( "last_traceback", Py_None); - PyErr_Clear(); /* just to be sure */ - return; - } - m_bModified=false; - } - + /* * This part here with excdict is a temporary patch * to avoid python/gameengine crashes when python @@ -293,10 +395,36 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) * should always ensure excdict is cleared). */ - PyObject *excdict= PyDict_Copy(m_pythondictionary); - PyObject* resultobj = PyEval_EvalCode((PyCodeObject*)m_bytecode, - excdict, excdict); - + excdict= PyDict_Copy(m_pythondictionary); + resultobj = PyEval_EvalCode((PyCodeObject*)m_bytecode, excdict, excdict); + /* PyRun_SimpleString(m_scriptText.Ptr()); */ + break; + } + case SCA_PYEXEC_MODULE: + { + if (m_bModified || m_debug) + if (Import()==false) // sets m_bModified to false + return; + if (!m_function) + return; + + PyObject *args= NULL; + + if(m_function_argc==1) { + args = PyTuple_New(1); + PyTuple_SET_ITEM(args, 0, GetProxy()); + } + + resultobj = PyObject_CallObject(m_function, args); + Py_XDECREF(args); + break; + } + + } /* end switch */ + + + + /* Free the return value and print the error */ if (resultobj) { Py_DECREF(resultobj); @@ -304,146 +432,87 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) else { // something is wrong, tell the user what went wrong - printf("Python script error from controller \"%s\": \n", GetName().Ptr()); + printf("Python script error from controller \"%s\":\n", GetName().Ptr()); PyErr_Print(); /* Added in 2.48a, the last_traceback can reference Objects for example, increasing * their user count. Not to mention holding references to wrapped data. * This is especially bad when the PyObject for the wrapped data is free'd, after blender * has alredy dealocated the pointer */ - PySys_SetObject( "last_traceback", Py_None); + PySys_SetObject( (char *)"last_traceback", NULL); PyErr_Clear(); /* just to be sure */ - - //PyRun_SimpleString(m_scriptText.Ptr()); } - - // clear after PyErrPrint - seems it can be using - // something in this dictionary and crash? - PyDict_Clear(excdict); - Py_DECREF(excdict); - m_triggeredSensors.erase(m_triggeredSensors.begin(), m_triggeredSensors.end()); - m_sCurrentController = NULL; -} - - - -PyObject* SCA_PythonController::_getattr(const STR_String& attr) -{ - _getattr_up(SCA_IController); -} - - - -PyObject* SCA_PythonController::PyGetActuators(PyObject* self) -{ - PyObject* resultlist = PyList_New(m_linkedactuators.size()); - for (unsigned int index=0;index<m_linkedactuators.size();index++) + + if(excdict) /* Only for SCA_PYEXEC_SCRIPT types */ { - PyList_SET_ITEM(resultlist,index,m_linkedactuators[index]->AddRef()); - } - - return resultlist; + /* clear after PyErrPrint - seems it can be using + * something in this dictionary and crash? */ + PyDict_Clear(excdict); + Py_DECREF(excdict); + } + + m_triggeredSensors.clear(); + m_sCurrentController = NULL; } -const char SCA_PythonController::GetSensor_doc[] = -"GetSensor (char sensorname) return linked sensor that is named [sensorname]\n"; -PyObject* -SCA_PythonController::PyGetSensor(PyObject* self, PyObject* value) +PyObject* SCA_PythonController::PyActivate(PyObject *value) { - - char *scriptArg = PyString_AsString(value); - if (scriptArg==NULL) { - PyErr_SetString(PyExc_TypeError, "expected a string (sensor name)"); + if(m_sCurrentController != this) { + PyErr_SetString(PyExc_SystemError, "Cannot add an actuator from a non-active controller"); return NULL; } - for (unsigned int index=0;index<m_linkedsensors.size();index++) - { - SCA_ISensor* sensor = m_linkedsensors[index]; - STR_String realname = sensor->GetName(); - if (realname == scriptArg) - { - return sensor->AddRef(); - } - } + SCA_IActuator* actu = LinkedActuatorFromPy(value); + if(actu==NULL) + return NULL; - char emsg[96]; - PyOS_snprintf( emsg, sizeof( emsg ), "Unable to find requested sensor \"%s\"", scriptArg ); - PyErr_SetString(PyExc_AttributeError, emsg); - return NULL; + m_sCurrentLogicManager->AddActiveActuator((SCA_IActuator*)actu, true); + Py_RETURN_NONE; } - - -const char SCA_PythonController::GetActuator_doc[] = -"GetActuator (char sensorname) return linked actuator that is named [actuatorname]\n"; -PyObject* -SCA_PythonController::PyGetActuator(PyObject* self, PyObject* value) +PyObject* SCA_PythonController::PyDeActivate(PyObject *value) { - - char *scriptArg = PyString_AsString(value); - if (scriptArg==NULL) { - PyErr_SetString(PyExc_TypeError, "expected a string (actuator name)"); + if(m_sCurrentController != this) { + PyErr_SetString(PyExc_SystemError, "Cannot add an actuator from a non-active controller"); return NULL; } - for (unsigned int index=0;index<m_linkedactuators.size();index++) - { - SCA_IActuator* actua = m_linkedactuators[index]; - STR_String realname = actua->GetName(); - if (realname == scriptArg) - { - return actua->AddRef(); - } - } + SCA_IActuator* actu = LinkedActuatorFromPy(value); + if(actu==NULL) + return NULL; - char emsg[96]; - PyOS_snprintf( emsg, sizeof( emsg ), "Unable to find requested actuator \"%s\"", scriptArg ); - PyErr_SetString(PyExc_AttributeError, emsg); - return NULL; + m_sCurrentLogicManager->AddActiveActuator((SCA_IActuator*)actu, false); + Py_RETURN_NONE; } - -const char SCA_PythonController::GetSensors_doc[] = "getSensors returns a list of all attached sensors"; -PyObject* -SCA_PythonController::PyGetSensors(PyObject* self) +PyObject* SCA_PythonController::pyattr_get_script(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - PyObject* resultlist = PyList_New(m_linkedsensors.size()); - for (unsigned int index=0;index<m_linkedsensors.size();index++) - { - PyList_SET_ITEM(resultlist,index,m_linkedsensors[index]->AddRef()); - } - - return resultlist; -} + //SCA_PythonController* self= static_cast<SCA_PythonController*>(static_cast<SCA_IController*>(static_cast<SCA_ILogicBrick*>(static_cast<CValue*>(static_cast<PyObjectPlus*>(self_v))))); + // static_cast<void *>(dynamic_cast<Derived *>(obj)) - static_cast<void *>(obj) -/* 1. getScript */ -PyObject* SCA_PythonController::PyGetScript(PyObject* self) -{ - return PyString_FromString(m_scriptText); + SCA_PythonController* self= static_cast<SCA_PythonController*>(self_v); + return PyUnicode_FromString(self->m_scriptText); } -/* 2. setScript */ -PyObject* SCA_PythonController::PySetScript(PyObject* self, PyObject* value) + + +int SCA_PythonController::pyattr_set_script(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - char *scriptArg = PyString_AsString(value); + SCA_PythonController* self= static_cast<SCA_PythonController*>(self_v); + + char *scriptArg = _PyUnicode_AsString(value); + if (scriptArg==NULL) { - PyErr_SetString(PyExc_TypeError, "expected a string (script name)"); - return NULL; + PyErr_SetString(PyExc_TypeError, "controller.script = string: Python Controller, expected a string script text"); + return PY_SET_ATTR_FAIL; } - + /* set scripttext sets m_bModified to true, so next time the script is needed, a reparse into byte code is done */ - - this->SetScriptText(scriptArg); - - Py_RETURN_NONE; + self->SetScriptText(scriptArg); + + return PY_SET_ATTR_SUCCESS; } -/* 1. getScript */ -PyObject* SCA_PythonController::PyGetState(PyObject* self) -{ - return PyInt_FromLong(m_statemask); -} /* eof */ diff --git a/source/gameengine/GameLogic/SCA_PythonController.h b/source/gameengine/GameLogic/SCA_PythonController.h index d9b2e242bea..9311b3f355e 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.h +++ b/source/gameengine/GameLogic/SCA_PythonController.h @@ -42,23 +42,37 @@ class SCA_IObject; class SCA_PythonController : public SCA_IController { Py_Header; - struct _object * m_bytecode; + struct _object * m_bytecode; /* SCA_PYEXEC_SCRIPT only */ + PyObject* m_function; /* SCA_PYEXEC_MODULE only */ + int m_function_argc; bool m_bModified; + bool m_debug; /* use with SCA_PYEXEC_MODULE for reloading every logic run */ + int m_mode; + protected: STR_String m_scriptText; STR_String m_scriptName; - PyObject* m_pythondictionary; + PyObject* m_pythondictionary; /* for SCA_PYEXEC_SCRIPT only */ + PyObject* m_pythonfunction; /* for SCA_PYEXEC_MODULE only */ + std::vector<class SCA_ISensor*> m_triggeredSensors; + + public: + enum SCA_PyExecMode + { + SCA_PYEXEC_SCRIPT = 0, + SCA_PYEXEC_MODULE, + SCA_PYEXEC_MAX + }; - public: static SCA_PythonController* m_sCurrentController; // protected !!! //for debugging //virtual CValue* AddRef(); //virtual int Release(); // Release a reference to this value (when reference count reaches 0, the value is removed from the heap) - SCA_PythonController(SCA_IObject* gameobj,PyTypeObject* T = &Type); + SCA_PythonController(SCA_IObject* gameobj, int mode); virtual ~SCA_PythonController(); virtual CValue* GetReplica(); @@ -67,24 +81,31 @@ class SCA_PythonController : public SCA_IController void SetScriptText(const STR_String& text); void SetScriptName(const STR_String& name); void SetDictionary(PyObject* pythondictionary); + void SetDebug(bool debug) { m_debug = debug; } void AddTriggeredSensor(class SCA_ISensor* sensor) { m_triggeredSensors.push_back(sensor); } int IsTriggered(class SCA_ISensor* sensor); + bool Compile(); + bool Import(); + void ErrorPrint(const char *error_msg); + static const char* sPyGetCurrentController__doc__; static PyObject* sPyGetCurrentController(PyObject* self); static const char* sPyAddActiveActuator__doc__; static PyObject* sPyAddActiveActuator(PyObject* self, PyObject* args); - virtual PyObject* _getattr(const STR_String& attr); + static SCA_IActuator* LinkedActuatorFromPy(PyObject *value); - KX_PYMETHOD_DOC_NOARGS(SCA_PythonController,GetSensors); - KX_PYMETHOD_DOC_NOARGS(SCA_PythonController,GetActuators); - KX_PYMETHOD_DOC_O(SCA_PythonController,GetSensor); - KX_PYMETHOD_DOC_O(SCA_PythonController,GetActuator); + + KX_PYMETHOD_O(SCA_PythonController,Activate); + KX_PYMETHOD_O(SCA_PythonController,DeActivate); KX_PYMETHOD_O(SCA_PythonController,SetScript); KX_PYMETHOD_NOARGS(SCA_PythonController,GetScript); - KX_PYMETHOD_NOARGS(SCA_PythonController,GetState); + + + static PyObject* pyattr_get_script(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_script(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); }; diff --git a/source/gameengine/GameLogic/SCA_RandomActuator.cpp b/source/gameengine/GameLogic/SCA_RandomActuator.cpp index 7b50a483cd8..a3a5cc2303e 100644 --- a/source/gameengine/GameLogic/SCA_RandomActuator.cpp +++ b/source/gameengine/GameLogic/SCA_RandomActuator.cpp @@ -50,15 +50,13 @@ SCA_RandomActuator::SCA_RandomActuator(SCA_IObject *gameobj, SCA_RandomActuator::KX_RANDOMACT_MODE mode, float para1, float para2, - const STR_String &propName, - PyTypeObject* T) - : SCA_IActuator(gameobj, T), + const STR_String &propName) + : SCA_IActuator(gameobj), m_propname(propName), m_parameter1(para1), m_parameter2(para2), m_distribution(mode) { - // m_base is never deleted, probably a memory leak! m_base = new SCA_RandomNumberGenerator(seed); m_counter = 0; enforceConstraints(); @@ -68,7 +66,7 @@ SCA_RandomActuator::SCA_RandomActuator(SCA_IObject *gameobj, SCA_RandomActuator::~SCA_RandomActuator() { - /* intentionally empty */ + m_base->Release(); } @@ -78,11 +76,16 @@ CValue* SCA_RandomActuator::GetReplica() SCA_RandomActuator* replica = new SCA_RandomActuator(*this); // replication just copy the m_base pointer => common random generator replica->ProcessReplica(); - CValue::AddDataToReplica(replica); - return replica; } +void SCA_RandomActuator::ProcessReplica() +{ + SCA_IActuator::ProcessReplica(); + // increment reference count so that we can release the generator at the end + m_base->AddRef(); +} + bool SCA_RandomActuator::Update() @@ -312,223 +315,139 @@ void SCA_RandomActuator::enforceConstraints() { /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_RandomActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_RandomActuator", - sizeof(SCA_RandomActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_RandomActuator::Parents[] = { - &SCA_RandomActuator::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_RandomActuator::Methods[] = { - {"setSeed", (PyCFunction) SCA_RandomActuator::sPySetSeed, METH_VARARGS, (PY_METHODCHAR)SetSeed_doc}, - {"getSeed", (PyCFunction) SCA_RandomActuator::sPyGetSeed, METH_VARARGS, (PY_METHODCHAR)GetSeed_doc}, - {"getPara1", (PyCFunction) SCA_RandomActuator::sPyGetPara1, METH_VARARGS, (PY_METHODCHAR)GetPara1_doc}, - {"getPara2", (PyCFunction) SCA_RandomActuator::sPyGetPara2, METH_VARARGS, (PY_METHODCHAR)GetPara2_doc}, - {"getDistribution", (PyCFunction) SCA_RandomActuator::sPyGetDistribution, METH_VARARGS, (PY_METHODCHAR)GetDistribution_doc}, - {"setProperty", (PyCFunction) SCA_RandomActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, - {"getProperty", (PyCFunction) SCA_RandomActuator::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, - {"setBoolConst", (PyCFunction) SCA_RandomActuator::sPySetBoolConst, METH_VARARGS, (PY_METHODCHAR)SetBoolConst_doc}, - {"setBoolUniform", (PyCFunction) SCA_RandomActuator::sPySetBoolUniform, METH_VARARGS, (PY_METHODCHAR)SetBoolUniform_doc}, - {"setBoolBernouilli",(PyCFunction) SCA_RandomActuator::sPySetBoolBernouilli, METH_VARARGS, (PY_METHODCHAR)SetBoolBernouilli_doc}, - {"setIntConst", (PyCFunction) SCA_RandomActuator::sPySetIntConst, METH_VARARGS, (PY_METHODCHAR)SetIntConst_doc}, - {"setIntUniform", (PyCFunction) SCA_RandomActuator::sPySetIntUniform, METH_VARARGS, (PY_METHODCHAR)SetIntUniform_doc}, - {"setIntPoisson", (PyCFunction) SCA_RandomActuator::sPySetIntPoisson, METH_VARARGS, (PY_METHODCHAR)SetIntPoisson_doc}, - {"setFloatConst", (PyCFunction) SCA_RandomActuator::sPySetFloatConst, METH_VARARGS, (PY_METHODCHAR)SetFloatConst_doc}, - {"setFloatUniform", (PyCFunction) SCA_RandomActuator::sPySetFloatUniform, METH_VARARGS, (PY_METHODCHAR)SetFloatUniform_doc}, - {"setFloatNormal", (PyCFunction) SCA_RandomActuator::sPySetFloatNormal, METH_VARARGS, (PY_METHODCHAR)SetFloatNormal_doc}, - {"setFloatNegativeExponential", (PyCFunction) SCA_RandomActuator::sPySetFloatNegativeExponential, METH_VARARGS, (PY_METHODCHAR)SetFloatNegativeExponential_doc}, + KX_PYMETHODTABLE(SCA_RandomActuator, setBoolConst), + KX_PYMETHODTABLE_NOARGS(SCA_RandomActuator, setBoolUniform), + KX_PYMETHODTABLE(SCA_RandomActuator, setBoolBernouilli), + + KX_PYMETHODTABLE(SCA_RandomActuator, setIntConst), + KX_PYMETHODTABLE(SCA_RandomActuator, setIntUniform), + KX_PYMETHODTABLE(SCA_RandomActuator, setIntPoisson), + + KX_PYMETHODTABLE(SCA_RandomActuator, setFloatConst), + KX_PYMETHODTABLE(SCA_RandomActuator, setFloatUniform), + KX_PYMETHODTABLE(SCA_RandomActuator, setFloatNormal), + KX_PYMETHODTABLE(SCA_RandomActuator, setFloatNegativeExponential), {NULL,NULL} //Sentinel }; -PyObject* SCA_RandomActuator::_getattr(const STR_String& attr) { - _getattr_up(SCA_IActuator); -} - -/* 1. setSeed */ -const char SCA_RandomActuator::SetSeed_doc[] = -"setSeed(seed)\n" -"\t- seed: integer\n" -"\tSet the initial seed of the generator. Equal seeds produce\n" -"\tequal series. If the seed is 0, the generator will produce\n" -"\tthe same value on every call.\n"; -PyObject* SCA_RandomActuator::PySetSeed(PyObject* self, PyObject* args, PyObject* kwds) { - long seedArg; - if(!PyArg_ParseTuple(args, "i", &seedArg)) { - return NULL; - } - - m_base->SetSeed(seedArg); - - Py_Return; -} -/* 2. getSeed */ -const char SCA_RandomActuator::GetSeed_doc[] = -"getSeed()\n" -"\tReturns the initial seed of the generator. Equal seeds produce\n" -"\tequal series.\n"; -PyObject* SCA_RandomActuator::PyGetSeed(PyObject* self, PyObject* args, PyObject* kwds) { - return PyInt_FromLong(m_base->GetSeed()); -} - -/* 4. getPara1 */ -const char SCA_RandomActuator::GetPara1_doc[] = -"getPara1()\n" -"\tReturns the first parameter of the active distribution. Refer\n" -"\tto the documentation of the generator types for the meaning\n" -"\tof this value."; -PyObject* SCA_RandomActuator::PyGetPara1(PyObject* self, PyObject* args, PyObject* kwds) { - return PyFloat_FromDouble(m_parameter1); -} - -/* 6. getPara2 */ -const char SCA_RandomActuator::GetPara2_doc[] = -"getPara2()\n" -"\tReturns the first parameter of the active distribution. Refer\n" -"\tto the documentation of the generator types for the meaning\n" -"\tof this value."; -PyObject* SCA_RandomActuator::PyGetPara2(PyObject* self, PyObject* args, PyObject* kwds) { - return PyFloat_FromDouble(m_parameter2); -} +PyAttributeDef SCA_RandomActuator::Attributes[] = { + KX_PYATTRIBUTE_FLOAT_RO("para1",SCA_RandomActuator,m_parameter1), + KX_PYATTRIBUTE_FLOAT_RO("para2",SCA_RandomActuator,m_parameter2), + KX_PYATTRIBUTE_ENUM_RO("distribution",SCA_RandomActuator,m_distribution), + KX_PYATTRIBUTE_STRING_RW_CHECK("propName",0,100,false,SCA_RandomActuator,m_propname,CheckProperty), + KX_PYATTRIBUTE_RW_FUNCTION("seed",SCA_RandomActuator,pyattr_get_seed,pyattr_set_seed), + { NULL } //Sentinel +}; -/* 8. getDistribution */ -const char SCA_RandomActuator::GetDistribution_doc[] = -"getDistribution()\n" -"\tReturns the type of the active distribution.\n"; -PyObject* SCA_RandomActuator::PyGetDistribution(PyObject* self, PyObject* args, PyObject* kwds) { - return PyInt_FromLong(m_distribution); +PyObject* SCA_RandomActuator::pyattr_get_seed(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + SCA_RandomActuator* act = static_cast<SCA_RandomActuator*>(self); + return PyLong_FromSsize_t(act->m_base->GetSeed()); } -/* 9. setProperty */ -const char SCA_RandomActuator::SetProperty_doc[] = -"setProperty(name)\n" -"\t- name: string\n" -"\tSet the property to which the random value is assigned. If the \n" -"\tgenerator and property types do not match, the assignment is ignored.\n"; -PyObject* SCA_RandomActuator::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds) { - char *nameArg; - if (!PyArg_ParseTuple(args, "s", &nameArg)) { - return NULL; - } - - CValue* prop = GetParent()->FindIdentifier(nameArg); - - if (!prop->IsError()) { - m_propname = nameArg; +int SCA_RandomActuator::pyattr_set_seed(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + SCA_RandomActuator* act = static_cast<SCA_RandomActuator*>(self); + if (PyLong_Check(value)) { + int ival = PyLong_AsSsize_t(value); + act->m_base->SetSeed(ival); + return PY_SET_ATTR_SUCCESS; } else { - ; /* not found ... */ + PyErr_SetString(PyExc_TypeError, "actuator.seed = int: Random Actuator, expected an integer"); + return PY_SET_ATTR_FAIL; } - prop->Release(); - - Py_Return; -} -/* 10. getProperty */ -const char SCA_RandomActuator::GetProperty_doc[] = -"getProperty(name)\n" -"\tReturn the property to which the random value is assigned. If the \n" -"\tgenerator and property types do not match, the assignment is ignored.\n"; -PyObject* SCA_RandomActuator::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) { - return PyString_FromString(m_propname); } /* 11. setBoolConst */ -const char SCA_RandomActuator::SetBoolConst_doc[] = +KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setBoolConst, "setBoolConst(value)\n" "\t- value: 0 or 1\n" -"\tSet this generator to produce a constant boolean value.\n"; -PyObject* SCA_RandomActuator::PySetBoolConst(PyObject* self, - PyObject* args, - PyObject* kwds) { +"\tSet this generator to produce a constant boolean value.\n") +{ int paraArg; - if(!PyArg_ParseTuple(args, "i", ¶Arg)) { + if(!PyArg_ParseTuple(args, "i:setBoolConst", ¶Arg)) { return NULL; } m_distribution = KX_RANDOMACT_BOOL_CONST; - if (paraArg) { - m_parameter1 = 1; - } + m_parameter1 = (paraArg) ? 1.0 : 0.0; - Py_Return; + Py_RETURN_NONE; } /* 12. setBoolUniform, */ -const char SCA_RandomActuator::SetBoolUniform_doc[] = +KX_PYMETHODDEF_DOC_NOARGS(SCA_RandomActuator, setBoolUniform, "setBoolUniform()\n" -"\tSet this generator to produce true and false, each with 50%% chance of occuring\n"; -PyObject* SCA_RandomActuator::PySetBoolUniform(PyObject* self, - PyObject* args, - PyObject* kwds) { +"\tSet this generator to produce true and false, each with 50%% chance of occuring\n") +{ /* no args */ m_distribution = KX_RANDOMACT_BOOL_UNIFORM; enforceConstraints(); - Py_Return; + Py_RETURN_NONE; } /* 13. setBoolBernouilli, */ -const char SCA_RandomActuator::SetBoolBernouilli_doc[] = +KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setBoolBernouilli, "setBoolBernouilli(value)\n" "\t- value: a float between 0 and 1\n" -"\tReturn false value * 100%% of the time.\n"; -PyObject* SCA_RandomActuator::PySetBoolBernouilli(PyObject* self, - PyObject* args, - PyObject* kwds) { +"\tReturn false value * 100%% of the time.\n") +{ float paraArg; - if(!PyArg_ParseTuple(args, "f", ¶Arg)) { + if(!PyArg_ParseTuple(args, "f:setBoolBernouilli", ¶Arg)) { return NULL; } m_distribution = KX_RANDOMACT_BOOL_BERNOUILLI; m_parameter1 = paraArg; enforceConstraints(); - Py_Return; + Py_RETURN_NONE; } /* 14. setIntConst,*/ -const char SCA_RandomActuator::SetIntConst_doc[] = +KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntConst, "setIntConst(value)\n" "\t- value: integer\n" -"\tAlways return value\n"; -PyObject* SCA_RandomActuator::PySetIntConst(PyObject* self, - PyObject* args, - PyObject* kwds) { +"\tAlways return value\n") +{ int paraArg; - if(!PyArg_ParseTuple(args, "i", ¶Arg)) { + if(!PyArg_ParseTuple(args, "i:setIntConst", ¶Arg)) { return NULL; } m_distribution = KX_RANDOMACT_INT_CONST; m_parameter1 = paraArg; enforceConstraints(); - Py_Return; + Py_RETURN_NONE; } /* 15. setIntUniform,*/ -const char SCA_RandomActuator::SetIntUniform_doc[] = +KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntUniform, "setIntUniform(lower_bound, upper_bound)\n" "\t- lower_bound: integer\n" "\t- upper_bound: integer\n" "\tReturn a random integer between lower_bound and\n" -"\tupper_bound. The boundaries are included.\n"; -PyObject* SCA_RandomActuator::PySetIntUniform(PyObject* self, - PyObject* args, - PyObject* kwds) { +"\tupper_bound. The boundaries are included.\n") +{ int paraArg1, paraArg2; - if(!PyArg_ParseTuple(args, "ii", ¶Arg1, ¶Arg2)) { + if(!PyArg_ParseTuple(args, "ii:setIntUniform", ¶Arg1, ¶Arg2)) { return NULL; } @@ -536,58 +455,52 @@ PyObject* SCA_RandomActuator::PySetIntUniform(PyObject* self, m_parameter1 = paraArg1; m_parameter2 = paraArg2; enforceConstraints(); - Py_Return; + Py_RETURN_NONE; } /* 16. setIntPoisson, */ -const char SCA_RandomActuator::SetIntPoisson_doc[] = +KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntPoisson, "setIntPoisson(value)\n" "\t- value: float\n" "\tReturn a Poisson-distributed number. This performs a series\n" "\tof Bernouilli tests with parameter value. It returns the\n" -"\tnumber of tries needed to achieve succes.\n"; -PyObject* SCA_RandomActuator::PySetIntPoisson(PyObject* self, - PyObject* args, - PyObject* kwds) { +"\tnumber of tries needed to achieve succes.\n") +{ float paraArg; - if(!PyArg_ParseTuple(args, "f", ¶Arg)) { + if(!PyArg_ParseTuple(args, "f:setIntPoisson", ¶Arg)) { return NULL; } m_distribution = KX_RANDOMACT_INT_POISSON; m_parameter1 = paraArg; enforceConstraints(); - Py_Return; + Py_RETURN_NONE; } -/* 17. setFloatConst,*/ -const char SCA_RandomActuator::SetFloatConst_doc[] = +/* 17. setFloatConst */ +KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatConst, "setFloatConst(value)\n" "\t- value: float\n" -"\tAlways return value\n"; -PyObject* SCA_RandomActuator::PySetFloatConst(PyObject* self, - PyObject* args, - PyObject* kwds) { +"\tAlways return value\n") +{ float paraArg; - if(!PyArg_ParseTuple(args, "f", ¶Arg)) { + if(!PyArg_ParseTuple(args, "f:setFloatConst", ¶Arg)) { return NULL; } m_distribution = KX_RANDOMACT_FLOAT_CONST; m_parameter1 = paraArg; enforceConstraints(); - Py_Return; + Py_RETURN_NONE; } /* 18. setFloatUniform, */ -const char SCA_RandomActuator::SetFloatUniform_doc[] = +KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatUniform, "setFloatUniform(lower_bound, upper_bound)\n" "\t- lower_bound: float\n" "\t- upper_bound: float\n" "\tReturn a random integer between lower_bound and\n" -"\tupper_bound.\n"; -PyObject* SCA_RandomActuator::PySetFloatUniform(PyObject* self, - PyObject* args, - PyObject* kwds) { +"\tupper_bound.\n") +{ float paraArg1, paraArg2; - if(!PyArg_ParseTuple(args, "ff", ¶Arg1, ¶Arg2)) { + if(!PyArg_ParseTuple(args, "ff:setFloatUniform", ¶Arg1, ¶Arg2)) { return NULL; } @@ -595,20 +508,18 @@ PyObject* SCA_RandomActuator::PySetFloatUniform(PyObject* self, m_parameter1 = paraArg1; m_parameter2 = paraArg2; enforceConstraints(); - Py_Return; + Py_RETURN_NONE; } /* 19. setFloatNormal, */ -const char SCA_RandomActuator::SetFloatNormal_doc[] = +KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatNormal, "setFloatNormal(mean, standard_deviation)\n" "\t- mean: float\n" "\t- standard_deviation: float\n" "\tReturn normal-distributed numbers. The average is mean, and the\n" -"\tdeviation from the mean is characterized by standard_deviation.\n"; -PyObject* SCA_RandomActuator::PySetFloatNormal(PyObject* self, - PyObject* args, - PyObject* kwds) { +"\tdeviation from the mean is characterized by standard_deviation.\n") +{ float paraArg1, paraArg2; - if(!PyArg_ParseTuple(args, "ff", ¶Arg1, ¶Arg2)) { + if(!PyArg_ParseTuple(args, "ff:setFloatNormal", ¶Arg1, ¶Arg2)) { return NULL; } @@ -616,26 +527,24 @@ PyObject* SCA_RandomActuator::PySetFloatNormal(PyObject* self, m_parameter1 = paraArg1; m_parameter2 = paraArg2; enforceConstraints(); - Py_Return; + Py_RETURN_NONE; } /* 20. setFloatNegativeExponential, */ -const char SCA_RandomActuator::SetFloatNegativeExponential_doc[] = +KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatNegativeExponential, "setFloatNegativeExponential(half_life)\n" "\t- half_life: float\n" "\tReturn negative-exponentially distributed numbers. The half-life 'time'\n" -"\tis characterized by half_life.\n"; -PyObject* SCA_RandomActuator::PySetFloatNegativeExponential(PyObject* self, - PyObject* args, - PyObject* kwds) { +"\tis characterized by half_life.\n") +{ float paraArg; - if(!PyArg_ParseTuple(args, "f", ¶Arg)) { + if(!PyArg_ParseTuple(args, "f:setFloatNegativeExponential", ¶Arg)) { return NULL; } m_distribution = KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL; m_parameter1 = paraArg; enforceConstraints(); - Py_Return; + Py_RETURN_NONE; } /* eof */ diff --git a/source/gameengine/GameLogic/SCA_RandomActuator.h b/source/gameengine/GameLogic/SCA_RandomActuator.h index f6da0595d1a..f84c44b43c9 100644 --- a/source/gameengine/GameLogic/SCA_RandomActuator.h +++ b/source/gameengine/GameLogic/SCA_RandomActuator.h @@ -85,57 +85,30 @@ class SCA_RandomActuator : public SCA_IActuator KX_RANDOMACT_MODE mode, float para1, float para2, - const STR_String &propName, - PyTypeObject* T=&Type); + const STR_String &propName); virtual ~SCA_RandomActuator(); virtual bool Update(); virtual CValue* GetReplica(); + virtual void ProcessReplica(); /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); + static PyObject* pyattr_get_seed(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_seed(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - /* 1. setSeed */ - KX_PYMETHOD_DOC(SCA_RandomActuator,SetSeed); - /* 2. getSeed */ - KX_PYMETHOD_DOC(SCA_RandomActuator,GetSeed); - /* 3. setPara1 -removed- */ - /* 4. getPara1 */ - KX_PYMETHOD_DOC(SCA_RandomActuator,GetPara1); - /* 5. setPara2 -removed- */ - /* 6. getPara2 */ - KX_PYMETHOD_DOC(SCA_RandomActuator,GetPara2); - /* 7. setDistribution -removed- */ - /* 8. getDistribution */ - KX_PYMETHOD_DOC(SCA_RandomActuator,GetDistribution); - /* 9. setProperty */ - KX_PYMETHOD_DOC(SCA_RandomActuator,SetProperty); - /* 10. getProperty */ - KX_PYMETHOD_DOC(SCA_RandomActuator,GetProperty); - /* 11. setBoolConst */ - KX_PYMETHOD_DOC(SCA_RandomActuator,SetBoolConst); - /* 12. setBoolUniform, */ - KX_PYMETHOD_DOC(SCA_RandomActuator,SetBoolUniform); - /* 13. setBoolBernouilli, */ - KX_PYMETHOD_DOC(SCA_RandomActuator,SetBoolBernouilli); - /* 14. setIntConst,*/ - KX_PYMETHOD_DOC(SCA_RandomActuator,SetIntConst); - /* 15. setIntUniform,*/ - KX_PYMETHOD_DOC(SCA_RandomActuator,SetIntUniform); - /* 16. setIntPoisson, */ - KX_PYMETHOD_DOC(SCA_RandomActuator,SetIntPoisson); - /* 17. setFloatConst,*/ - KX_PYMETHOD_DOC(SCA_RandomActuator,SetFloatConst); - /* 18. setFloatUniform, */ - KX_PYMETHOD_DOC(SCA_RandomActuator,SetFloatUniform); - /* 19. setFloatNormal, */ - KX_PYMETHOD_DOC(SCA_RandomActuator,SetFloatNormal); - /* 20. setFloatNegativeExponential, */ - KX_PYMETHOD_DOC(SCA_RandomActuator,SetFloatNegativeExponential); - + KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setBoolConst); + KX_PYMETHOD_DOC_NOARGS(SCA_RandomActuator, setBoolUniform); + KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setBoolBernouilli); + KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setIntConst); + KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setIntUniform); + KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setIntPoisson); + KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setFloatConst); + KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setFloatUniform); + KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setFloatNormal); + KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setFloatNegativeExponential); }; /* end of class KX_EditObjectActuator : public SCA_PropertyActuator */ #endif diff --git a/source/gameengine/GameLogic/SCA_RandomEventManager.cpp b/source/gameengine/GameLogic/SCA_RandomEventManager.cpp index 156478d866d..976597aa812 100644 --- a/source/gameengine/GameLogic/SCA_RandomEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_RandomEventManager.cpp @@ -50,9 +50,10 @@ SCA_RandomEventManager::SCA_RandomEventManager(class SCA_LogicManager* logicmgr) void SCA_RandomEventManager::NextFrame() { - for (set<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++) + SG_DList::iterator<SCA_ISensor> it(m_sensors); + for (it.begin();!it.end();++it) { - (*i)->Activate(m_logicmgr, NULL); + (*it)->Activate(m_logicmgr); } } diff --git a/source/gameengine/GameLogic/SCA_RandomEventManager.h b/source/gameengine/GameLogic/SCA_RandomEventManager.h index 79138c23c62..c8b511b87b7 100644 --- a/source/gameengine/GameLogic/SCA_RandomEventManager.h +++ b/source/gameengine/GameLogic/SCA_RandomEventManager.h @@ -45,6 +45,13 @@ public: SCA_RandomEventManager(class SCA_LogicManager* logicmgr); virtual void NextFrame(); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_RandomEventManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_RANDOMEVENTMGR diff --git a/source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp b/source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp index 06b5cca6ce9..0267cc8ebbf 100644 --- a/source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp +++ b/source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp @@ -59,6 +59,7 @@ SCA_RandomNumberGenerator::SCA_RandomNumberGenerator(long seed) { // int mti = N + 1; /*unused*/ m_seed = seed; + m_refcount = 1; SetStartVector(); } diff --git a/source/gameengine/GameLogic/SCA_RandomNumberGenerator.h b/source/gameengine/GameLogic/SCA_RandomNumberGenerator.h index b9311d31af6..f986fadeaf0 100644 --- a/source/gameengine/GameLogic/SCA_RandomNumberGenerator.h +++ b/source/gameengine/GameLogic/SCA_RandomNumberGenerator.h @@ -34,8 +34,15 @@ #ifndef __KX_RANDOMNUMBERGENERATOR #define __KX_RANDOMNUMBERGENERATOR +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class SCA_RandomNumberGenerator { + /* reference counted for memleak */ + int m_refcount; + /** base seed */ long m_seed; @@ -56,6 +63,23 @@ class SCA_RandomNumberGenerator { float DrawFloat(); long GetSeed(); void SetSeed(long newseed); + SCA_RandomNumberGenerator* AddRef() + { + ++m_refcount; + return this; + } + void Release() + { + if (--m_refcount == 0) + delete this; + } + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_RandomNumberGenerator"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif /* __KX_RANDOMNUMBERGENERATOR */ diff --git a/source/gameengine/GameLogic/SCA_RandomSensor.cpp b/source/gameengine/GameLogic/SCA_RandomSensor.cpp index 202fd6382e6..890875e61c6 100644 --- a/source/gameengine/GameLogic/SCA_RandomSensor.cpp +++ b/source/gameengine/GameLogic/SCA_RandomSensor.cpp @@ -46,11 +46,9 @@ SCA_RandomSensor::SCA_RandomSensor(SCA_EventManager* eventmgr, SCA_IObject* gameobj, - int startseed, - PyTypeObject* T) - : SCA_ISensor(gameobj,eventmgr, T) + int startseed) + : SCA_ISensor(gameobj,eventmgr) { - // m_basegenerator is never deleted => memory leak m_basegenerator = new SCA_RandomNumberGenerator(startseed); Init(); } @@ -59,7 +57,7 @@ SCA_RandomSensor::SCA_RandomSensor(SCA_EventManager* eventmgr, SCA_RandomSensor::~SCA_RandomSensor() { - /* Nothing to be done here. */ + m_basegenerator->Release(); } void SCA_RandomSensor::Init() @@ -74,13 +72,18 @@ void SCA_RandomSensor::Init() CValue* SCA_RandomSensor::GetReplica() { CValue* replica = new SCA_RandomSensor(*this); - // replication copies m_basegenerator pointer => share same generator // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } +void SCA_RandomSensor::ProcessReplica() +{ + SCA_ISensor::ProcessReplica(); + // increment reference count so that we can release the generator at this end + m_basegenerator->AddRef(); +} bool SCA_RandomSensor::IsPositiveTrigger() @@ -89,7 +92,7 @@ bool SCA_RandomSensor::IsPositiveTrigger() } -bool SCA_RandomSensor::Evaluate(CValue* event) +bool SCA_RandomSensor::Evaluate() { /* Random generator is the generator from Line 25 of Table 1 in */ /* [KNUTH 1981, The Art of Computer Programming Vol. 2 */ @@ -127,76 +130,52 @@ bool SCA_RandomSensor::Evaluate(CValue* event) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_RandomSensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_RandomSensor", - sizeof(SCA_RandomSensor), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_RandomSensor::Parents[] = { - &SCA_RandomSensor::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_RandomSensor::Methods[] = { - {"setSeed", (PyCFunction) SCA_RandomSensor::sPySetSeed, METH_VARARGS, (PY_METHODCHAR)SetSeed_doc}, - {"getSeed", (PyCFunction) SCA_RandomSensor::sPyGetSeed, METH_VARARGS, (PY_METHODCHAR)GetSeed_doc}, - {"getLastDraw", (PyCFunction) SCA_RandomSensor::sPyGetLastDraw, METH_VARARGS, (PY_METHODCHAR)GetLastDraw_doc}, {NULL,NULL} //Sentinel }; -PyObject* SCA_RandomSensor::_getattr(const STR_String& attr) { - _getattr_up(SCA_ISensor); -} - -/* 1. setSeed */ -const char SCA_RandomSensor::SetSeed_doc[] = -"setSeed(seed)\n" -"\t- seed: integer\n" -"\tSet the initial seed of the generator. Equal seeds produce\n" -"\tequal series. If the seed is 0, the generator will produce\n" -"\tthe same value on every call.\n"; -PyObject* SCA_RandomSensor::PySetSeed(PyObject* self, PyObject* args, PyObject* kwds) { - long seedArg; - if(!PyArg_ParseTuple(args, "i", &seedArg)) { - return NULL; - } - - m_basegenerator->SetSeed(seedArg); - - Py_Return; -} +PyAttributeDef SCA_RandomSensor::Attributes[] = { + KX_PYATTRIBUTE_BOOL_RO("lastDraw",SCA_RandomSensor,m_lastdraw), + KX_PYATTRIBUTE_RW_FUNCTION("seed", SCA_RandomSensor, pyattr_get_seed, pyattr_set_seed), + {NULL} //Sentinel +}; -/* 2. getSeed */ -const char SCA_RandomSensor::GetSeed_doc[] = -"getSeed()\n" -"\tReturns the initial seed of the generator. Equal seeds produce\n" -"\tequal series.\n"; -PyObject* SCA_RandomSensor::PyGetSeed(PyObject* self, PyObject* args, PyObject* kwds) { - return PyInt_FromLong(m_basegenerator->GetSeed()); +PyObject* SCA_RandomSensor::pyattr_get_seed(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + SCA_RandomSensor* self= static_cast<SCA_RandomSensor*>(self_v); + return PyLong_FromSsize_t(self->m_basegenerator->GetSeed()); } -/* 3. getLastDraw */ -const char SCA_RandomSensor::GetLastDraw_doc[] = -"getLastDraw()\n" -"\tReturn the last value that was drawn.\n"; -PyObject* SCA_RandomSensor::PyGetLastDraw(PyObject* self, PyObject* args, PyObject* kwds) { - return PyInt_FromLong(m_lastdraw); +int SCA_RandomSensor::pyattr_set_seed(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + SCA_RandomSensor* self= static_cast<SCA_RandomSensor*>(self_v); + if (!PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, "sensor.seed = int: Random Sensor, expected an integer"); + return PY_SET_ATTR_FAIL; + } + self->m_basegenerator->SetSeed(PyLong_AsSsize_t(value)); + return PY_SET_ATTR_SUCCESS; } /* eof */ diff --git a/source/gameengine/GameLogic/SCA_RandomSensor.h b/source/gameengine/GameLogic/SCA_RandomSensor.h index d29bfb6837a..f93cf57370e 100644 --- a/source/gameengine/GameLogic/SCA_RandomSensor.h +++ b/source/gameengine/GameLogic/SCA_RandomSensor.h @@ -48,26 +48,20 @@ class SCA_RandomSensor : public SCA_ISensor public: SCA_RandomSensor(class SCA_EventManager* rndmgr, SCA_IObject* gameobj, - int startseed, - PyTypeObject* T=&Type); + int startseed); virtual ~SCA_RandomSensor(); virtual CValue* GetReplica(); - virtual bool Evaluate(CValue* event); + virtual void ProcessReplica(); + virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void Init(); /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - - /* 1. setSeed */ - KX_PYMETHOD_DOC(SCA_RandomSensor,SetSeed); - /* 2. getSeed */ - KX_PYMETHOD_DOC(SCA_RandomSensor,GetSeed); - /* 3. getSeed */ - KX_PYMETHOD_DOC(SCA_RandomSensor,GetLastDraw); + + static PyObject* pyattr_get_seed(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_seed(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); }; diff --git a/source/gameengine/GameLogic/SCA_TimeEventManager.cpp b/source/gameengine/GameLogic/SCA_TimeEventManager.cpp index b7fadd3d62c..911ea772bef 100644 --- a/source/gameengine/GameLogic/SCA_TimeEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_TimeEventManager.cpp @@ -52,7 +52,7 @@ SCA_TimeEventManager::SCA_TimeEventManager(SCA_LogicManager* logicmgr) SCA_TimeEventManager::~SCA_TimeEventManager() { for (vector<CValue*>::iterator it = m_timevalues.begin(); - !(it == m_timevalues.end()); it++) + !(it == m_timevalues.end()); ++it) { (*it)->Release(); } @@ -80,7 +80,7 @@ void SCA_TimeEventManager::NextFrame(double curtime, double fixedtime) // update sensors, but ... need deltatime ! for (vector<CValue*>::iterator it = m_timevalues.begin(); - !(it == m_timevalues.end()); it++) + !(it == m_timevalues.end()); ++it) { float newtime = (*it)->GetNumber() + fixedtime; floatval->SetFloat(newtime); @@ -104,7 +104,7 @@ void SCA_TimeEventManager::AddTimeProperty(CValue* timeval) void SCA_TimeEventManager::RemoveTimeProperty(CValue* timeval) { for (vector<CValue*>::iterator it = m_timevalues.begin(); - !(it == m_timevalues.end()); it++) + !(it == m_timevalues.end()); ++it) { if ((*it) == timeval) { diff --git a/source/gameengine/GameLogic/SCA_TimeEventManager.h b/source/gameengine/GameLogic/SCA_TimeEventManager.h index bd57e12eb44..089f21e603b 100644 --- a/source/gameengine/GameLogic/SCA_TimeEventManager.h +++ b/source/gameengine/GameLogic/SCA_TimeEventManager.h @@ -48,6 +48,13 @@ public: virtual void RemoveSensor(class SCA_ISensor* sensor); void AddTimeProperty(CValue* timeval); void RemoveTimeProperty(CValue* timeval); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SCA_TimeEventManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_TIMEEVENTMANAGER diff --git a/source/gameengine/GameLogic/SCA_XNORController.cpp b/source/gameengine/GameLogic/SCA_XNORController.cpp index 3ef7c07fe0a..17350feb98b 100644 --- a/source/gameengine/GameLogic/SCA_XNORController.cpp +++ b/source/gameengine/GameLogic/SCA_XNORController.cpp @@ -42,10 +42,9 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_XNORController::SCA_XNORController(SCA_IObject* gameobj, - PyTypeObject* T) +SCA_XNORController::SCA_XNORController(SCA_IObject* gameobj) : - SCA_IController(gameobj,T) + SCA_IController(gameobj) { } @@ -66,7 +65,7 @@ void SCA_XNORController::Trigger(SCA_LogicManager* logicmgr) !(is==m_linkedsensors.end());is++) { SCA_ISensor* sensor = *is; - if (sensor->IsPositiveTrigger()) + if (sensor->GetState()) { if (sensorresult == false) { @@ -77,19 +76,12 @@ void SCA_XNORController::Trigger(SCA_LogicManager* logicmgr) } } - CValue* newevent = new CBoolValue(sensorresult); - for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin(); !(i==m_linkedactuators.end());i++) { - SCA_IActuator* actua = *i;//m_linkedactuators.at(i); - logicmgr->AddActiveActuator(actua,newevent); + SCA_IActuator* actua = *i; + logicmgr->AddActiveActuator(actua,sensorresult); } - - // every actuator that needs the event, has a it's own reference to it now so - // release it (so to be clear: if there is no actuator, it's deleted right now) - newevent->Release(); - } @@ -98,7 +90,7 @@ CValue* SCA_XNORController::GetReplica() { CValue* replica = new SCA_XNORController(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } @@ -111,38 +103,33 @@ CValue* SCA_XNORController::GetReplica() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_XNORController::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_XNORController", - sizeof(SCA_XNORController), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_XNORController::Parents[] = { - &SCA_XNORController::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IController::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_XNORController::Methods[] = { {NULL,NULL} //Sentinel }; -PyObject* SCA_XNORController::_getattr(const STR_String& attr) { - _getattr_up(SCA_IController); -} +PyAttributeDef SCA_XNORController::Attributes[] = { + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/GameLogic/SCA_XNORController.h b/source/gameengine/GameLogic/SCA_XNORController.h index 4b1eaee95d8..18e77fae665 100644 --- a/source/gameengine/GameLogic/SCA_XNORController.h +++ b/source/gameengine/GameLogic/SCA_XNORController.h @@ -39,7 +39,7 @@ class SCA_XNORController : public SCA_IController Py_Header; //virtual void Trigger(class SCA_LogicManager* logicmgr); public: - SCA_XNORController(SCA_IObject* gameobj,PyTypeObject* T=&Type); + SCA_XNORController(SCA_IObject* gameobj); virtual ~SCA_XNORController(); virtual CValue* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); @@ -48,8 +48,6 @@ public: /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); - }; #endif //__KX_XNORCONTROLLER diff --git a/source/gameengine/GameLogic/SCA_XORController.cpp b/source/gameengine/GameLogic/SCA_XORController.cpp index 6499c62f5f2..a6a7cc25897 100644 --- a/source/gameengine/GameLogic/SCA_XORController.cpp +++ b/source/gameengine/GameLogic/SCA_XORController.cpp @@ -42,10 +42,9 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_XORController::SCA_XORController(SCA_IObject* gameobj, - PyTypeObject* T) +SCA_XORController::SCA_XORController(SCA_IObject* gameobj) : - SCA_IController(gameobj,T) + SCA_IController(gameobj) { } @@ -66,7 +65,7 @@ void SCA_XORController::Trigger(SCA_LogicManager* logicmgr) !(is==m_linkedsensors.end());is++) { SCA_ISensor* sensor = *is; - if (sensor->IsPositiveTrigger()) + if (sensor->GetState()) { if (sensorresult == true) { @@ -77,19 +76,12 @@ void SCA_XORController::Trigger(SCA_LogicManager* logicmgr) } } - CValue* newevent = new CBoolValue(sensorresult); - for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin(); !(i==m_linkedactuators.end());i++) { - SCA_IActuator* actua = *i;//m_linkedactuators.at(i); - logicmgr->AddActiveActuator(actua,newevent); + SCA_IActuator* actua = *i; + logicmgr->AddActiveActuator(actua,sensorresult); } - - // every actuator that needs the event, has a it's own reference to it now so - // release it (so to be clear: if there is no actuator, it's deleted right now) - newevent->Release(); - } @@ -98,7 +90,7 @@ CValue* SCA_XORController::GetReplica() { CValue* replica = new SCA_XORController(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } @@ -111,38 +103,33 @@ CValue* SCA_XORController::GetReplica() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_XORController::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "SCA_XORController", - sizeof(SCA_XORController), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject SCA_XORController::Parents[] = { - &SCA_XORController::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IController::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef SCA_XORController::Methods[] = { {NULL,NULL} //Sentinel }; -PyObject* SCA_XORController::_getattr(const STR_String& attr) { - _getattr_up(SCA_IController); -} +PyAttributeDef SCA_XORController::Attributes[] = { + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/GameLogic/SCA_XORController.h b/source/gameengine/GameLogic/SCA_XORController.h index f50cd33c125..2607a533661 100644 --- a/source/gameengine/GameLogic/SCA_XORController.h +++ b/source/gameengine/GameLogic/SCA_XORController.h @@ -39,17 +39,10 @@ class SCA_XORController : public SCA_IController Py_Header; //virtual void Trigger(class SCA_LogicManager* logicmgr); public: - SCA_XORController(SCA_IObject* gameobj,PyTypeObject* T=&Type); + SCA_XORController(SCA_IObject* gameobj); virtual ~SCA_XORController(); virtual CValue* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); - - /* --------------------------------------------------------------------- */ - /* Python interface ---------------------------------------------------- */ - /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - }; #endif //__KX_XORCONTROLLER diff --git a/source/gameengine/GameLogic/SConscript b/source/gameengine/GameLogic/SConscript index fa5a3123215..1530c71c7f3 100644 --- a/source/gameengine/GameLogic/SConscript +++ b/source/gameengine/GameLogic/SConscript @@ -5,14 +5,20 @@ sources = env.Glob('*.cpp') + env.Glob('Joystick/*.cpp') incs = '. #/source/kernel/gen_system #/intern/string' incs += ' #/source/gameengine/Expressions #/intern/moto/include' -incs += ' #/source/gameengine/Rasterizer' +incs += ' #/source/gameengine/Rasterizer #/source/gameengine/SceneGraph' incs += ' ' + env['BF_PYTHON_INC'] -incs += ' ' + env['BF_SDL_INC'] -defs = '' -if not env['WITH_BF_SDL']: - defs += ' DISABLE_SDL' +defs = [] -env.BlenderLib ( 'bf_logic', sources, Split(incs), Split(defs), libtype=['game','player'], priority=[30, 110] ) +if env['WITH_BF_SDL']: + incs += ' ' + env['BF_SDL_INC'] +else: + defs.append('DISABLE_SDL') + +if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): + if env['BF_DEBUG']: + defs.append('_DEBUG') + +env.BlenderLib ( 'bf_logic', sources, Split(incs), defs, libtype=['core','player'], priority=[330,65], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/GamePlayer/CMakeLists.txt b/source/gameengine/GamePlayer/CMakeLists.txt index fc5912155cf..7b4fa4892df 100644 --- a/source/gameengine/GamePlayer/CMakeLists.txt +++ b/source/gameengine/GamePlayer/CMakeLists.txt @@ -24,8 +24,9 @@ # # ***** END GPL LICENSE BLOCK ***** -SUBDIRS(common ghost) +ADD_SUBDIRECTORY(common) +ADD_SUBDIRECTORY(ghost) IF(WITH_WEBPLUGIN) - SUBDIRS(xembed) + ADD_SUBDIRECTORY(xembed) ENDIF(WITH_WEBPLUGIN) diff --git a/source/gameengine/GamePlayer/common/CMakeLists.txt b/source/gameengine/GamePlayer/common/CMakeLists.txt index 0c6c4179e2d..c865cf5ce25 100644 --- a/source/gameengine/GamePlayer/common/CMakeLists.txt +++ b/source/gameengine/GamePlayer/common/CMakeLists.txt @@ -25,55 +25,50 @@ # ***** END GPL LICENSE BLOCK ***** SET(SRC - bmfont.cpp - GPC_Canvas.cpp - GPC_Engine.cpp - GPC_KeyboardDevice.cpp - GPC_MouseDevice.cpp - GPC_RawImage.cpp - GPC_RawLoadDotBlendArray.cpp - GPC_RawLogoArrays.cpp - GPC_RenderTools.cpp - GPC_System.cpp + bmfont.cpp + GPC_Canvas.cpp + GPC_Engine.cpp + GPC_KeyboardDevice.cpp + GPC_MouseDevice.cpp + GPC_RawImage.cpp + GPC_RawLoadDotBlendArray.cpp + GPC_RawLogoArrays.cpp + GPC_RenderTools.cpp + GPC_System.cpp ) SET(INC - . - ../../../../intern/string - ../../../../intern/ghost - ../../../../intern/guardedalloc - ../../../../intern/bmfont - ../../../../intern/moto/include - ../../../../intern/SoundSystem - ../../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../../source/kernel/gen_system - ../../../../source/kernel/gen_messaging - ../../../../source/gameengine/Converter - ../../../../source/blender/imbuf - ../../../../source/gameengine/Ketsji - ../../../../source/blender/blenlib - ../../../../source/blender/blenkernel - ../../../../source/blender - ../../../../source/blender/include - ../../../../source/blender/makesdna - ../../../../source/gameengine/Rasterizer - ../../../../source/gameengine/GameLogic - ../../../../source/gameengine/Expressions - ../../../../source/gameengine/Network - ../../../../source/gameengine/SceneGraph - ../../../../source/gameengine/Physics/common - ../../../../source/gameengine/Physics/Sumo - ../../../../source/gameengine/Physics/Sumo/Fuzzics/include - ../../../../source/gameengine/Network/LoopBackNetwork - ../../../../source/gameengine/GamePlayer/ghost - ../../../../source/blender/misc - ../../../../source/blender/blenloader - ../../../../source/blender/gpu - ../../../../extern/glew/include - ${PYTHON_INC} - ${SOLID_INC} - ${PNG_INC} - ${ZLIB_INC} + . + ../../../../intern/string + ../../../../intern/ghost + ../../../../intern/guardedalloc + ../../../../intern/moto/include + ../../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer + ../../../../source/kernel/gen_system + ../../../../source/kernel/gen_messaging + ../../../../source/gameengine/Converter + ../../../../source/blender/imbuf + ../../../../source/gameengine/Ketsji + ../../../../source/blender/blenlib + ../../../../source/blender/blenkernel + ../../../../source/blender + ../../../../source/blender/include + ../../../../source/blender/makesdna + ../../../../source/gameengine/Rasterizer + ../../../../source/gameengine/GameLogic + ../../../../source/gameengine/Expressions + ../../../../source/gameengine/Network + ../../../../source/gameengine/SceneGraph + ../../../../source/gameengine/Physics/common + ../../../../source/gameengine/Network/LoopBackNetwork + ../../../../source/gameengine/GamePlayer/ghost + ../../../../source/blender/misc + ../../../../source/blender/blenloader + ../../../../source/blender/gpu + ../../../../extern/glew/include + ${PYTHON_INC} + ${PNG_INC} + ${ZLIB_INC} ) BLENDERLIB_NOLIST(gp_common "${SRC}" "${INC}") diff --git a/source/gameengine/GamePlayer/common/GPC_Engine.cpp b/source/gameengine/GamePlayer/common/GPC_Engine.cpp index 868dddb901c..85a362d042a 100644 --- a/source/gameengine/GamePlayer/common/GPC_Engine.cpp +++ b/source/gameengine/GamePlayer/common/GPC_Engine.cpp @@ -39,6 +39,7 @@ #include "BKE_blender.h" // initglobals() #include "BKE_global.h" // Global G +#include "BKE_report.h" #include "DNA_scene_types.h" #include "DNA_camera_types.h" // Camera #include "DNA_object_types.h" // Object @@ -57,7 +58,6 @@ #include "NG_LoopBackNetworkDeviceInterface.h" #include "RAS_IRenderTools.h" -#include "SND_DeviceManager.h" #include "GPC_Engine.h" #include "GPC_KeyboardDevice.h" @@ -74,8 +74,7 @@ GPC_Engine::GPC_Engine(char *customLoadingAnimationURL, m_system(NULL), m_keyboarddev(NULL), m_mousedev(NULL), m_canvas(NULL), m_rendertools(NULL), m_portal(NULL), m_sceneconverter(NULL), m_networkdev(NULL), - m_audiodevice(NULL), m_curarea(NULL), - m_customLoadingAnimationURL(NULL), + m_curarea(NULL), m_customLoadingAnimationURL(NULL), m_foregroundColor(foregroundColor), m_backgroundColor(backgroundColor), m_frameRate(frameRate), m_BlenderLogo(0), m_Blender3DLogo(0)/*, m_NaNLogo(0)*/ @@ -135,15 +134,19 @@ GPC_Engine::~GPC_Engine() bool GPC_Engine::Start(char *filename) { - BlendReadError error; - BlendFileData *bfd= BLO_read_from_file(filename, &error); + ReportList reports; + BlendFileData *bfd; + + BKE_reports_init(&reports, RPT_STORE); + bfd= BLO_read_from_file(filename, &reports); + BKE_reports_clear(&reports); if (!bfd) { // XXX, deal with error here cout << "Unable to load: " << filename << endl; return false; } - + StartKetsji(); if(bfd->type == BLENFILETYPE_PUB) @@ -156,8 +159,12 @@ bool GPC_Engine::Start(char *filename) bool GPC_Engine::Start(unsigned char *blenderDataBuffer, unsigned int blenderDataBufferSize) { - BlendReadError error; - BlendFileData *bfd= BLO_read_from_memory(blenderDataBuffer, blenderDataBufferSize, &error); + ReportList reports; + BlendFileData *bfd; + + BKE_reports_init(&reports, RPT_STORE); + bfd= BLO_read_from_memory(blenderDataBuffer, blenderDataBufferSize, &reports); + BKE_reports_clear(&reports); if (!bfd) { // XXX, deal with error here @@ -176,7 +183,7 @@ bool GPC_Engine::Start(unsigned char *blenderDataBuffer, bool GPC_Engine::StartKetsji(void) { - STR_String startSceneName = G.scene->id.name + 2; + STR_String startSceneName = ""; // XXX scene->id.name + 2; /* KX_KetsjiEngine* ketsjieng = new KX_KetsjiEngine(m_system); m_portal = new KetsjiPortal(ketsjieng); @@ -192,7 +199,6 @@ bool GPC_Engine::StartKetsji(void) m_keyboarddev, m_mousedev, m_networkdev, - m_audiodevice, m_system); m_system->SetMainLoop(m_portal->m_ketsjieng); @@ -328,12 +334,6 @@ void GPC_Engine::Exit() m_networkdev = 0; } - if (m_audiodevice) - { - SND_DeviceManager::Unsubscribe(); - m_audiodevice = 0; - } - m_initialized = false; } diff --git a/source/gameengine/GamePlayer/common/GPC_Engine.h b/source/gameengine/GamePlayer/common/GPC_Engine.h index b7121599c6e..42234bcbcd6 100644 --- a/source/gameengine/GamePlayer/common/GPC_Engine.h +++ b/source/gameengine/GamePlayer/common/GPC_Engine.h @@ -40,7 +40,6 @@ class RAS_IRenderTools; class KetsjiPortal; class KX_ISceneConverter; class NG_LoopBackNetworkDeviceInterface; -class SND_IAudioDevice; class GPC_RawImage; @@ -77,8 +76,6 @@ public: KX_ISceneConverter* m_sceneconverter; /** Network interface. */ NG_LoopBackNetworkDeviceInterface* m_networkdev; - /** Audiodevice interface */ - SND_IAudioDevice* m_audiodevice; struct ScrArea *m_curarea; // for future use, not used yet diff --git a/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp b/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp index 474df9276a7..472ff580392 100644 --- a/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp +++ b/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp @@ -42,7 +42,7 @@ void GPC_KeyboardDevice::NextFrame() // Now convert justpressed key events into regular (active) keyevents int previousTable = 1-m_currentTable; - for (int keyevent= KX_BEGINKEY; keyevent< KX_ENDKEY;keyevent++) + for (int keyevent= KX_BEGINKEY; keyevent<= KX_ENDKEY;keyevent++) { SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][keyevent]; if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED || @@ -69,7 +69,7 @@ bool GPC_KeyboardDevice::ConvertEvent(int incode, int val) KX_EnumInputs kxevent = this->ToNative(incode); // only process it, if it's a key - if (kxevent >= KX_BEGINKEY && kxevent < KX_ENDKEY) + if (kxevent >= KX_BEGINKEY && kxevent <= KX_ENDKEY) { int previousTable = 1-m_currentTable; @@ -114,9 +114,7 @@ bool GPC_KeyboardDevice::ConvertEvent(int incode, int val) } } } - } else if(kxevent==KX_ENDKEY) { - exit(1); - } + } return result; } diff --git a/source/gameengine/GamePlayer/common/GPC_PolygonMaterial.cpp b/source/gameengine/GamePlayer/common/GPC_PolygonMaterial.cpp deleted file mode 100644 index b1e2b5af0e6..00000000000 --- a/source/gameengine/GamePlayer/common/GPC_PolygonMaterial.cpp +++ /dev/null @@ -1,412 +0,0 @@ -/** - * $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "GL/glew.h" - -#include "GPC_PolygonMaterial.h" -#include "MT_Vector3.h" -#include "RAS_IRasterizer.h" -#include "RAS_GLExtensionManager.h" - -/* This list includes only data type definitions */ -#include "DNA_object_types.h" -#include "DNA_material_types.h" -#include "DNA_image_types.h" -#include "DNA_lamp_types.h" -#include "DNA_group_types.h" -#include "DNA_scene_types.h" -#include "DNA_camera_types.h" -#include "DNA_property_types.h" -#include "DNA_text_types.h" -#include "DNA_sensor_types.h" -#include "DNA_controller_types.h" -#include "DNA_actuator_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_view3d_types.h" -#include "DNA_world_types.h" - -#include "BKE_global.h" -#include "BKE_image.h" -#include "BKE_mesh.h" - -#include "MEM_guardedalloc.h" - -#include "IMB_imbuf_types.h" -/* end of blender include block */ - -static Image *fCurpage=0; -static int fCurtile=0, fCurmode=0, fCurTileXRep=0, fCurTileYRep=0; -static short fTexWindx, fTexWindy, fTexWinsx, fTexWinsy; -static int fDoMipMap = 1; -static int fLinearMipMap=1; -static int fAlphamode= -1; - - /* (n&(n-1)) zeros the least significant bit of n */ -static int is_pow2(int num) { - return ((num)&(num-1))==0; -} -static int smaller_pow2(int num) { - while (!is_pow2(num)) - num= num&(num-1); - return num; -} - -static void my_make_repbind(Image *ima) -{ - if(ima==0 || ima->ibufs.first==0) return; - - if(ima->repbind) { - glDeleteTextures(ima->totbind, (GLuint*)ima->repbind); - delete (ima->repbind); - ima->repbind= 0; - } - ima->totbind= ima->xrep*ima->yrep; - if(ima->totbind>1) { - ima->repbind= (unsigned int *) malloc(sizeof(int)*ima->totbind); - for (int i=0;i<ima->totbind;i++) - ((int*)ima->repbind)[i] = 0; - } -} - -extern "C" int set_tpage(MTFace *tface); - -int set_tpage(MTFace *tface) -{ - static MTFace *lasttface= 0; - Image *ima; - unsigned int *rect, *bind; - int tpx, tpy, tilemode, tileXRep,tileYRep; - - /* disable */ - if(tface==0) { - if(lasttface==0) return 0; - - lasttface= 0; - fCurtile= 0; - fCurpage= 0; - if(fCurmode!=0) { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - } - fCurmode= 0; - fCurTileXRep=0; - fCurTileYRep=0; - fAlphamode= -1; - - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - return 0; - } - lasttface= tface; - - if( fAlphamode != tface->transp) { - fAlphamode= tface->transp; - - if(fAlphamode) { - if(fAlphamode==TF_ADD) { - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - glDisable ( GL_ALPHA_TEST ); - /* glBlendEquationEXT(GL_FUNC_ADD_EXT); */ - } - else if(fAlphamode==TF_ALPHA) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable ( GL_ALPHA_TEST ); - /* glBlendEquationEXT(GL_FUNC_ADD_EXT); */ - } - else if (fAlphamode==TF_CLIP){ - glDisable(GL_BLEND); - glEnable ( GL_ALPHA_TEST ); - glAlphaFunc(GL_GREATER, 0.5f); - } - /* else { */ - /* glBlendFunc(GL_ONE, GL_ONE); */ - /* glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); */ - /* } */ - } - else glDisable(GL_BLEND); - } - - ima= (struct Image *) tface->tpage; - - /* Enable or disable environment mapping */ - if (ima && (ima->flag & IMA_REFLECT)){ - - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - } - else{ - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - } - - tilemode= tface->mode & TF_TILES; - tileXRep = 0; - tileYRep = 0; - if (ima) - { - tileXRep = ima->xrep; - tileYRep = ima->yrep; - } - - - if(ima==fCurpage && fCurtile==tface->tile && tilemode==fCurmode && fCurTileXRep==tileXRep && fCurTileYRep == tileYRep) return ima!=0; - - if(tilemode!=fCurmode || fCurTileXRep!=tileXRep || fCurTileYRep != tileYRep) - { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - - if(tilemode && ima!=0) - glScalef(ima->xrep, ima->yrep, 1.0); - - glMatrixMode(GL_MODELVIEW); - } - - if(ima==0 || ima->ok==0) { - glDisable(GL_TEXTURE_2D); - - fCurtile= tface->tile; - fCurpage= 0; - fCurmode= tilemode; - fCurTileXRep = tileXRep; - fCurTileYRep = tileYRep; - - return 0; - } - - ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); - - if(ibuf==0) { - ima->ok= 0; - - fCurtile= tface->tile; - fCurpage= 0; - fCurmode= tilemode; - fCurTileXRep = tileXRep; - fCurTileYRep = tileYRep; - - glDisable(GL_TEXTURE_2D); - return 0; - } - - if(ima->tpageflag & IMA_TWINANIM) fCurtile= ima->lastframe; - else fCurtile= tface->tile; - - if(tilemode) { - - if(ima->repbind==0) my_make_repbind(ima); - - if(fCurtile>=ima->totbind) fCurtile= 0; - - /* this happens when you change repeat buttons */ - if(ima->repbind) bind= ima->repbind+fCurtile; - else bind= &ima->bindcode; - - if(*bind==0) { - - fTexWindx= ibuf->x/ima->xrep; - fTexWindy= ibuf->y/ima->yrep; - - if(fCurtile>=ima->xrep*ima->yrep) fCurtile= ima->xrep*ima->yrep-1; - - fTexWinsy= fCurtile / ima->xrep; - fTexWinsx= fCurtile - fTexWinsy*ima->xrep; - - fTexWinsx*= fTexWindx; - fTexWinsy*= fTexWindy; - - tpx= fTexWindx; - tpy= fTexWindy; - - rect= ibuf->rect + fTexWinsy*ibuf->x + fTexWinsx; - } - } - else { - bind= &ima->bindcode; - - if(*bind==0) { - tpx= ibuf->x; - tpy= ibuf->y; - rect= ibuf->rect; - } - } - - if(*bind==0) { - int rectw= tpx, recth= tpy; - unsigned int *tilerect= NULL, *scalerect= NULL; - - /* - * Maarten: - * According to Ton this code is not needed anymore. It was used only - * in really old Blenders. - * Reevan: - * Actually it is needed for backwards compatibility. Simpledemo 6 does not display correctly without it. - */ -#if 1 - if (tilemode) { - int y; - - tilerect= (unsigned int*)MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect"); - for (y=0; y<recth; y++) { - unsigned int *rectrow= &rect[y*ibuf->x]; - unsigned int *tilerectrow= &tilerect[y*rectw]; - - memcpy(tilerectrow, rectrow, tpx*sizeof(*rectrow)); - } - - rect= tilerect; - } -#endif - if (!is_pow2(rectw) || !is_pow2(recth)) { - rectw= smaller_pow2(rectw); - recth= smaller_pow2(recth); - - scalerect= (unsigned int *)MEM_mallocN(rectw*recth*sizeof(*scalerect), "scalerect"); - gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, rect, rectw, recth, GL_UNSIGNED_BYTE, scalerect); - rect= scalerect; - } - - glGenTextures(1, (GLuint*)bind); - - /* - if(G.f & G_DEBUG) { - printf("var1: %s\n", ima->id.name+2); - printf("var1: %d, var2: %d\n", *bind, tpx); - printf("var1: %d, var2: %d\n", fCurtile, tilemode); - } - */ - glBindTexture( GL_TEXTURE_2D, *bind); - - if (!fDoMipMap) - { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } else - { - int minfilter= fLinearMipMap?GL_LINEAR_MIPMAP_LINEAR:GL_LINEAR_MIPMAP_NEAREST; - - gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - if (tilerect) - MEM_freeN(tilerect); - if (scalerect) - MEM_freeN(scalerect); - } - else glBindTexture( GL_TEXTURE_2D, *bind); - - - - glEnable(GL_TEXTURE_2D); - - fCurpage= ima; - fCurmode= tilemode; - fCurTileXRep = tileXRep; - fCurTileYRep = tileYRep; - - return 1; -} - -#if 0 -GPC_PolygonMaterial::GPC_PolygonMaterial(const STR_String& texname, bool ba, const STR_String& matname, - int tile, int tileXrep, int tileYrep, int mode, bool transparant, bool zsort, - int lightlayer, bool bIsTriangle, void* clientobject, void* tpage) : - RAS_IPolyMaterial(texname, ba, matname, tile, tileXrep, tileYrep, mode, - transparant, zsort, lightlayer, bIsTriangle, clientobject), m_tface((struct MTFace*)tpage) -{ - // clear local caching info - my_set_tpage(0); -} - - -GPC_PolygonMaterial::~GPC_PolygonMaterial(void) -{ -} - - -void GPC_PolygonMaterial::Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const -{ - if (GetCachingInfo() != cachingInfo) - { - if (!cachingInfo) - { - my_set_tpage(0); - } - cachingInfo = GetCachingInfo(); - - if ((m_drawingmode & 4)&& (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) ) - { - update_realtime_texture((struct MTFace*) m_tface, rasty->GetTime()); - my_set_tpage(m_tface); - rasty->EnableTextures(true); - } else - { - my_set_tpage(0); - rasty->EnableTextures(false); - } - - //TF_TWOSIDE == 512, todo, make this a ketsji enum - if(m_drawingmode & 512) { - rasty->SetCullFace(false); - } - - else - { - rasty->SetCullFace(true);//glEnable(GL_CULL_FACE); - //else glDisable(GL_CULL_FACE); - } - } - rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity); - rasty->SetShinyness(m_shininess); - rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0); -} - -#endif -void GPC_PolygonMaterial::SetMipMappingEnabled(bool enabled) -{ - fDoMipMap = enabled ? 1 : 0; -} diff --git a/source/gameengine/GamePlayer/common/GPC_PolygonMaterial.h b/source/gameengine/GamePlayer/common/GPC_PolygonMaterial.h deleted file mode 100644 index 212decd078c..00000000000 --- a/source/gameengine/GamePlayer/common/GPC_PolygonMaterial.h +++ /dev/null @@ -1,89 +0,0 @@ -/** - * $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ - -#ifndef __GPC_POLYGONMATERIAL -#define __GPC_POLYGONMATERIAL - -#include "RAS_IPolygonMaterial.h" - -namespace GPC_PolygonMaterial -{ - void SetMipMappingEnabled(bool enabled = false); -}; - -#if 0 -class GPC_PolygonMaterial : public RAS_IPolyMaterial -{ - struct MTFace* m_tface; - -public: - GPC_PolygonMaterial(const STR_String& texname, bool ba, const STR_String& matname, - int tile, int tileXrep, int tileYrep, int mode, bool transparant, bool zsort, - int lightlayer, bool bIsTriangle, void* clientobject, void* tpage); - - virtual ~GPC_PolygonMaterial(void); - - /** - * Returns the caching information for this material, - * This can be used to speed up the rasterizing process. - * @return The caching information. - */ - virtual TCachingInfo GetCachingInfo(void) const; - - /** - * Activates the material in the (OpenGL) rasterizer. - * On entry, the cachingInfo contains info about the last activated material. - * On exit, the cachingInfo should contain updated info about this material. - * @param rasty The rasterizer in which the material should be active. - * @param cachingInfo The information about the material used to speed up rasterizing. - */ - virtual void Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const; - - /** - * Returns the Blender texture face structure that is used for this material. - * @return The material's texture face. - */ - MTFace* GetMTFace(void) const; - - static void SetMipMappingEnabled(bool enabled = false); -}; - - -inline MTFace* GPC_PolygonMaterial::GetMTFace(void) const -{ - return m_tface; -} - -inline GPC_PolygonMaterial::TCachingInfo GPC_PolygonMaterial::GetCachingInfo(void) const -{ - return GetMTFace(); -} -#endif -#endif // __GPC_POLYGONMATERIAL_H - diff --git a/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp b/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp index 78d8eaf2aa3..24fca3feb8b 100644 --- a/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp +++ b/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp @@ -40,6 +40,7 @@ #include "KX_BlenderMaterial.h" #include "KX_RayCast.h" #include "KX_IPhysicsController.h" +#include "KX_Light.h" #include "PHY_IPhysicsEnvironment.h" @@ -52,11 +53,12 @@ #include "GPC_RenderTools.h" + unsigned int GPC_RenderTools::m_numgllights; GPC_RenderTools::GPC_RenderTools() { - m_font = BMF_GetFont(BMF_kHelvetica10); +// XXX m_font = BMF_GetFont(BMF_kHelvetica10); glGetIntegerv(GL_MAX_LIGHTS, (GLint*) &m_numgllights); if (m_numgllights < 8) @@ -71,7 +73,8 @@ void GPC_RenderTools::BeginFrame(RAS_IRasterizer* rasty) { m_clientobject = NULL; m_lastlightlayer = -1; - m_lastlighting = false; + m_lastauxinfo = NULL; + m_lastlighting = true; /* force disable in DisableOpenGLLights() */ DisableOpenGLLights(); } @@ -85,33 +88,35 @@ void GPC_RenderTools::EndFrame(RAS_IRasterizer* rasty) * has a maximum of 8 lights (simultaneous), so 20 * 8 lights are possible in * a scene. */ -void GPC_RenderTools::ProcessLighting(int layer, const MT_Transform& viewmat) +void GPC_RenderTools::ProcessLighting(RAS_IRasterizer *rasty, bool uselights, const MT_Transform& viewmat) { - if(m_lastlightlayer == layer) - return; + bool enable = false; + int layer= -1; - m_lastlightlayer = layer; + /* find the layer */ + if(uselights) { + if(m_clientobject) + layer = static_cast<KX_GameObject*>(m_clientobject)->GetLayer(); + } - bool enable = false; + /* avoid state switching */ + if(m_lastlightlayer == layer && m_lastauxinfo == m_auxilaryClientInfo) + return; - if (layer >= 0) - { - if (m_clientobject) - { - if (layer == RAS_LIGHT_OBJECT_LAYER) - layer = static_cast<KX_GameObject*>(m_clientobject)->GetLayer(); + m_lastlightlayer = layer; + m_lastauxinfo = m_auxilaryClientInfo; - enable = applyLights(layer, viewmat); - } - } + /* enable/disable lights as needed */ + if(layer >= 0) + enable = applyLights(layer, viewmat); if(enable) - EnableOpenGLLights(); + EnableOpenGLLights(rasty); else DisableOpenGLLights(); } -void GPC_RenderTools::EnableOpenGLLights() +void GPC_RenderTools::EnableOpenGLLights(RAS_IRasterizer *rasty) { if(m_lastlighting == true) return; @@ -120,7 +125,8 @@ void GPC_RenderTools::EnableOpenGLLights() glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, true); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (rasty->GetCameraOrtho())? GL_FALSE: GL_TRUE); if (GLEW_EXT_separate_specular_color || GLEW_VERSION_1_2) glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); @@ -279,10 +285,7 @@ void GPC_RenderTools::RenderText2D(RAS_TEXT_RENDER_MODE mode, int height) { STR_String tmpstr(text); - int lines; char* s = tmpstr.Ptr(); - char* p; - // Save and change OpenGL settings int texture2D; @@ -305,28 +308,19 @@ void GPC_RenderTools::RenderText2D(RAS_TEXT_RENDER_MODE mode, glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); - - // Actual drawing - unsigned char colors[2][3] = { - {0x00, 0x00, 0x00}, - {0xFF, 0xFF, 0xFF} - }; - int numTimes = mode == RAS_TEXT_PADDED ? 2 : 1; - for (int i = 0; i < numTimes; i++) { - glColor3ub(colors[i][0], colors[i][1], colors[i][2]); - glRasterPos2i(xco, yco); - for (p = s, lines = 0; *p; p++) { - if (*p == '\n') - { - lines++; - glRasterPos2i(xco, yco-(lines*18)); - } - BMF_DrawCharacter(m_font, *p); - } - xco += 1; - yco += 1; + + // Actual drawing (draw black first if padded) + if (mode == RAS_IRenderTools::RAS_TEXT_PADDED) + { + glColor3ub(0, 0, 0); + glRasterPos2s(xco+1, height-yco-1); + // XXX BMF_DrawString(m_font, s); } + glColor3ub(255, 255, 255); + glRasterPos2s(xco, height-yco); + // XXX BMF_DrawString(m_font, s); + // Restore view settings glMatrixMode(GL_PROJECTION); glPopMatrix(); @@ -391,17 +385,13 @@ void GPC_RenderTools::PopMatrix() int GPC_RenderTools::applyLights(int objectlayer, const MT_Transform& viewmat) { // taken from blender source, incompatibility between Blender Object / GameObject + KX_Scene* kxscene = (KX_Scene*)m_auxilaryClientInfo; float glviewmat[16]; unsigned int count; - float vec[4]; + std::vector<struct RAS_LightObject*>::iterator lit = m_lights.begin(); - vec[3]= 1.0; - for(count=0; count<m_numgllights; count++) glDisable((GLenum)(GL_LIGHT0+count)); - - //std::vector<struct RAS_LightObject*> m_lights; - std::vector<struct RAS_LightObject*>::iterator lit = m_lights.begin(); viewmat.getValue(glviewmat); @@ -410,76 +400,14 @@ int GPC_RenderTools::applyLights(int objectlayer, const MT_Transform& viewmat) for (lit = m_lights.begin(), count = 0; !(lit==m_lights.end()) && count < m_numgllights; ++lit) { RAS_LightObject* lightdata = (*lit); - if (lightdata->m_layer & objectlayer) - { - vec[0] = (*(lightdata->m_worldmatrix))(0,3); - vec[1] = (*(lightdata->m_worldmatrix))(1,3); - vec[2] = (*(lightdata->m_worldmatrix))(2,3); - vec[3] = 1; - - if(lightdata->m_type==RAS_LightObject::LIGHT_SUN) { - - vec[0] = (*(lightdata->m_worldmatrix))(0,2); - vec[1] = (*(lightdata->m_worldmatrix))(1,2); - vec[2] = (*(lightdata->m_worldmatrix))(2,2); - //vec[0]= base->object->obmat[2][0]; - //vec[1]= base->object->obmat[2][1]; - //vec[2]= base->object->obmat[2][2]; - vec[3]= 0.0; - glLightfv((GLenum)(GL_LIGHT0+count), GL_POSITION, vec); - } - else { - //vec[3]= 1.0; - glLightfv((GLenum)(GL_LIGHT0+count), GL_POSITION, vec); - glLightf((GLenum)(GL_LIGHT0+count), GL_CONSTANT_ATTENUATION, 1.0); - glLightf((GLenum)(GL_LIGHT0+count), GL_LINEAR_ATTENUATION, lightdata->m_att1/lightdata->m_distance); - // without this next line it looks backward compatible. - //attennuation still is acceptable - glLightf((GLenum)(GL_LIGHT0+count), GL_QUADRATIC_ATTENUATION, lightdata->m_att2/(lightdata->m_distance*lightdata->m_distance)); - - if(lightdata->m_type==RAS_LightObject::LIGHT_SPOT) { - vec[0] = -(*(lightdata->m_worldmatrix))(0,2); - vec[1] = -(*(lightdata->m_worldmatrix))(1,2); - vec[2] = -(*(lightdata->m_worldmatrix))(2,2); - //vec[0]= -base->object->obmat[2][0]; - //vec[1]= -base->object->obmat[2][1]; - //vec[2]= -base->object->obmat[2][2]; - glLightfv((GLenum)(GL_LIGHT0+count), GL_SPOT_DIRECTION, vec); - glLightf((GLenum)(GL_LIGHT0+count), GL_SPOT_CUTOFF, lightdata->m_spotsize/2.0); - glLightf((GLenum)(GL_LIGHT0+count), GL_SPOT_EXPONENT, 128.0*lightdata->m_spotblend); - } - else glLightf((GLenum)(GL_LIGHT0+count), GL_SPOT_CUTOFF, 180.0); - } - - if (lightdata->m_nodiffuse) - { - vec[0] = vec[1] = vec[2] = vec[3] = 0.0; - } else { - vec[0]= lightdata->m_energy*lightdata->m_red; - vec[1]= lightdata->m_energy*lightdata->m_green; - vec[2]= lightdata->m_energy*lightdata->m_blue; - vec[3]= 1.0; - } - glLightfv((GLenum)(GL_LIGHT0+count), GL_DIFFUSE, vec); - if (lightdata->m_nospecular) - { - vec[0] = vec[1] = vec[2] = vec[3] = 0.0; - } else if (lightdata->m_nodiffuse) { - vec[0]= lightdata->m_energy*lightdata->m_red; - vec[1]= lightdata->m_energy*lightdata->m_green; - vec[2]= lightdata->m_energy*lightdata->m_blue; - vec[3]= 1.0; - } - glLightfv((GLenum)(GL_LIGHT0+count), GL_SPECULAR, vec); - glEnable((GLenum)(GL_LIGHT0+count)); + KX_LightObject *kxlight = (KX_LightObject*)lightdata->m_light; + if(kxlight->ApplyLight(kxscene, objectlayer, count)) count++; - } } glPopMatrix(); return count; - } void GPC_RenderTools::MotionBlur(RAS_IRasterizer* rasterizer) diff --git a/source/gameengine/GamePlayer/common/GPC_RenderTools.h b/source/gameengine/GamePlayer/common/GPC_RenderTools.h index 382956e73ea..478d8b1a3c5 100644 --- a/source/gameengine/GamePlayer/common/GPC_RenderTools.h +++ b/source/gameengine/GamePlayer/common/GPC_RenderTools.h @@ -38,8 +38,6 @@ #include "RAS_IRenderTools.h" -#include "BMF_Api.h" - struct KX_ClientObjectInfo; class KX_RayCast; @@ -54,9 +52,10 @@ class GPC_RenderTools : public RAS_IRenderTools { int m_lastlightlayer; bool m_lastlighting; + void *m_lastauxinfo; static unsigned int m_numgllights; - BMF_Font* m_font; +// XXX BMF_Font* m_font; public: GPC_RenderTools(); @@ -65,9 +64,9 @@ public: void EndFrame(RAS_IRasterizer* rasty); void BeginFrame(RAS_IRasterizer* rasty); - void EnableOpenGLLights(); + void EnableOpenGLLights(RAS_IRasterizer *rasty); void DisableOpenGLLights(); - void ProcessLighting(int layer, const MT_Transform& viewmat); + void ProcessLighting(RAS_IRasterizer *rasty, bool uselights, const MT_Transform& viewmat); /* @attention mode is ignored here */ void RenderText2D(RAS_TEXT_RENDER_MODE mode, diff --git a/source/gameengine/GamePlayer/common/Makefile b/source/gameengine/GamePlayer/common/Makefile index 6a12e659be6..e1b07a226f6 100644 --- a/source/gameengine/GamePlayer/common/Makefile +++ b/source/gameengine/GamePlayer/common/Makefile @@ -47,17 +47,13 @@ CPPFLAGS += -I../../../blender/gpu CPPFLAGS += -I../../../kernel/gen_system CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include -CPPFLAGS += -I$(NAN_FUZZICS)/include CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include -CPPFLAGS += -I$(NAN_SUMO)/include -CPPFLAGS += -I$(NAN_SOLID)/include CPPFLAGS += -I$(NAN_PNG)/include CPPFLAGS += -I$(NAN_ZLIB)/include CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) +CPPFLAGS += -I$(NAN_AUDASPACE)/include -CPPFLAGS += -I$(NAN_BMFONT)/include -CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include CPPFLAGS += -I../../../gameengine/Converter CPPFLAGS += -I../../../gameengine/Expressions CPPFLAGS += -I../../../gameengine/GameLogic @@ -70,7 +66,6 @@ CPPFLAGS += -I../../../gameengine/Network/LoopBackNetwork CPPFLAGS += -I../../../gameengine/Rasterizer CPPFLAGS += -I../../../gameengine/SceneGraph CPPFLAGS += -I../../../gameengine/Rasterizer/RAS_OpenGLRasterizer -CPPFLAGS += -I../../../gameengine/Physics/Sumo CPPFLAGS += -I../../../gameengine/Physics/common ############################### diff --git a/source/gameengine/GamePlayer/common/SConscript b/source/gameengine/GamePlayer/common/SConscript index 30f20a670d3..dd5a48c2b55 100644 --- a/source/gameengine/GamePlayer/common/SConscript +++ b/source/gameengine/GamePlayer/common/SConscript @@ -18,9 +18,7 @@ incs = ['.', '#intern/string', '#intern/ghost', '#intern/guardedalloc', - '#intern/bmfont', '#intern/moto/include', - '#intern/SoundSystem', '#source/gameengine/Rasterizer/RAS_OpenGLRasterizer', '#source/kernel/gen_system', '#source/kernel/gen_messaging', @@ -39,15 +37,13 @@ incs = ['.', '#source/gameengine/Network', '#source/gameengine/SceneGraph', '#source/gameengine/Physics/common', - '#source/gameengine/Physics/Sumo', - '#source/gameengine/Physics/Sumo/Fuzzics/include', '#source/gameengine/Network/LoopBackNetwork', '#source/gameengine/GamePlayer/ghost', '#source/blender/misc', '#source/blender/blenloader', '#source/blender/gpu', '#extern/glew/include'] - + #This is all plugin stuff! #if sys.platform=='win32': # source_files += ['windows/GPW_Canvas.cpp', @@ -63,12 +59,7 @@ incs = ['.', # gp_common_env.Append ( CPPPATH = ['unix']) incs += Split(env['BF_PYTHON_INC']) -incs += Split(env['BF_SOLID_INC']) incs += Split(env['BF_PNG_INC']) incs += Split(env['BF_ZLIB_INC']) -cflags=[] -if env['OURPLATFORM']=='win32-vc': - cflags = ['/GR'] - -env.BlenderLib (libname='gp_common', sources=source_files, includes=incs, defines = [], libtype='player', priority=5, compileflags=cflags) +env.BlenderLib (libname='gp_common', sources=source_files, includes=incs, defines = [], libtype=['player'], priority=[5], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/GamePlayer/common/unix/GPU_Engine.cpp b/source/gameengine/GamePlayer/common/unix/GPU_Engine.cpp index a5dec02c753..0ef087efbfe 100644 --- a/source/gameengine/GamePlayer/common/unix/GPU_Engine.cpp +++ b/source/gameengine/GamePlayer/common/unix/GPU_Engine.cpp @@ -44,9 +44,6 @@ #include "NG_LoopBackNetworkDeviceInterface.h" #include "SND_DeviceManager.h" #include "KX_BlenderSceneConverter.h" -#ifdef USE_SUMO_SOLID - #include "SM_Scene.h" -#endif #include "KX_KetsjiEngine.h" #include "GPC_RenderTools.h" diff --git a/source/gameengine/GamePlayer/common/unix/Makefile b/source/gameengine/GamePlayer/common/unix/Makefile index a2bdb7225a0..c86f61b45d8 100644 --- a/source/gameengine/GamePlayer/common/unix/Makefile +++ b/source/gameengine/GamePlayer/common/unix/Makefile @@ -35,6 +35,7 @@ include nan_compile.mk CCFLAGS += $(LEVEL_1_CPP_WARNINGS) +CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) CPPFLAGS += -I$(NAN_STRING)/include @@ -55,12 +56,7 @@ CPPFLAGS += -I../../../../gameengine/Rasterizer CPPFLAGS += -I../../../../gameengine/Rasterizer/RAS_OpenGLRasterizer CPPFLAGS += -I../../../../gameengine/SceneGraph -CPPFLAGS += -I$(NAN_FUZZICS)/include -CPPFLAGS += -I$(NAN_SUMO)/include -CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include CPPFLAGS += -I$(NAN_MOTO)/include -CPPFLAGS += -I$(NAN_BMFONT)/include -CPPFLAGS += -I$(NAN_SOLID)/include # Blender stuff CPPFLAGS += -I../../../../blender/blenkernel diff --git a/source/gameengine/GamePlayer/common/windows/Makefile b/source/gameengine/GamePlayer/common/windows/Makefile index b0fb25f35b8..3f1deb05f3a 100644 --- a/source/gameengine/GamePlayer/common/windows/Makefile +++ b/source/gameengine/GamePlayer/common/windows/Makefile @@ -48,8 +48,7 @@ CPPFLAGS += -I$(SRCHOME)/gameengine/Physics/Sumo/include CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I$(NAN_STRING)/include -CPPFLAGS += -I$(NAN_BMFONT)/include -CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include +CPPFLAGS += -I$(NAN_GLEW)/include # Blender stuff CPPFLAGS += -I$(SRCHOME)/blender/blenkernel diff --git a/source/gameengine/GamePlayer/ghost/CMakeLists.txt b/source/gameengine/GamePlayer/ghost/CMakeLists.txt index 5e0ca93ac06..d50784cb967 100644 --- a/source/gameengine/GamePlayer/ghost/CMakeLists.txt +++ b/source/gameengine/GamePlayer/ghost/CMakeLists.txt @@ -25,50 +25,50 @@ # ***** END GPL LICENSE BLOCK ***** SET(SRC - GPG_Application.cpp - GPG_Canvas.cpp - GPG_ghost.cpp - GPG_KeyboardDevice.cpp - GPG_System.cpp + GPG_Application.cpp + GPG_Canvas.cpp + GPG_ghost.cpp + GPG_KeyboardDevice.cpp + GPG_System.cpp ) SET(INC - . - ../../../../intern/string - ../../../../intern/ghost - ../../../../intern/guardedalloc - ../../../../intern/bmfont - ../../../../intern/moto/include - ../../../../intern/SoundSystem - ../../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../../source/kernel/gen_system - ../../../../source/kernel/gen_messaging - ../../../../source/gameengine/Converter - ../../../../source/blender/imbuf - ../../../../source/gameengine/Ketsji - ../../../../source/blender/blenlib - ../../../../source/blender/blenkernel - ../../../../source/blender/readblenfile - ../../../../source/blender - ../../../../source/blender/include - ../../../../source/blender/makesdna - ../../../../source/gameengine/Rasterizer - ../../../../source/gameengine/GameLogic - ../../../../source/gameengine/Expressions - ../../../../source/gameengine/Network - ../../../../source/gameengine/SceneGraph - ../../../../source/gameengine/Physics/common - ../../../../source/gameengine/Physics/Sumo - ../../../../source/gameengine/Physics/Sumo/Fuzzics/include - ../../../../source/gameengine/Network/LoopBackNetwork - ../../../../source/gameengine/GamePlayer/common - ../../../../source/blender/misc - ../../../../source/blender/blenloader - ../../../../source/blender/gpu - ../../../../extern/solid - ../../../../extern/glew/include - ${PYTHON_INC} + . + ../../../../intern/string + ../../../../intern/ghost + ../../../../intern/guardedalloc + ../../../../intern/moto/include + ../../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer + ../../../../source/kernel/gen_system + ../../../../source/kernel/gen_messaging + ../../../../source/gameengine/Converter + ../../../../source/blender/imbuf + ../../../../source/gameengine/Ketsji + ../../../../source/blender/blenlib + ../../../../source/blender/blenkernel + ../../../../source/blender/readblenfile + ../../../../source/blender + ../../../../source/blender/include + ../../../../source/blender/makesdna + ../../../../source/blender/makesrna + ../../../../source/gameengine/Rasterizer + ../../../../source/gameengine/GameLogic + ../../../../source/gameengine/Expressions + ../../../../source/gameengine/Network + ../../../../source/gameengine/SceneGraph + ../../../../source/gameengine/Physics/common + ../../../../source/gameengine/Network/LoopBackNetwork + ../../../../source/gameengine/GamePlayer/common + ../../../../source/blender/misc + ../../../../source/blender/blenloader + ../../../../source/blender/gpu + ../../../../extern/glew/include + ${PYTHON_INC} ) +IF(WITH_FFMPEG) + ADD_DEFINITIONS(-DWITH_FFMPEG) +ENDIF(WITH_FFMPEG) + BLENDERLIB_NOLIST(gp_ghost "${SRC}" "${INC}") #env.BlenderLib (libname='gp_ghost', sources=source_files, includes = incs, defines = [], libtype='player',priority=0, compileflags=cflags) diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index a9196a1a5e3..8ec41968042 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -57,6 +57,7 @@ extern "C" #include "BLO_readfile.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_sound.h" #include "IMB_imbuf.h" #include "DNA_scene_types.h" #ifdef __cplusplus @@ -84,7 +85,6 @@ extern "C" #include "KX_BlenderSceneConverter.h" #include "NG_LoopBackNetworkDeviceInterface.h" -#include "SND_DeviceManager.h" #include "GPC_MouseDevice.h" #include "GPC_RenderTools.h" @@ -125,8 +125,7 @@ GPG_Application::GPG_Application(GHOST_ISystem* system) m_rendertools(0), m_rasterizer(0), m_sceneconverter(0), - m_networkdevice(0), - m_audiodevice(0), + m_networkdevice(0), m_blendermat(0), m_blenderglslmat(0), m_pyGlobalDictString(0), @@ -151,18 +150,22 @@ GPG_Application::~GPG_Application(void) -bool GPG_Application::SetGameEngineData(struct Main* maggie, Scene *scene) +bool GPG_Application::SetGameEngineData(struct Main* maggie, Scene *scene, int argc, char **argv) { bool result = false; if (maggie != NULL && scene != NULL) { - G.scene = scene; +// XXX G.scene = scene; m_maggie = maggie; m_startSceneName = scene->id.name+2; m_startScene = scene; result = true; } + + /* Python needs these */ + m_argc= argc; + m_argv= argv; return result; } @@ -208,7 +211,7 @@ static LRESULT CALLBACK screenSaverWindowProc(HWND hwnd, UINT uMsg, WPARAM wPara BOOL CALLBACK findGhostWindowHWNDProc(HWND hwnd, LPARAM lParam) { - GHOST_IWindow *p = (GHOST_IWindow*) GetWindowLong(hwnd, GWL_USERDATA); + GHOST_IWindow *p = (GHOST_IWindow*) GetWindowLongPtr(hwnd, GWLP_USERDATA); BOOL ret = TRUE; if (p == ghost_window_to_find) { @@ -292,8 +295,8 @@ bool GPG_Application::startScreenSaverFullScreen( if (ghost_hwnd != NULL) { GetCursorPos(&scr_save_mouse_pos); - ghost_wnd_proc = (WNDPROC) GetWindowLong(ghost_hwnd, GWL_WNDPROC); - SetWindowLong(ghost_hwnd,GWL_WNDPROC, (LONG) screenSaverWindowProc); + ghost_wnd_proc = (WNDPROC) GetWindowLongPtr(ghost_hwnd, GWLP_WNDPROC); + SetWindowLongPtr(ghost_hwnd,GWLP_WNDPROC, (uintptr_t) screenSaverWindowProc); } } return ret; @@ -520,23 +523,25 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) // SYS_WriteCommandLineInt(syshandle, "fixedtime", 0); // SYS_WriteCommandLineInt(syshandle, "vertexarrays",1); + GameData *gm= &m_startScene->gm; bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0); bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0); - bool fixedFr = (G.fileflags & G_FILE_ENABLE_ALL_FRAMES); + bool fixedFr = (gm->flag & GAME_ENABLE_ALL_FRAMES); - bool showPhysics = (G.fileflags & G_FILE_SHOW_PHYSICS); + bool showPhysics = (gm->flag & GAME_SHOW_PHYSICS); SYS_WriteCommandLineInt(syshandle, "show_physics", showPhysics); bool fixed_framerate= (SYS_GetCommandLineInt(syshandle, "fixed_framerate", fixedFr) != 0); bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0); - bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", G.fileflags & G_FILE_DISPLAY_LISTS) != 0); + bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", gm->flag & GAME_DISPLAY_LISTS) != 0); + bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 1) != 0); if(GLEW_ARB_multitexture && GLEW_VERSION_1_1) m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0); if(GPU_extensions_minimum_support()) m_blenderglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0); - else if(G.fileflags & G_FILE_GAME_MAT_GLSL) + else if(gm->matmode == GAME_MAT_GLSL) m_blendermat = false; // create the canvas, rasterizer and rendertools @@ -578,13 +583,8 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) if (!m_networkdevice) goto initFailed; - // get an audiodevice - SND_DeviceManager::Subscribe(); - m_audiodevice = SND_DeviceManager::Instance(); - if (!m_audiodevice) - goto initFailed; - m_audiodevice->UseCD(); - + sound_init(); + // create a ketsjisystem (only needed for timing and stuff) m_kxsystem = new GPG_System (m_system); if (!m_kxsystem) @@ -601,9 +601,11 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) m_ketsjiengine->SetRenderTools(m_rendertools); m_ketsjiengine->SetRasterizer(m_rasterizer); m_ketsjiengine->SetNetworkDevice(m_networkdevice); - m_ketsjiengine->SetAudioDevice(m_audiodevice); + m_ketsjiengine->SetTimingDisplay(frameRate, false, false); + CValue::SetDeprecationWarnings(nodepwarnings); + m_ketsjiengine->SetUseFixedTime(fixed_framerate); m_ketsjiengine->SetTimingDisplay(frameRate, profile, properties); @@ -612,8 +614,8 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) return m_engineInitialized; initFailed: + sound_exit(); delete m_kxsystem; - delete m_audiodevice; delete m_networkdevice; delete m_mouse; delete m_keyboard; @@ -626,7 +628,6 @@ initFailed: m_keyboard = NULL; m_mouse = NULL; m_networkdevice = NULL; - m_audiodevice = NULL; m_kxsystem = NULL; return false; } @@ -643,7 +644,7 @@ bool GPG_Application::startEngine(void) /* m_canvas->SetBannerDisplayEnabled(true); Camera* cam; - cam = (Camera*)G.scene->camera->data; + cam = (Camera*)scene->camera->data; if (cam) { if (((cam->flag) & 48)==48) { m_canvas->SetBannerDisplayEnabled(false); @@ -656,7 +657,7 @@ bool GPG_Application::startEngine(void) */ // create a scene converter, create and convert the stratingscene - m_sceneconverter = new KX_BlenderSceneConverter(m_maggie,0, m_ketsjiengine); + m_sceneconverter = new KX_BlenderSceneConverter(m_maggie, m_ketsjiengine); if (m_sceneconverter) { STR_String startscenename = m_startSceneName.Ptr(); @@ -664,21 +665,20 @@ bool GPG_Application::startEngine(void) // if (always_use_expand_framing) // sceneconverter->SetAlwaysUseExpandFraming(true); - if(m_blendermat && (G.fileflags & G_FILE_GAME_MAT)) + if(m_blendermat && (m_startScene->gm.matmode != GAME_MAT_TEXFACE)) m_sceneconverter->SetMaterials(true); - if(m_blenderglslmat && (G.fileflags & G_FILE_GAME_MAT_GLSL)) + if(m_blenderglslmat && (m_startScene->gm.matmode == GAME_MAT_GLSL)) m_sceneconverter->SetGLSLMaterials(true); KX_Scene* startscene = new KX_Scene(m_keyboard, m_mouse, m_networkdevice, - m_audiodevice, startscenename, m_startScene); // some python things - PyObject* dictionaryobject = initGamePlayerPythonScripting("Ketsji", psl_Lowest); + PyObject* dictionaryobject = initGamePlayerPythonScripting("Ketsji", psl_Lowest, m_maggie, m_argc, m_argv); m_ketsjiengine->SetPythonDictionary(dictionaryobject); initRasterizer(m_rasterizer, m_canvas); PyObject *gameLogic = initGameLogic(m_ketsjiengine, startscene); @@ -686,16 +686,23 @@ bool GPG_Application::startEngine(void) initGameKeys(); initPythonConstraintBinding(); initMathutils(); + initGeometry(); + initBGL(); +#ifdef WITH_FFMPEG + initVideoTexture(); +#endif + + //initialize Dome Settings + if(m_startScene->gm.stereoflag == STEREO_DOME) + 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); // Set the GameLogic.globalDict from marshal'd data, so we can // load new blend files and keep data in GameLogic.globalDict loadGamePythonConfig(m_pyGlobalDictString, m_pyGlobalDictString_Length); m_sceneconverter->ConvertScene( - startscenename, startscene, dictionaryobject, - m_keyboard, m_rendertools, m_canvas); m_ketsjiengine->AddScene(startscene); @@ -711,7 +718,7 @@ bool GPG_Application::startEngine(void) // Set the animation playback rate for ipo's and actions // the framerate below should patch with FPS macro defined in blendef.h // Could be in StartEngine set the framerate, we need the scene to do this - m_ketsjiengine->SetAnimFrameRate( (((double) G.scene->r.frs_sec) / G.scene->r.frs_sec_base) ); +// XXX m_ketsjiengine->SetAnimFrameRate( (((double) scene->r.frs_sec) / scene->r.frs_sec_base) ); } @@ -755,6 +762,7 @@ void GPG_Application::stopEngine() void GPG_Application::exitEngine() { + sound_exit(); if (m_ketsjiengine) { stopEngine(); @@ -766,11 +774,6 @@ void GPG_Application::exitEngine() delete m_kxsystem; m_kxsystem = 0; } - if (m_audiodevice) - { - SND_DeviceManager::Unsubscribe(); - m_audiodevice = 0; - } if (m_networkdevice) { delete m_networkdevice; diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.h b/source/gameengine/GamePlayer/ghost/GPG_Application.h index 38408f919b4..73430213078 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.h +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.h @@ -38,7 +38,6 @@ class KX_KetsjiEngine; class KX_ISceneConverter; class NG_LoopBackNetworkDeviceInterface; -class SND_IAudioDevice; class RAS_IRasterizer; class GHOST_IEvent; class GHOST_ISystem; @@ -58,7 +57,7 @@ public: GPG_Application(GHOST_ISystem* system); ~GPG_Application(void); - bool SetGameEngineData(struct Main* maggie, struct Scene* scene); + bool SetGameEngineData(struct Main* maggie, struct Scene* scene, int argc, char** argv); bool startWindow(STR_String& title, int windowLeft, int windowTop, int windowWidth, int windowHeight, const bool stereoVisual, const int stereoMode); bool startFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode); @@ -142,8 +141,6 @@ protected: KX_ISceneConverter* m_sceneconverter; /** Network interface. */ NG_LoopBackNetworkDeviceInterface* m_networkdevice; - /** Sound device. */ - SND_IAudioDevice* m_audiodevice; bool m_blendermat; bool m_blenderglslmat; @@ -154,5 +151,9 @@ protected: */ char* m_pyGlobalDictString; int m_pyGlobalDictString_Length; + + /* argc and argv need to be passed on to python */ + int m_argc; + char** m_argv; }; diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index 0bf0317d8f2..fb2e1c72a85 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -58,14 +58,19 @@ extern "C" #include "BKE_global.h" #include "BKE_icons.h" #include "BKE_node.h" +#include "BKE_report.h" #include "BLI_blenlib.h" #include "DNA_scene_types.h" +#include "DNA_userdef_types.h" #include "BLO_readfile.h" #include "BLO_readblenfile.h" #include "IMB_imbuf.h" int GHOST_HACK_getFirstFile(char buf[]); +extern char bprogname[]; /* holds a copy of argv[0], from creator.c */ +extern char btempdir[]; /* use this to store a valid temp directory */ + #ifdef __cplusplus } #endif // __cplusplus @@ -85,6 +90,8 @@ extern "C" #include "BKE_main.h" #include "BKE_utildefines.h" +#include "RNA_define.h" + #ifdef WIN32 #include <windows.h> #ifdef NDEBUG @@ -162,45 +169,53 @@ void usage(const char* program) consoleoption = ""; #endif - printf("usage: %s [-w [-p l t w h]] %s[-g gamengineoptions] " + printf("usage: %s [-w [w h l t]] [-f [fw fh fb ff]] %s[-g gamengineoptions] " "[-s stereomode] filename.blend\n", program, consoleoption); - printf(" -h: Prints this command summary\n"); + printf(" -h: Prints this command summary\n\n"); printf(" -w: display in a window\n"); - printf(" -p: specify window position\n"); + printf(" --Optional parameters--\n"); + printf(" w = window width\n"); + printf(" h = window height\n\n"); printf(" l = window left coordinate\n"); printf(" t = window top coordinate\n"); - printf(" w = window width\n"); - printf(" h = window height\n"); + printf(" Note: If w or h is defined, both must be defined.\n"); + printf(" Also, if l or t is defined, all options must be used.\n\n"); printf(" -f: start game in full screen mode\n"); + printf(" --Optional parameters--\n"); printf(" fw = full screen mode pixel width\n"); - printf(" fh = full screen mode pixel height\n"); + printf(" fh = full screen mode pixel height\n\n"); printf(" fb = full screen mode bits per pixel\n"); printf(" ff = full screen mode frequency\n"); + printf(" Note: If fw or fh is defined, both must be defined.\n"); + printf(" Also, if fb is used, fw and fh must be used. ff requires all options.\n\n"); printf(" -s: start player in stereo\n"); printf(" stereomode: hwpageflip (Quad buffered shutter glasses)\n"); printf(" syncdoubling (Above Below)\n"); printf(" sidebyside (Left Right)\n"); printf(" anaglyph (Red-Blue glasses)\n"); printf(" vinterlace (Vertical interlace for autostereo display)\n"); - printf(" depending on the type of stereo you want\n"); + printf(" depending on the type of stereo you want\n\n"); #ifndef _WIN32 - printf(" -i: parent windows ID \n"); + printf(" -i: parent windows ID \n\n"); #endif #ifdef _WIN32 - printf(" -c: keep console window open\n"); + printf(" -c: keep console window open\n\n"); #endif - printf(" -d: turn debugging on\n"); - printf(" -g: game engine options:\n"); - printf(" Name Default Description\n"); - printf(" ----------------------------------------\n"); - printf(" fixedtime 0 Do the same timestep each frame \"Enable all frames\"\n"); - printf(" nomipmap 0 Disable mipmaps\n"); - printf(" show_framerate 0 Show the frame rate\n"); - printf(" show_properties 0 Show debug properties\n"); - printf(" show_profile 0 Show profiling information\n"); - printf(" blender_material 0 Enable material settings\n"); + printf(" -d: turn debugging on\n\n"); + printf(" -g: game engine options:\n\n"); + printf(" Name Default Description\n"); + printf(" ------------------------------------------------------------------------\n"); + printf(" fixedtime 0 \"Enable all frames\"\n"); + printf(" nomipmap 0 Disable mipmaps\n"); + printf(" show_framerate 0 Show the frame rate\n"); + printf(" show_properties 0 Show debug properties\n"); + printf(" show_profile 0 Show profiling information\n"); + printf(" blender_material 0 Enable material settings\n"); + printf(" ignore_deprecation_warnings 1 Ignore deprecation warnings\n"); + printf("\n"); + printf(" - : all arguments after this are ignored, allowing python to access them from sys.argv\n"); printf("\n"); - printf("example: %s -p 10 10 320 200 -g noaudio c:\\loadtest.blend\n", program); + printf("example: %s -w 320 200 10 10 -g noaudio c:\\loadtest.blend\n", program); printf("example: %s -g show_framerate = 0 c:\\loadtest.blend\n", program); } @@ -240,7 +255,7 @@ static void get_filename(int argc, char **argv, char *filename) if (BLI_exists(gamefile)) BLI_strncpy(filename, gamefile, FILE_MAXDIR + FILE_MAXFILE); - delete gamefile; + delete [] gamefile; } #else @@ -251,35 +266,33 @@ static void get_filename(int argc, char **argv, char *filename) #endif // !_APPLE } -static BlendFileData *load_game_data(char *progname, char *filename = NULL, char *relativename = NULL) { - BlendReadError error; +static BlendFileData *load_game_data(char *progname, char *filename = NULL, char *relativename = NULL) +{ + ReportList reports; BlendFileData *bfd = NULL; + + BKE_reports_init(&reports, RPT_STORE); /* try to load ourself, will only work if we are a runtime */ if (blo_is_a_runtime(progname)) { - bfd= blo_read_runtime(progname, &error); + bfd= blo_read_runtime(progname, &reports); if (bfd) { bfd->type= BLENFILETYPE_RUNTIME; strcpy(bfd->main->name, progname); } } else { - bfd= BLO_read_from_file(progname, &error); - } - - /* - if (bfd && bfd->type == BLENFILETYPE_BLEND) { - BLO_blendfiledata_free(bfd); - bfd = NULL; - error = BRE_NOT_A_PUBFILE; + bfd= BLO_read_from_file(progname, &reports); } - */ if (!bfd && filename) { bfd = load_game_data(filename); if (!bfd) { - printf("Loading %s failed: %s\n", filename, BLO_bre_as_string(error)); + printf("Loading %s failed: ", filename); + BKE_reports_print(&reports, RPT_ERROR); } } + + BKE_reports_clear(&reports); return bfd; } @@ -287,6 +300,7 @@ static BlendFileData *load_game_data(char *progname, char *filename = NULL, char int main(int argc, char** argv) { int i; + int argc_py_clamped= argc; /* use this so python args can be added after ' - ' */ bool error = false; SYS_SystemHandle syshandle = SYS_GetSystem(); bool fullScreen = false; @@ -336,6 +350,8 @@ int main(int argc, char** argv) */ #endif // __APPLE__ + RNA_init(); + init_nodesystem(); initglobals(); @@ -375,6 +391,13 @@ int main(int argc, char** argv) } } #endif + // XXX add the ability to change this values to the command line parsing. + U.mixbufsize = 2048; + U.audiodevice = 2; + U.audiorate = 44100; + U.audioformat = 0x24; + U.audiochannels = 2; + for (i = 1; (i < argc) && !error #ifdef WIN32 && scr_saver_mode == SCREEN_SAVER_MODE_NONE @@ -387,6 +410,12 @@ int main(int argc, char** argv) #endif if (argv[i][0] == '-') { + /* ignore all args after " - ", allow python to have own args */ + if (argv[i][1]=='\0') { + argc_py_clamped= i; + break; + } + switch (argv[i][1]) { case 'g': @@ -431,54 +460,41 @@ int main(int argc, char** argv) G.f |= G_DEBUG; /* std output printf's */ MEM_set_memory_debug(); break; - - case 'p': - // Parse window position and size options - if (argv[i][2] == 0) { - i++; - if ((i + 4) < argc) - { - windowLeft = atoi(argv[i++]); - windowTop = atoi(argv[i++]); - windowWidth = atoi(argv[i++]); - windowHeight = atoi(argv[i++]); - windowParFound = true; - } - else - { - error = true; - printf("error: too few options for window argument.\n"); - } - } else { /* mac specific */ - - if (strncmp(argv[i], "-psn_", 5)==0) - i++; /* skip process serial number */ - } - break; + case 'f': i++; fullScreen = true; fullScreenParFound = true; - if ((i + 2) < argc && argv[i][0] != '-' && argv[i+1][0] != '-') + if ((i + 2) <= argc && argv[i][0] != '-' && argv[i+1][0] != '-') { fullScreenWidth = atoi(argv[i++]); fullScreenHeight = atoi(argv[i++]); - if ((i + 1) < argc && argv[i][0] != '-') + if ((i + 1) <= argc && argv[i][0] != '-') { fullScreenBpp = atoi(argv[i++]); - if ((i + 1) < argc && argv[i][0] != '-') + if ((i + 1) <= argc && argv[i][0] != '-') fullScreenFrequency = atoi(argv[i++]); } } break; case 'w': // Parse window position and size options + i++; + fullScreen = false; + windowParFound = true; + + if ((i + 2) <= argc && argv[i][0] != '-' && argv[i+1][0] != '-') { - fullScreen = false; - fullScreenParFound = true; - i++; + windowWidth = atoi(argv[i++]); + windowHeight = atoi(argv[i++]); + if ((i +2) <= argc && argv[i][0] != '-' && argv[i+1][0] != '-') + { + windowLeft = atoi(argv[i++]); + windowTop = atoi(argv[i++]); + } } break; + case 'h': usage(argv[0]); return 0; @@ -603,7 +619,7 @@ int main(int argc, char** argv) char pathname[FILE_MAXDIR + FILE_MAXFILE]; char *titlename; - get_filename(argc, argv, filename); + get_filename(argc_py_clamped, argv, filename); if(filename[0]) BLI_convertstringcwd(filename); @@ -698,14 +714,14 @@ int main(int argc, char** argv) } // GPG_Application app (system, maggie, startscenename); - app.SetGameEngineData(maggie, scene); + app.SetGameEngineData(maggie, scene, argc, argv); /* this argc cant be argc_py_clamped, since python uses it */ BLI_strncpy(pathname, maggie->name, sizeof(pathname)); BLI_strncpy(G.sce, maggie->name, sizeof(G.sce)); + setGamePythonPath(G.sce); if (firstTimeRunning) { - setGamePythonPath(G.sce); firstTimeRunning = false; if (fullScreen) diff --git a/source/gameengine/GamePlayer/ghost/Makefile b/source/gameengine/GamePlayer/ghost/Makefile index 52e219db8f2..a7fcf46b695 100644 --- a/source/gameengine/GamePlayer/ghost/Makefile +++ b/source/gameengine/GamePlayer/ghost/Makefile @@ -39,8 +39,6 @@ CCFLAGS += $(LEVEL_1_CPP_WARNINGS) CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) CPPFLAGS += -I$(NAN_STRING)/include -CPPFLAGS += -I$(NAN_BMFONT)/include -CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I../../GamePlayer/common @@ -69,6 +67,7 @@ CPPFLAGS += -I../../../blender/blenlib CPPFLAGS += -I../../../blender/blenloader CPPFLAGS += -I../../../blender/imbuf CPPFLAGS += -I../../../blender/makesdna +CPPFLAGS += -I../../../blender/makesrna CPPFLAGS += -I../../../blender/readblenfile CPPFLAGS += -I../../../blender/gpu @@ -82,3 +81,6 @@ CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_GHOST)/include CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) +ifeq ($(WITH_FFMPEG), true) + CPPFLAGS += -DWITH_FFMPEG +endif diff --git a/source/gameengine/GamePlayer/ghost/SConscript b/source/gameengine/GamePlayer/ghost/SConscript index 33cf07b6211..fdd7792b72a 100644 --- a/source/gameengine/GamePlayer/ghost/SConscript +++ b/source/gameengine/GamePlayer/ghost/SConscript @@ -12,9 +12,7 @@ incs = ['.', '#intern/string', '#intern/ghost', '#intern/guardedalloc', - '#intern/bmfont', '#intern/moto/include', - '#intern/SoundSystem', '#source/gameengine/Rasterizer/RAS_OpenGLRasterizer', '#source/kernel/gen_system', '#source/kernel/gen_messaging', @@ -27,6 +25,7 @@ incs = ['.', '#source/blender', '#source/blender/include', '#source/blender/makesdna', + '#source/blender/makesrna', '#source/gameengine/BlenderRoutines', '#source/gameengine/Rasterizer', '#source/gameengine/GameLogic', @@ -34,8 +33,6 @@ incs = ['.', '#source/gameengine/Network', '#source/gameengine/SceneGraph', '#source/gameengine/Physics/common', - '#source/gameengine/Physics/Sumo', - '#source/gameengine/Physics/Sumo/Fuzzics/include', '#source/gameengine/Network/LoopBackNetwork', '#source/gameengine/GamePlayer/common', '#source/blender/misc', @@ -44,10 +41,9 @@ incs = ['.', '#extern/glew/include'] incs += Split(env['BF_PYTHON_INC']) -incs += Split(env['BF_SOLID_INC']) -cflags = [] -if env['OURPLATFORM']=='win32-vc': - cflags = ['/GR'] +defs = [] +if env['WITH_BF_FFMPEG']: + defs.append('WITH_FFMPEG') -env.BlenderLib (libname='gp_ghost', sources=source_files, includes = incs, defines = [], libtype='player',priority=0, compileflags=cflags) +env.BlenderLib (libname='gp_ghost', sources=source_files, includes = incs, defines = defs, libtype=['player'],priority=[0], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp index 8ec463be6ff..109a693ec6d 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.cpp +++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp @@ -20,41 +20,33 @@ BL_BlenderShader::BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lig : mScene(scene), mMat(ma), - mLightLayer(lightlayer) + mLightLayer(lightlayer), + mGPUMat(NULL) { mBlenderScene = scene->GetBlenderScene(); mBlendMode = GPU_BLEND_SOLID; - if(mMat) - GPU_material_from_blender(mBlenderScene, mMat); + ReloadMaterial(); } BL_BlenderShader::~BL_BlenderShader() { - if(mMat && GPU_material_from_blender(mBlenderScene, mMat)) - GPU_material_unbind(GPU_material_from_blender(mBlenderScene, mMat)); + if(mGPUMat) + GPU_material_unbind(mGPUMat); } -bool BL_BlenderShader::Ok() +void BL_BlenderShader::ReloadMaterial() { - return VerifyShader(); -} - -bool BL_BlenderShader::VerifyShader() -{ - if(mMat) - return (GPU_material_from_blender(mBlenderScene, mMat) != 0); - else - return false; + mGPUMat = (mMat) ? GPU_material_from_blender(mBlenderScene, mMat) : NULL; } void BL_BlenderShader::SetProg(bool enable, double time) { if(VerifyShader()) { if(enable) - GPU_material_bind(GPU_material_from_blender(mBlenderScene, mMat), mLightLayer, ~0, time); + GPU_material_bind(mGPUMat, mLightLayer, mBlenderScene->lay, time, 1); else - GPU_material_unbind(GPU_material_from_blender(mBlenderScene, mMat)); + GPU_material_unbind(mGPUMat); } } @@ -66,7 +58,7 @@ int BL_BlenderShader::GetAttribNum() if(!VerifyShader()) return enabled; - GPU_material_vertex_attributes(GPU_material_from_blender(mBlenderScene, mMat), &attribs); + GPU_material_vertex_attributes(mGPUMat, &attribs); for(i = 0; i < attribs.totlayer; i++) if(attribs.layer[i].glindex+1 > enabled) @@ -89,7 +81,7 @@ void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat) if(!VerifyShader()) return; - gpumat = GPU_material_from_blender(mBlenderScene, mMat); + gpumat = mGPUMat; if(ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) { GPU_material_vertex_attributes(gpumat, &attribs); @@ -131,7 +123,7 @@ void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) float obmat[4][4], viewmat[4][4], viewinvmat[4][4], obcol[4]; GPUMaterial *gpumat; - gpumat = GPU_material_from_blender(mBlenderScene, mMat); + gpumat = mGPUMat; if(!gpumat || !GPU_material_bound(gpumat)) return; diff --git a/source/gameengine/Ketsji/BL_BlenderShader.h b/source/gameengine/Ketsji/BL_BlenderShader.h index 5c1f59f94ad..073ce8f1ca5 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.h +++ b/source/gameengine/Ketsji/BL_BlenderShader.h @@ -32,22 +32,38 @@ private: struct Material *mMat; int mLightLayer; int mBlendMode; + GPUMaterial *mGPUMat; - bool VerifyShader(); + bool VerifyShader() + { + return (NULL != mGPUMat); + } public: BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer); virtual ~BL_BlenderShader(); - bool Ok(); + bool Ok() + { + // same as VerifyShared + return (NULL != mGPUMat); + } void SetProg(bool enable, double time=0.0); int GetAttribNum(); void SetAttribs(class RAS_IRasterizer* ras, const BL_Material *mat); void Update(const class RAS_MeshSlot & ms, class RAS_IRasterizer* rasty); + void ReloadMaterial(); int GetBlendMode(); bool Equals(BL_BlenderShader *blshader); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_BlenderShader"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif//__BL_GPUSHADER_H__ diff --git a/source/gameengine/Ketsji/BL_Material.cpp b/source/gameengine/Ketsji/BL_Material.cpp index 7e3d6984f19..c63b9d55306 100644 --- a/source/gameengine/Ketsji/BL_Material.cpp +++ b/source/gameengine/Ketsji/BL_Material.cpp @@ -28,6 +28,11 @@ int getNumTexChannels( Material *mat ) BL_Material::BL_Material() { + Initialize(); +} + +void BL_Material::Initialize() +{ rgb[0] = 0; rgb[1] = 0; rgb[2] = 0; @@ -52,7 +57,7 @@ BL_Material::BL_Material() mode = 0; material = 0; tface = 0; - material_index = 0; + materialindex = 0; amb=0.5f; num_enabled = 0; num_users = 1; diff --git a/source/gameengine/Ketsji/BL_Material.h b/source/gameengine/Ketsji/BL_Material.h index 0eaa234566c..6b53e7fa8b1 100644 --- a/source/gameengine/Ketsji/BL_Material.h +++ b/source/gameengine/Ketsji/BL_Material.h @@ -4,6 +4,10 @@ #include "STR_String.h" #include "MT_Point2.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + // -- struct MTex; struct Material; @@ -44,6 +48,7 @@ private: public: // ----------------------------------- BL_Material(); + void Initialize(); int IdMode; unsigned int ras_mode; @@ -54,6 +59,7 @@ public: int tile,tilexrep[MAXTEX],tileyrep[MAXTEX]; STR_String matname; STR_String mtexname[MAXTEX]; + int materialindex; float matcolor[4]; float speccolor[3]; @@ -68,8 +74,6 @@ public: int mode; int num_enabled; - int material_index; - BL_Mapping mapping[MAXTEX]; STR_String imageId[MAXTEX]; @@ -98,6 +102,13 @@ public: void SetSharedMaterial(bool v); bool IsShared(); void SetUsers(int num); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_Material"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; // BL_Material::IdMode diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp index 80892764089..f548bcdaae1 100644 --- a/source/gameengine/Ketsji/BL_Shader.cpp +++ b/source/gameengine/Ketsji/BL_Shader.cpp @@ -18,7 +18,7 @@ #define spit(x) std::cout << x << std::endl; #define SORT_UNIFORMS 1 -#define UNIFORM_MAX_LEN sizeof(float)*16 +#define UNIFORM_MAX_LEN (int)sizeof(float)*16 #define MAX_LOG_LEN 262144 // bounds BL_Uniform::BL_Uniform(int data_size) @@ -108,13 +108,13 @@ void BL_Uniform::SetData(int location, int type,bool transpose) #endif } -const bool BL_Shader::Ok()const +bool BL_Shader::Ok()const { return (mShader !=0 && mOk && mUse); } -BL_Shader::BL_Shader(PyTypeObject *T) -: PyObjectPlus(T), +BL_Shader::BL_Shader() +: PyObjectPlus(), mShader(0), mPass(1), mOk(0), @@ -728,13 +728,6 @@ void BL_Shader::SetUniform(int uniform, const int* val, int len) } } - -PyObject* BL_Shader::_getattr(const STR_String& attr) -{ - _getattr_up(PyObjectPlus); -} - - PyMethodDef BL_Shader::Methods[] = { // creation @@ -767,52 +760,54 @@ PyMethodDef BL_Shader::Methods[] = {NULL,NULL} //Sentinel }; - -PyTypeObject BL_Shader::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "BL_Shader", - sizeof(BL_Shader), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, - __repr, - 0 +PyAttributeDef BL_Shader::Attributes[] = { + { NULL } //Sentinel }; - -PyParentObject BL_Shader::Parents[] = { +PyTypeObject BL_Shader::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "BL_Shader", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &PyObjectPlus::Type, - &BL_Shader::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; - KX_PYMETHODDEF_DOC( BL_Shader, setSource," setSource(vertexProgram, fragmentProgram)" ) { if(mShader !=0 && mOk ) { // already set... - Py_Return; + Py_RETURN_NONE; } char *v,*f; int apply=0; - if( PyArg_ParseTuple(args, "ssi", &v, &f, &apply) ) + if( PyArg_ParseTuple(args, "ssi:setSource", &v, &f, &apply) ) { vertProg = v; fragProg = f; if( LinkProgram() ) { glUseProgramObjectARB( mShader ); mUse = apply!=0; - Py_Return; + Py_RETURN_NONE; } vertProg = 0; fragProg = 0; mUse = 0; - Py_Return; + Py_RETURN_NONE; } return NULL; } @@ -827,22 +822,22 @@ KX_PYMETHODDEF_DOC( BL_Shader, delSource, "delSource( )" ) mShader = 0; mOk = 0; mUse = 0; - Py_Return; + Py_RETURN_NONE; } KX_PYMETHODDEF_DOC( BL_Shader, isValid, "isValid()" ) { - return PyInt_FromLong( ( mShader !=0 && mOk ) ); + return PyLong_FromSsize_t( ( mShader !=0 && mOk ) ); } KX_PYMETHODDEF_DOC( BL_Shader, getVertexProg ,"getVertexProg( )" ) { - return PyString_FromString(vertProg?vertProg:""); + return PyUnicode_FromString(vertProg?vertProg:""); } KX_PYMETHODDEF_DOC( BL_Shader, getFragmentProg ,"getFragmentProg( )" ) { - return PyString_FromString(fragProg?fragProg:""); + return PyUnicode_FromString(fragProg?fragProg:""); } KX_PYMETHODDEF_DOC( BL_Shader, validate, "validate()") @@ -851,7 +846,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, validate, "validate()") Py_RETURN_NONE; } if(mShader==0) { - PyErr_Format(PyExc_TypeError, "invalid shader object"); + PyErr_SetString(PyExc_TypeError, "shader.validate(): BL_Shader, invalid shader object"); return NULL; } int stat = 0; @@ -871,7 +866,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, validate, "validate()") MEM_freeN(logInf); logInf=0; } - Py_Return; + Py_RETURN_NONE; } @@ -883,7 +878,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setSampler, "setSampler(name, index)" ) const char *uniform=""; int index=-1; - if(PyArg_ParseTuple(args, "si", &uniform, &index)) + if(PyArg_ParseTuple(args, "si:setSampler", &uniform, &index)) { int loc = GetUniformLocation(uniform); if(loc != -1) { @@ -908,11 +903,11 @@ KX_PYMETHODDEF_DOC( BL_Shader, setSampler, "setSampler(name, index)" ) KX_PYMETHODDEF_DOC( BL_Shader, setNumberOfPasses, "setNumberOfPasses( max-pass )" ) { int pass = 1; - if(!PyArg_ParseTuple(args, "i", &pass)) + if(!PyArg_ParseTuple(args, "i:setNumberOfPasses", &pass)) return NULL; mPass = 1; - Py_Return; + Py_RETURN_NONE; } /// access functions @@ -924,7 +919,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1f, "setUniform1f(name, fx)" ) const char *uniform=""; float value=0; - if(PyArg_ParseTuple(args, "sf", &uniform, &value )) + if(PyArg_ParseTuple(args, "sf:setUniform1f", &uniform, &value )) { int loc = GetUniformLocation(uniform); if(loc != -1) @@ -935,7 +930,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1f, "setUniform1f(name, fx)" ) SetUniform( loc, (float)value ); #endif } - Py_Return; + Py_RETURN_NONE; } return NULL; } @@ -948,7 +943,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2f , "setUniform2f(name, fx, fy)") } const char *uniform=""; float array[2]={ 0,0 }; - if(PyArg_ParseTuple(args, "sff", &uniform, &array[0],&array[1] )) + if(PyArg_ParseTuple(args, "sff:setUniform2f", &uniform, &array[0],&array[1] )) { int loc = GetUniformLocation(uniform); if(loc != -1) @@ -959,7 +954,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2f , "setUniform2f(name, fx, fy)") SetUniform(loc, array, 2); #endif } - Py_Return; + Py_RETURN_NONE; } return NULL; } @@ -972,7 +967,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ") } const char *uniform=""; float array[3]={0,0,0}; - if(PyArg_ParseTuple(args, "sfff", &uniform, &array[0],&array[1],&array[2])) + if(PyArg_ParseTuple(args, "sfff:setUniform3f", &uniform, &array[0],&array[1],&array[2])) { int loc = GetUniformLocation(uniform); if(loc != -1) @@ -983,7 +978,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ") SetUniform(loc, array, 3); #endif } - Py_Return; + Py_RETURN_NONE; } return NULL; @@ -997,7 +992,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) " } const char *uniform=""; float array[4]={0,0,0,0}; - if(PyArg_ParseTuple(args, "sffff", &uniform, &array[0],&array[1],&array[2], &array[3])) + if(PyArg_ParseTuple(args, "sffff:setUniform4f", &uniform, &array[0],&array[1],&array[2], &array[3])) { int loc = GetUniformLocation(uniform); if(loc != -1) @@ -1008,7 +1003,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) " SetUniform(loc, array, 4); #endif } - Py_Return; + Py_RETURN_NONE; } return NULL; } @@ -1021,7 +1016,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1i, "setUniform1i(name, ix)" ) } const char *uniform=""; int value=0; - if(PyArg_ParseTuple(args, "si", &uniform, &value )) + if(PyArg_ParseTuple(args, "si:setUniform1i", &uniform, &value )) { int loc = GetUniformLocation(uniform); if(loc != -1) @@ -1032,7 +1027,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1i, "setUniform1i(name, ix)" ) SetUniform(loc, (int)value); #endif } - Py_Return; + Py_RETURN_NONE; } return NULL; } @@ -1045,7 +1040,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2i , "setUniform2i(name, ix, iy)") } const char *uniform=""; int array[2]={ 0,0 }; - if(PyArg_ParseTuple(args, "sii", &uniform, &array[0],&array[1] )) + if(PyArg_ParseTuple(args, "sii:setUniform2i", &uniform, &array[0],&array[1] )) { int loc = GetUniformLocation(uniform); if(loc != -1) @@ -1056,7 +1051,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2i , "setUniform2i(name, ix, iy)") SetUniform(loc, array, 2); #endif } - Py_Return; + Py_RETURN_NONE; } return NULL; } @@ -1070,7 +1065,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ") const char *uniform=""; int array[3]={0,0,0}; - if(PyArg_ParseTuple(args, "siii", &uniform, &array[0],&array[1],&array[2])) + if(PyArg_ParseTuple(args, "siii:setUniform3i", &uniform, &array[0],&array[1],&array[2])) { int loc = GetUniformLocation(uniform); if(loc != -1) @@ -1081,7 +1076,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ") SetUniform(loc, array, 3); #endif } - Py_Return; + Py_RETURN_NONE; } return NULL; } @@ -1093,7 +1088,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) " } const char *uniform=""; int array[4]={0,0,0, 0}; - if(PyArg_ParseTuple(args, "siiii", &uniform, &array[0],&array[1],&array[2], &array[3] )) + if(PyArg_ParseTuple(args, "siiii:setUniform4i", &uniform, &array[0],&array[1],&array[2], &array[3] )) { int loc = GetUniformLocation(uniform); if(loc != -1) @@ -1104,7 +1099,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) " SetUniform(loc, array, 4); #endif } - Py_Return; + Py_RETURN_NONE; } return NULL; } @@ -1118,7 +1113,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv , "setUniformfv( float (list2 or lis PyObject *listPtr =0; float array_data[4] = {0.f,0.f,0.f,0.f}; - if(PyArg_ParseTuple(args, "sO", &uniform, &listPtr)) + if(PyArg_ParseTuple(args, "sO:setUniformfv", &uniform, &listPtr)) { int loc = GetUniformLocation(uniform); if(loc != -1) @@ -1144,7 +1139,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv , "setUniformfv( float (list2 or lis #else SetUniform(loc, array2, 2); #endif - Py_Return; + Py_RETURN_NONE; } break; case 3: { @@ -1154,7 +1149,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv , "setUniformfv( float (list2 or lis #else SetUniform(loc, array3, 3); #endif - Py_Return; + Py_RETURN_NONE; }break; case 4: { @@ -1164,11 +1159,11 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv , "setUniformfv( float (list2 or lis #else SetUniform(loc, array4, 4); #endif - Py_Return; + Py_RETURN_NONE; }break; default: { - PyErr_Format(PyExc_TypeError, "Invalid list size"); + PyErr_SetString(PyExc_TypeError, "shader.setUniform4i(name, ix,iy,iz, iw): BL_Shader. invalid list size"); return NULL; }break; } @@ -1178,7 +1173,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv , "setUniformfv( float (list2 or lis return NULL; } -KX_PYMETHODDEF_DOC( BL_Shader, setUniformiv, "setUniformiv( int (list2 or list3 or list4) )") +KX_PYMETHODDEF_DOC( BL_Shader, setUniformiv, "setUniformiv( uniform_name, (list2 or list3 or list4) )") { if(mError) { Py_RETURN_NONE; @@ -1187,70 +1182,84 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformiv, "setUniformiv( int (list2 or list3 PyObject *listPtr =0; int array_data[4] = {0,0,0,0}; - if(PyArg_ParseTuple(args, "sO", &uniform, &listPtr)) + if(!PyArg_ParseTuple(args, "sO:setUniformiv", &uniform, &listPtr)) + return NULL; + + int loc = GetUniformLocation(uniform); + + if(loc == -1) { + PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, first string argument is not a valid uniform value"); + return NULL; + } + + if(!PySequence_Check(listPtr)) { + PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, second argument is not a sequence"); + return NULL; + } + + unsigned int list_size = PySequence_Size(listPtr); + + for(unsigned int i=0; (i<list_size && i<4); i++) { - int loc = GetUniformLocation(uniform); - if(loc != -1) + PyObject *item = PySequence_GetItem(listPtr, i); + array_data[i] = PyLong_AsSsize_t(item); + Py_DECREF(item); + } + + if(PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, one or more values in the list is not an int"); + return NULL; + } + + /* Sanity checks done! */ + + switch(list_size) + { + case 2: { - if(PySequence_Check(listPtr)) - { - unsigned int list_size = PySequence_Size(listPtr); - - for(unsigned int i=0; (i<list_size && i<4); i++) - { - PyObject *item = PySequence_GetItem(listPtr, i); - array_data[i] = PyInt_AsLong(item); - Py_DECREF(item); - } - switch(list_size) - { - case 2: - { - int array2[2] = { array_data[0],array_data[1]}; + int array2[2] = { array_data[0],array_data[1]}; #ifdef SORT_UNIFORMS - SetUniformiv(loc, BL_Uniform::UNI_INT2, array2, sizeof(int)*2); + SetUniformiv(loc, BL_Uniform::UNI_INT2, array2, sizeof(int)*2); #else - SetUniform(loc, array2, 2); + SetUniform(loc, array2, 2); #endif - Py_Return; - } break; - case 3: - { - int array3[3] = { array_data[0],array_data[1],array_data[2] }; + Py_RETURN_NONE; + } break; + case 3: + { + int array3[3] = { array_data[0],array_data[1],array_data[2] }; #ifdef SORT_UNIFORMS - SetUniformiv(loc, BL_Uniform::UNI_INT3, array3, sizeof(int)*3); - + SetUniformiv(loc, BL_Uniform::UNI_INT3, array3, sizeof(int)*3); + #else - SetUniform(loc, array3, 3); + SetUniform(loc, array3, 3); #endif - Py_Return; - }break; - case 4: - { - int array4[4] = { array_data[0],array_data[1],array_data[2],array_data[3] }; + Py_RETURN_NONE; + }break; + case 4: + { + int array4[4] = { array_data[0],array_data[1],array_data[2],array_data[3] }; #ifdef SORT_UNIFORMS - SetUniformiv(loc, BL_Uniform::UNI_INT4, array4, sizeof(int)*4); - + SetUniformiv(loc, BL_Uniform::UNI_INT4, array4, sizeof(int)*4); + #else - SetUniform(loc, array4, 4); + SetUniform(loc, array4, 4); #endif - Py_Return; - }break; - default: - { - PyErr_Format(PyExc_TypeError, "Invalid list size"); - return NULL; - }break; - } - } - } + Py_RETURN_NONE; + }break; + default: + { + PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, second argument, invalid list size, expected an int list between 2 and 4"); + return NULL; + }break; } - return NULL; + + Py_RETURN_NONE; } KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix4, -"setUniformMatrix4(uniform-name, mat-4x4, transpose(row-major=true, col-major=false)" ) +"setUniformMatrix4(uniform_name, mat-4x4, transpose(row-major=true, col-major=false)" ) { if(mError) { Py_RETURN_NONE; @@ -1266,33 +1275,38 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix4, const char *uniform=""; PyObject *matrix=0; int transp=1; // MT_ is row major so transpose by default.... - if(PyArg_ParseTuple(args, "sO|i",&uniform, &matrix,&transp)) - { - int loc = GetUniformLocation(uniform); - if(loc != -1) - { - if (PyObject_IsMT_Matrix(matrix, 4)) - { - MT_Matrix4x4 mat; - if (PyMatTo(matrix, mat)) - { + + if(!PyArg_ParseTuple(args, "sO|i:setUniformMatrix4",&uniform, &matrix,&transp)) + return NULL; + + int loc = GetUniformLocation(uniform); + + if(loc == -1) { + PyErr_SetString(PyExc_TypeError, "shader.setUniformMatrix4(...): BL_Shader, first string argument is not a valid uniform value"); + return NULL; + } + + MT_Matrix4x4 mat; + + if (!PyMatTo(matrix, mat)) { + PyErr_SetString(PyExc_TypeError, "shader.setUniformMatrix4(...): BL_Shader, second argument cannot be converted into a 4x4 matrix"); + return NULL; + } + + /* Sanity checks done! */ + #ifdef SORT_UNIFORMS - mat.getValue(matr); - SetUniformfv(loc, BL_Uniform::UNI_MAT4, matr, (sizeof(float)*16), (transp!=0) ); + mat.getValue(matr); + SetUniformfv(loc, BL_Uniform::UNI_MAT4, matr, (sizeof(float)*16), (transp!=0) ); #else - SetUniform(loc,mat,(transp!=0)); + SetUniform(loc,mat,(transp!=0)); #endif - Py_Return; - } - } - } - } - return NULL; + Py_RETURN_NONE; } KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix3, -"setUniformMatrix3(uniform-name, list[3x3], transpose(row-major=true, col-major=false)" ) +"setUniformMatrix3(uniform_name, list[3x3], transpose(row-major=true, col-major=false)" ) { if(mError) { Py_RETURN_NONE; @@ -1307,29 +1321,32 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix3, const char *uniform=""; PyObject *matrix=0; int transp=1; // MT_ is row major so transpose by default.... - if(PyArg_ParseTuple(args, "sO|i",&uniform, &matrix,&transp)) - { - int loc = GetUniformLocation(uniform); - if(loc != -1) - { - if (PyObject_IsMT_Matrix(matrix, 3)) - { - MT_Matrix3x3 mat; - if (PyMatTo(matrix, mat)) - { + if(!PyArg_ParseTuple(args, "sO|i:setUniformMatrix3",&uniform, &matrix,&transp)) + return NULL; + + int loc = GetUniformLocation(uniform); + + if(loc == -1) { + PyErr_SetString(PyExc_TypeError, "shader.setUniformMatrix3(...): BL_Shader, first string argument is not a valid uniform value"); + return NULL; + } + + + MT_Matrix3x3 mat; + + if (!PyMatTo(matrix, mat)) { + PyErr_SetString(PyExc_TypeError, "shader.setUniformMatrix3(...): BL_Shader, second argument cannot be converted into a 3x3 matrix"); + return NULL; + } + + #ifdef SORT_UNIFORMS - mat.getValue(matr); - SetUniformfv(loc, BL_Uniform::UNI_MAT3, matr, (sizeof(float)*9), (transp!=0) ); + mat.getValue(matr); + SetUniformfv(loc, BL_Uniform::UNI_MAT3, matr, (sizeof(float)*9), (transp!=0) ); #else - SetUniform(loc,mat,(transp!=0)); + SetUniform(loc,mat,(transp!=0)); #endif - Py_Return; - - } - } - } - } - return NULL; + Py_RETURN_NONE; } KX_PYMETHODDEF_DOC( BL_Shader, setAttrib, "setAttrib(enum)" ) @@ -1337,18 +1354,20 @@ KX_PYMETHODDEF_DOC( BL_Shader, setAttrib, "setAttrib(enum)" ) if(mError) { Py_RETURN_NONE; } + int attr=0; - if(PyArg_ParseTuple(args, "i", &attr )) { - if(mShader==0) { - PyErr_Format(PyExc_ValueError, "invalid shader object"); - return NULL; - } - mAttr=SHD_TANGENT; - glUseProgramObjectARB(mShader); - glBindAttribLocationARB(mShader, mAttr, "Tangent"); - Py_Return; + + if(!PyArg_ParseTuple(args, "i:setAttrib", &attr )) + return NULL; + + if(mShader==0) { + PyErr_SetString(PyExc_ValueError, "shader.setAttrib() BL_Shader, invalid shader object"); + return NULL; } - return NULL; + mAttr=SHD_TANGENT; /* What the heck is going on here - attr is just ignored??? - Campbell */ + glUseProgramObjectARB(mShader); + glBindAttribLocationARB(mShader, mAttr, "Tangent"); + Py_RETURN_NONE; } @@ -1360,7 +1379,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformDef, "setUniformDef(name, enum)" ) const char *uniform=""; int nloc=0; - if(PyArg_ParseTuple(args, "si",&uniform, &nloc)) + if(PyArg_ParseTuple(args, "si:setUniformDef",&uniform, &nloc)) { int loc = GetUniformLocation(uniform); if(loc != -1) @@ -1376,7 +1395,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformDef, "setUniformDef(name, enum)" ) } if(defined) { - Py_Return; + Py_RETURN_NONE; } BL_DefUniform *uni = new BL_DefUniform(); @@ -1384,7 +1403,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformDef, "setUniformDef(name, enum)" ) uni->mType = nloc; uni->mFlag = 0; mPreDef.push_back(uni); - Py_Return; + Py_RETURN_NONE; } } return NULL; diff --git a/source/gameengine/Ketsji/BL_Shader.h b/source/gameengine/Ketsji/BL_Shader.h index 18ca8f8b4f8..b2610d7762a 100644 --- a/source/gameengine/Ketsji/BL_Shader.h +++ b/source/gameengine/Ketsji/BL_Shader.h @@ -25,6 +25,12 @@ public: { } int mLoc; // Sampler location + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_Sampler"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; /** @@ -65,6 +71,13 @@ public: int GetLocation() { return mLoc; } void* getData() { return mData; } + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_Uniform"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; /** @@ -83,6 +96,13 @@ public: int mType; int mLoc; unsigned int mFlag; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_DefUniform"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; /** @@ -120,7 +140,7 @@ private: void ClearUniforms(); public: - BL_Shader(PyTypeObject *T=&Type); + BL_Shader(); virtual ~BL_Shader(); // Unused for now tangent is set as @@ -166,7 +186,7 @@ public: //const BL_Sampler* GetSampler(int i); void SetSampler(int loc, int unit); - const bool Ok()const; + bool Ok()const; unsigned int GetProg(); void SetProg(bool enable); int GetAttribute(){return mAttr;}; @@ -202,7 +222,7 @@ public: void SetUniform(int uniform, const int val); // Python interface - virtual PyObject* _getattr(const STR_String& attr); + virtual PyObject* py_repr(void) { return PyUnicode_FromFormat("BL_Shader\n\tvertex shader:%s\n\n\tfragment shader%s\n\n", vertProg, fragProg); } // ----------------------------------- KX_PYMETHOD_DOC( BL_Shader, setSource ); diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp index f0ef84032f7..5d40ba7d75c 100644 --- a/source/gameengine/Ketsji/BL_Texture.cpp +++ b/source/gameengine/Ketsji/BL_Texture.cpp @@ -609,7 +609,7 @@ int BL_Texture::GetPow2(int n) void BL_Texture::SplitEnvMap(EnvMap *map) { - if (!map || !map->ima || map->ima && !map->ima->ok) return; + if (!map || !map->ima || (map->ima && !map->ima->ok)) return; ImBuf *ibuf= BKE_image_get_ibuf(map->ima, NULL); if (ibuf) my_envmap_split_ima(map, ibuf); diff --git a/source/gameengine/Ketsji/BL_Texture.h b/source/gameengine/Ketsji/BL_Texture.h index 0d0c7a277f2..2dfd9c542d3 100644 --- a/source/gameengine/Ketsji/BL_Texture.h +++ b/source/gameengine/Ketsji/BL_Texture.h @@ -59,6 +59,20 @@ public: void SetMapping(int mode); void DisableUnit(); void setTexEnv(BL_Material *mat, bool modulate=false); + unsigned int swapTexture (unsigned int newTex) { + // swap texture codes + unsigned int tmp = mTexture; + mTexture = newTex; + // return original texture code + return tmp; + } + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_Texture"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif//__BL_TEXTURE_H__ diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index 58411f6d25e..01d369bc7a9 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -25,57 +25,48 @@ # ***** END GPL LICENSE BLOCK ***** FILE(GLOB SRC *.cpp) -SET(SRC - ${SRC} - ../../../source/blender/python/api2_2x/Mathutils.c - ../../../source/blender/python/api2_2x/constant.c - ../../../source/blender/python/api2_2x/euler.c - ../../../source/blender/python/api2_2x/gen_utils.c - ../../../source/blender/python/api2_2x/matrix.c - ../../../source/blender/python/api2_2x/point.c - ../../../source/blender/python/api2_2x/quat.c - ../../../source/blender/python/api2_2x/vector.c -) SET(INC - . - ../../../source/kernel/gen_system - ../../../intern/string - ../../../intern/guardedalloc - ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../intern/bmfont - ../../../source/gameengine/Converter - ../../../source/blender/imbuf - ../../../intern/ghost/include - ../../../intern/moto/include - ../../../source/gameengine/Ketsji - ../../../source/blender/blenlib - ../../../source/blender/blenkernel - ../../../source/blender/python/api2_2x - ../../../source/blender - ../../../source/blender/include - ../../../source/blender/makesdna - ../../../source/gameengine/Rasterizer - ../../../source/gameengine/GameLogic - ../../../source/gameengine/Expressions - ../../../source/gameengine/Ketsji/KXNetwork - ../../../source/gameengine/Network - ../../../source/gameengine/SceneGraph - ../../../source/gameengine/Physics/common - ../../../source/gameengine/Physics/Bullet - ../../../source/gameengine/Physics/Sumo - ../../../source/gameengine/Physics/Sumo/Fuzzics/include - ../../../source/gameengine/Network/LoopBackNetwork - ../../../intern/SoundSystem - ../../../source/blender/misc - ../../../source/blender/blenloader - ../../../source/blender/gpu - ../../../extern/bullet2/src - ../../../extern/solid - ../../../extern/glew/include - ${PYTHON_INC} - ${SDL_INC} + . + ../../../source/kernel/gen_system + ../../../intern/string + ../../../intern/guardedalloc + ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer + ../../../source/gameengine/Converter + ../../../source/blender/imbuf + ../../../intern/ghost/include + ../../../intern/moto/include + ../../../source/gameengine/Ketsji + ../../../source/blender/blenlib + ../../../source/blender/blenkernel + ../../../source/blender/python + ../../../source/blender/python/generic + ../../../source/blender + ../../../source/blender/include + ../../../source/blender/makesdna + ../../../source/gameengine/Rasterizer + ../../../source/gameengine/GameLogic + ../../../source/gameengine/Expressions + ../../../source/gameengine/Ketsji/KXNetwork + ../../../source/gameengine/Network + ../../../source/gameengine/SceneGraph + ../../../source/gameengine/Physics/common + ../../../source/gameengine/Physics/Bullet + ../../../source/gameengine/Network/LoopBackNetwork + ../../../intern/audaspace/intern + ../../../source/blender/misc + ../../../source/blender/blenloader + ../../../source/blender/gpu + ../../../extern/bullet2/src + ../../../extern/glew/include + ${PYTHON_INC} ) +IF(WITH_SDL) + SET(INC ${INC} ${SDL_INCLUDE_DIR}) +ELSE(WITH_SDL) + ADD_DEFINITIONS(-DDISABLE_SDL) +ENDIF(WITH_SDL) + BLENDERLIB(bf_ketsji "${SRC}" "${INC}") #env.BlenderLib ( 'bf_ketsji', sources, Split(incs), [], libtype=['game','player'], priority=[25, 72], compileflags = cflags ) diff --git a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt index fa0ca378c6b..b89b0dcff9f 100644 --- a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt +++ b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt @@ -27,14 +27,16 @@ FILE(GLOB SRC *.cpp) SET(INC - . - ../../../../source/kernel/gen_system - ../../../../intern/string - ../../../../source/gameengine/Ketsji - ../../../../source/gameengine/GameLogic - ../../../../source/gameengine/Expressions - ../../../../source/gameengine/Network - ${PYTHON_INC} + . + ../../../../source/kernel/gen_system + ../../../../intern/string + ../../../../intern/moto/include + ../../../../source/gameengine/Ketsji + ../../../../source/gameengine/GameLogic + ../../../../source/gameengine/Expressions + ../../../../source/gameengine/SceneGraph + ../../../../source/gameengine/Network + ${PYTHON_INC} ) BLENDERLIB(kx_network "${SRC}" "${INC}") diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp index eee8e9f6827..738f64713b0 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp @@ -61,12 +61,12 @@ void KX_NetworkEventManager::NextFrame() // each frame, the logicmanager will call the network // eventmanager to look for network events, and process it's // 'network' sensors - set<class SCA_ISensor*>::iterator it; - - for (it = m_sensors.begin(); !(it==m_sensors.end()); it++) { + SG_DList::iterator<SCA_ISensor> it(m_sensors); + for (it.begin();!it.end();++it) + { // printf("KX_NetworkEventManager::proceed sensor %.2f\n", curtime); // process queue - (*it)->Activate(m_logicmgr, NULL); + (*it)->Activate(m_logicmgr); } // now a list of triggerer sensors has been built diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp index 85921ae75ca..3af8f765251 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp @@ -41,13 +41,12 @@ KX_NetworkMessageActuator::KX_NetworkMessageActuator( const STR_String &toPropName, const STR_String &subject, int bodyType, - const STR_String &body, - PyTypeObject* T) : - SCA_IActuator(gameobj,T), + const STR_String &body) : + SCA_IActuator(gameobj), m_networkscene(networkscene), m_toPropName(toPropName), m_subject(subject), - m_bodyType(bodyType), + m_bPropBody(bodyType), m_body(body) { } @@ -69,13 +68,13 @@ bool KX_NetworkMessageActuator::Update() } //printf("messageactuator true event\n"); - if (m_bodyType == 1) // ACT_MESG_PROP in DNA_actuator_types.h + if (m_bPropBody) // ACT_MESG_PROP in DNA_actuator_types.h { m_networkscene->SendMessage( m_toPropName, GetParent()->GetName(), m_subject, - GetParent()->GetPropertyText(m_body,"")); + GetParent()->GetPropertyText(m_body)); } else { m_networkscene->SendMessage( @@ -93,9 +92,6 @@ CValue* KX_NetworkMessageActuator::GetReplica() new KX_NetworkMessageActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - return replica; } @@ -105,117 +101,35 @@ CValue* KX_NetworkMessageActuator::GetReplica() /* Integration hooks -------------------------------------------------- */ PyTypeObject KX_NetworkMessageActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_NetworkMessageActuator", - sizeof(KX_NetworkMessageActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_NetworkMessageActuator::Parents[] = { - &KX_NetworkMessageActuator::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_NetworkMessageActuator::Methods[] = { - {"setToPropName", (PyCFunction) - KX_NetworkMessageActuator::sPySetToPropName, METH_VARARGS}, - {"setSubject", (PyCFunction) - KX_NetworkMessageActuator::sPySetSubject, METH_VARARGS}, - {"setBodyType", (PyCFunction) - KX_NetworkMessageActuator::sPySetBodyType, METH_VARARGS}, - {"setBody", (PyCFunction) - KX_NetworkMessageActuator::sPySetBody, METH_VARARGS}, {NULL,NULL} // Sentinel }; -PyObject* KX_NetworkMessageActuator::_getattr(const STR_String& attr) { - _getattr_up(SCA_IActuator); -} - -// 1. SetToPropName -PyObject* KX_NetworkMessageActuator::PySetToPropName( - PyObject* self, - PyObject* args, - PyObject* kwds) -{ - char* ToPropName; - - if (PyArg_ParseTuple(args, "s", &ToPropName)) { - m_toPropName = ToPropName; - } - else { - return NULL; - } - - Py_Return; -} - -// 2. SetSubject -PyObject* KX_NetworkMessageActuator::PySetSubject( - PyObject* self, - PyObject* args, - PyObject* kwds) -{ - char* Subject; - - if (PyArg_ParseTuple(args, "s", &Subject)) { - m_subject = Subject; - } - else { - return NULL; - } - - Py_Return; -} - -// 3. SetBodyType -PyObject* KX_NetworkMessageActuator::PySetBodyType( - PyObject* self, - PyObject* args, - PyObject* kwds) -{ - int BodyType; - - if (PyArg_ParseTuple(args, "i", &BodyType)) { - m_bodyType = BodyType; - } - else { - return NULL; - } - - Py_Return; -} - -// 4. SetBody -PyObject* KX_NetworkMessageActuator::PySetBody( - PyObject* self, - PyObject* args, - PyObject* kwds) -{ - char* Body; - - if (PyArg_ParseTuple(args, "s", &Body)) { - m_body = Body; - } - else { - return NULL; - } - - Py_Return; -} - +PyAttributeDef KX_NetworkMessageActuator::Attributes[] = { + KX_PYATTRIBUTE_STRING_RW("propName", 0, 100, false, KX_NetworkMessageActuator, m_toPropName), + KX_PYATTRIBUTE_STRING_RW("subject", 0, 100, false, KX_NetworkMessageActuator, m_subject), + KX_PYATTRIBUTE_BOOL_RW("usePropBody", KX_NetworkMessageActuator, m_bPropBody), + KX_PYATTRIBUTE_STRING_RW("body", 0, 16384, false, KX_NetworkMessageActuator, m_body), + { NULL } //Sentinel +}; diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h index 653107699c7..fa7a674c250 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h @@ -41,7 +41,7 @@ class KX_NetworkMessageActuator : public SCA_IActuator class NG_NetworkScene* m_networkscene; // needed for replication STR_String m_toPropName; STR_String m_subject; - int m_bodyType; + bool m_bPropBody; STR_String m_body; public: KX_NetworkMessageActuator( @@ -50,8 +50,7 @@ public: const STR_String &toPropName, const STR_String &subject, int bodyType, - const STR_String &body, - PyTypeObject* T=&Type); + const STR_String &body); virtual ~KX_NetworkMessageActuator(); virtual bool Update(); @@ -61,13 +60,6 @@ public: /* Python interface ------------------------------------------- */ /* ------------------------------------------------------------ */ - virtual PyObject* _getattr(const STR_String& attr); - - KX_PYMETHOD(KX_NetworkMessageActuator, SetToPropName); - KX_PYMETHOD(KX_NetworkMessageActuator, SetSubject); - KX_PYMETHOD(KX_NetworkMessageActuator, SetBodyType); - KX_PYMETHOD(KX_NetworkMessageActuator, SetBody); - }; #endif //__KX_NETWORKMESSAGEACTUATOR_H diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp index 8956df9c96b..392e9dd9d1b 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp @@ -50,11 +50,9 @@ KX_NetworkMessageSensor::KX_NetworkMessageSensor( class KX_NetworkEventManager* eventmgr, // our eventmanager class NG_NetworkScene *NetworkScene, // our scene SCA_IObject* gameobj, // the sensor controlling object - const STR_String &subject, - PyTypeObject* T + const STR_String &subject ) : - SCA_ISensor(gameobj,eventmgr,T), - m_Networkeventmgr(eventmgr), + SCA_ISensor(gameobj,eventmgr), m_NetworkScene(NetworkScene), m_subject(subject), m_frame_message_count (0), @@ -79,15 +77,13 @@ CValue* KX_NetworkMessageSensor::GetReplica() { CValue* replica = new KX_NetworkMessageSensor(*this); if (replica == NULL) return NULL; - - // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } // Return true only for flank (UP and DOWN) -bool KX_NetworkMessageSensor::Evaluate(CValue* event) +bool KX_NetworkMessageSensor::Evaluate() { bool result = false; bool WasUp = m_IsUp; @@ -104,8 +100,8 @@ bool KX_NetworkMessageSensor::Evaluate(CValue* event) m_SubjectList = NULL; } - STR_String toname=GetParent()->GetName(); - STR_String subject = this->m_subject; + STR_String& toname=GetParent()->GetName(); + STR_String& subject = this->m_subject; vector<NG_NetworkMessage*> messages = m_NetworkScene->FindMessages(toname,"",subject,true); @@ -125,9 +121,9 @@ bool KX_NetworkMessageSensor::Evaluate(CValue* event) for (mesit=messages.begin();mesit!=messages.end();mesit++) { // save the body - STR_String body = (*mesit)->GetMessageText(); + const STR_String& body = (*mesit)->GetMessageText(); // save the subject - STR_String messub = (*mesit)->GetSubject(); + const STR_String& messub = (*mesit)->GetSubject(); #ifdef NAN_NET_DEBUG if (body) { cout << "body [" << body << "]\n"; @@ -168,116 +164,55 @@ bool KX_NetworkMessageSensor::IsPositiveTrigger() /* Integration hooks --------------------------------------------------- */ PyTypeObject KX_NetworkMessageSensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_NetworkMessageSensor", - sizeof(KX_NetworkMessageSensor), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_NetworkMessageSensor::Parents[] = { - &KX_NetworkMessageSensor::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_NetworkMessageSensor::Methods[] = { - {"setSubjectFilterText", (PyCFunction) - KX_NetworkMessageSensor::sPySetSubjectFilterText, METH_O, - (PY_METHODCHAR)SetSubjectFilterText_doc}, - {"getFrameMessageCount", (PyCFunction) - KX_NetworkMessageSensor::sPyGetFrameMessageCount, METH_NOARGS, - (PY_METHODCHAR)GetFrameMessageCount_doc}, - {"getBodies", (PyCFunction) - KX_NetworkMessageSensor::sPyGetBodies, METH_NOARGS, - (PY_METHODCHAR)GetBodies_doc}, - {"getSubject", (PyCFunction) - KX_NetworkMessageSensor::sPyGetSubject, METH_NOARGS, - (PY_METHODCHAR)GetSubject_doc}, - {"getSubjects", (PyCFunction) - KX_NetworkMessageSensor::sPyGetSubjects, METH_NOARGS, - (PY_METHODCHAR)GetSubjects_doc}, {NULL,NULL} //Sentinel }; -PyObject* KX_NetworkMessageSensor::_getattr(const STR_String& attr) { - _getattr_up(SCA_ISensor); // implicit return! -} - -// 1. Set the message subject that this sensor listens for -const char KX_NetworkMessageSensor::SetSubjectFilterText_doc[] = -"\tsetSubjectFilterText(value)\n" -"\tChange the message subject text that this sensor is listening to.\n"; - -PyObject* KX_NetworkMessageSensor::PySetSubjectFilterText( PyObject* self, PyObject* value) -{ - char* Subject = PyString_AsString(value); - if (Subject==NULL) { - PyErr_SetString(PyExc_TypeError, "expected a string message"); - return NULL; - } - - m_subject = Subject; - Py_RETURN_NONE; -} - -// 2. Get the number of messages received since the last frame -const char KX_NetworkMessageSensor::GetFrameMessageCount_doc[] = -"\tgetFrameMessageCount()\n" -"\tGet the number of messages received since the last frame.\n"; - -PyObject* KX_NetworkMessageSensor::PyGetFrameMessageCount( PyObject* ) -{ - return PyInt_FromLong(long(m_frame_message_count)); -} - -// 3. Get the message bodies -const char KX_NetworkMessageSensor::GetBodies_doc[] = -"\tgetBodies()\n" -"\tGet the list of message bodies.\n"; +PyAttributeDef KX_NetworkMessageSensor::Attributes[] = { + KX_PYATTRIBUTE_STRING_RW("subject", 0, 100, false, KX_NetworkMessageSensor, m_subject), + KX_PYATTRIBUTE_INT_RO("frameMessageCount", KX_NetworkMessageSensor, m_frame_message_count), + KX_PYATTRIBUTE_RO_FUNCTION("bodies", KX_NetworkMessageSensor, pyattr_get_bodies), + KX_PYATTRIBUTE_RO_FUNCTION("subjects", KX_NetworkMessageSensor, pyattr_get_subjects), + { NULL } //Sentinel +}; -PyObject* KX_NetworkMessageSensor::PyGetBodies( PyObject* ) +PyObject* KX_NetworkMessageSensor::pyattr_get_bodies(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - if (m_BodyList) { - return ((PyObject*) m_BodyList->AddRef()); + KX_NetworkMessageSensor *self = static_cast<KX_NetworkMessageSensor*>(self_v); + if (self->m_BodyList) { + return self->m_BodyList->GetProxy(); } else { - return ((PyObject*) new CListValue()); + return (new CListValue())->NewProxy(true); } } -// 4. Get the message subject: field of the message sensor -const char KX_NetworkMessageSensor::GetSubject_doc[] = -"\tgetSubject()\n" -"\tGet the subject: field of the message sensor.\n"; - -PyObject* KX_NetworkMessageSensor::PyGetSubject( PyObject* ) -{ - return PyString_FromString(m_subject ? m_subject : ""); -} - -// 5. Get the message subjects -const char KX_NetworkMessageSensor::GetSubjects_doc[] = -"\tgetSubjects()\n" -"\tGet list of message subjects.\n"; - -PyObject* KX_NetworkMessageSensor::PyGetSubjects( PyObject* ) +PyObject* KX_NetworkMessageSensor::pyattr_get_subjects(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - if (m_SubjectList) { - return ((PyObject*) m_SubjectList->AddRef()); + KX_NetworkMessageSensor *self = static_cast<KX_NetworkMessageSensor*>(self_v); + if (self->m_SubjectList) { + return self->m_SubjectList->GetProxy(); } else { - return ((PyObject*) new CListValue()); + return (new CListValue())->NewProxy(true); } } diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h index 8cdfd6cdb5a..d8a0651d2f1 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h @@ -39,7 +39,6 @@ class KX_NetworkMessageSensor : public SCA_ISensor { // note: Py_Header MUST BE the first listed here Py_Header; - KX_NetworkEventManager *m_Networkeventmgr; NG_NetworkScene *m_NetworkScene; // The subject we filter on. @@ -57,13 +56,12 @@ public: KX_NetworkEventManager* eventmgr, // our eventmanager NG_NetworkScene *NetworkScene, // our scene SCA_IObject* gameobj, // the sensor controlling object - const STR_String &subject, - PyTypeObject* T=&Type + const STR_String &subject ); virtual ~KX_NetworkMessageSensor(); virtual CValue* GetReplica(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void Init(); void EndFrame(); @@ -72,14 +70,9 @@ public: /* Python interface -------------------------------------------- */ /* ------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); - - KX_PYMETHOD_DOC_O(KX_NetworkMessageSensor, SetSubjectFilterText); - KX_PYMETHOD_DOC_NOARGS(KX_NetworkMessageSensor, GetFrameMessageCount); - KX_PYMETHOD_DOC_NOARGS(KX_NetworkMessageSensor, GetBodies); - KX_PYMETHOD_DOC_NOARGS(KX_NetworkMessageSensor, GetSubject); - KX_PYMETHOD_DOC_NOARGS(KX_NetworkMessageSensor, GetSubjects); - + /* attributes */ + static PyObject* pyattr_get_bodies(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_subjects(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); }; diff --git a/source/gameengine/Ketsji/KXNetwork/Makefile b/source/gameengine/Ketsji/KXNetwork/Makefile index ddcb03600d5..365ed8fc9c3 100644 --- a/source/gameengine/Ketsji/KXNetwork/Makefile +++ b/source/gameengine/Ketsji/KXNetwork/Makefile @@ -38,8 +38,10 @@ CCFLAGS += $(LEVEL_1_CPP_WARNINGS) CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I../../Expressions CPPFLAGS += -I../../GameLogic +CPPFLAGS += -I../../SceneGraph CPPFLAGS += -I../../Network CPPFLAGS += -I../../../kernel/gen_system CPPFLAGS += -I.. diff --git a/source/gameengine/Ketsji/KXNetwork/SConscript b/source/gameengine/Ketsji/KXNetwork/SConscript index 2297b96c19e..8f88511acca 100644 --- a/source/gameengine/Ketsji/KXNetwork/SConscript +++ b/source/gameengine/Ketsji/KXNetwork/SConscript @@ -3,10 +3,10 @@ Import ('env') sources = env.Glob('*.cpp') -incs = '. #source/kernel/gen_system #intern/string #source/gameengine/Ketsji' +incs = '. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/Ketsji' incs += ' #source/gameengine/GameLogic #source/gameengine/Expressions' -incs += ' #source/gameengine/Network' +incs += ' #source/gameengine/Network #source/gameengine/SceneGraph' incs += ' ' + env['BF_PYTHON_INC'] -env.BlenderLib ( 'kx_network', Split(sources), Split(incs), defines=[],libtype=['game2', 'player'], priority=[5, 155] ) +env.BlenderLib ( 'bf_network', Split(sources), Split(incs), defines=[],libtype=['core','player'], priority=[400,125], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index f92200780d5..be3d4906761 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -42,36 +42,45 @@ BL_BlenderShader *KX_BlenderMaterial::mLastBlenderShader = NULL; //static PyObject *gTextureDict = 0; -KX_BlenderMaterial::KX_BlenderMaterial( - KX_Scene *scene, - BL_Material *data, - bool skin, - int lightlayer, - PyTypeObject *T - ) -: PyObjectPlus(T), - RAS_IPolyMaterial( - STR_String( data->texname[0] ), - STR_String( data->matname ), // needed for physics! - data->tile, - data->tilexrep[0], - data->tileyrep[0], - data->mode, - data->transp, - ((data->ras_mode &ALPHA)!=0), - ((data->ras_mode &ZSORT)!=0), - lightlayer - ), - mMaterial(data), +KX_BlenderMaterial::KX_BlenderMaterial() +: PyObjectPlus(), + RAS_IPolyMaterial(), + mMaterial(NULL), mShader(0), mBlenderShader(0), - mScene(scene), + mScene(NULL), mUserDefBlend(0), mModified(0), mConstructed(false), mPass(0) +{ +} +void KX_BlenderMaterial::Initialize( + KX_Scene *scene, + BL_Material *data, + bool skin) { + RAS_IPolyMaterial::Initialize( + data->texname[0], + data->matname, + data->materialindex, + data->tile, + data->tilexrep[0], + data->tileyrep[0], + data->mode, + data->transp, + ((data->ras_mode &ALPHA)!=0), + ((data->ras_mode &ZSORT)!=0) + ); + mMaterial = data; + mShader = 0; + mBlenderShader = 0; + mScene = scene; + mUserDefBlend = 0; + mModified = 0; + mConstructed = false; + mPass = 0; // -------------------------------- // RAS_IPolyMaterial variables... m_flag |= RAS_BLENDERMAT; @@ -95,7 +104,6 @@ KX_BlenderMaterial::KX_BlenderMaterial( ); } m_multimode += mMaterial->IdMode+ (mMaterial->ras_mode & ~(COLLIDER|USE_LIGHT)); - } KX_BlenderMaterial::~KX_BlenderMaterial() @@ -106,7 +114,6 @@ KX_BlenderMaterial::~KX_BlenderMaterial() OnExit(); } - MTFace* KX_BlenderMaterial::GetMTFace(void) const { // fonts on polys @@ -120,14 +127,41 @@ unsigned int* KX_BlenderMaterial::GetMCol(void) const return mMaterial->rgb; } -void KX_BlenderMaterial::OnConstruction() +void KX_BlenderMaterial::GetMaterialRGBAColor(unsigned char *rgba) const +{ + if (mMaterial) { + *rgba++ = (unsigned char) (mMaterial->matcolor[0]*255.0); + *rgba++ = (unsigned char) (mMaterial->matcolor[1]*255.0); + *rgba++ = (unsigned char) (mMaterial->matcolor[2]*255.0); + *rgba++ = (unsigned char) (mMaterial->matcolor[3]*255.0); + } else + RAS_IPolyMaterial::GetMaterialRGBAColor(rgba); +} + +Material *KX_BlenderMaterial::GetBlenderMaterial() const +{ + return mMaterial->material; +} + +Scene* KX_BlenderMaterial::GetBlenderScene() const +{ + return mScene->GetBlenderScene(); +} + +void KX_BlenderMaterial::ReleaseMaterial() +{ + if (mBlenderShader) + mBlenderShader->ReloadMaterial(); +} + +void KX_BlenderMaterial::OnConstruction(int layer) { if (mConstructed) // when material are reused between objects return; if(mMaterial->glslmat) - SetBlenderGLSLShader(); + SetBlenderGLSLShader(layer); // for each unique material... int i; @@ -201,7 +235,7 @@ void KX_BlenderMaterial::OnExit() } if( mMaterial->tface ) - GPU_set_tpage(mMaterial->tface); + GPU_set_tpage(mMaterial->tface, 1); } @@ -377,10 +411,12 @@ KX_BlenderMaterial::ActivatShaders( } else rasty->SetLines(false); + ActivatGLMaterials(rasty); + ActivateTexGen(rasty); } - ActivatGLMaterials(rasty); - ActivateTexGen(rasty); + //ActivatGLMaterials(rasty); + //ActivateTexGen(rasty); } void @@ -469,10 +505,12 @@ KX_BlenderMaterial::ActivateMat( } else rasty->SetLines(false); + ActivatGLMaterials(rasty); + ActivateTexGen(rasty); } - ActivatGLMaterials(rasty); - ActivateTexGen(rasty); + //ActivatGLMaterials(rasty); + //ActivateTexGen(rasty); } bool @@ -601,8 +639,7 @@ void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const if (mode &USECUSTOMUV) { - STR_String str = mMaterial->mapping[i].uvCoName; - if (!str.IsEmpty()) + if (!mMaterial->mapping[i].uvCoName.IsEmpty()) ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV2, i); continue; } @@ -737,6 +774,7 @@ void KX_BlenderMaterial::UpdateIPO( mMaterial->hard = (float)(hard); mMaterial->emit = (float)(emit); mMaterial->spec_f = (float)(spec); + mMaterial->ref = (float)(ref); } @@ -748,41 +786,35 @@ PyMethodDef KX_BlenderMaterial::Methods[] = {NULL,NULL} //Sentinel }; - -PyTypeObject KX_BlenderMaterial::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_BlenderMaterial", - sizeof(KX_BlenderMaterial), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, - __repr, - 0 +PyAttributeDef KX_BlenderMaterial::Attributes[] = { + //KX_PYATTRIBUTE_TODO("shader"), + //KX_PYATTRIBUTE_TODO("materialIndex"), + //KX_PYATTRIBUTE_TODO("blending"), + { NULL } //Sentinel }; - -PyParentObject KX_BlenderMaterial::Parents[] = { +PyTypeObject KX_BlenderMaterial::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "KX_BlenderMaterial", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &PyObjectPlus::Type, - &KX_BlenderMaterial::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; - -PyObject* KX_BlenderMaterial::_getattr(const STR_String& attr) -{ - _getattr_up(PyObjectPlus); -} - -int KX_BlenderMaterial::_setattr(const STR_String& attr, PyObject *pyvalue) -{ - return PyObjectPlus::_setattr(attr, pyvalue); -} - - KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()") { if( !GLEW_ARB_fragment_shader) { @@ -790,7 +822,7 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()") spit("Fragment shaders not supported"); mModified = true; - Py_Return; + Py_RETURN_NONE; } if( !GLEW_ARB_vertex_shader) { @@ -798,14 +830,14 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()") spit("Vertex shaders not supported"); mModified = true; - Py_Return; + Py_RETURN_NONE; } if(!GLEW_ARB_shader_objects) { if(!mModified) spit("GLSL not supported"); mModified = true; - Py_Return; + Py_RETURN_NONE; } else { // returns Py_None on error @@ -820,8 +852,7 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()") m_flag &= ~RAS_BLENDERGLSL; mMaterial->SetSharedMaterial(true); mScene->GetBucketManager()->ReleaseDisplayLists(this); - Py_INCREF(mShader); - return mShader; + return mShader->GetProxy(); }else { // decref all references to the object @@ -829,26 +860,21 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()") // We will then go back to fixed functionality // for this material if(mShader) { - if(mShader->ob_refcnt > 1) { - Py_DECREF(mShader); - } - else { - delete mShader; - mShader=0; - } + delete mShader; /* will handle python de-referencing */ + mShader=0; } } - Py_Return; + Py_RETURN_NONE; } - PyErr_Format(PyExc_ValueError, "GLSL Error"); + PyErr_SetString(PyExc_ValueError, "material.getShader(): KX_BlenderMaterial, GLSL Error"); return NULL; } -void KX_BlenderMaterial::SetBlenderGLSLShader(void) +void KX_BlenderMaterial::SetBlenderGLSLShader(int layer) { if(!mBlenderShader) - mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, m_lightlayer); + mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, layer); if(!mBlenderShader->Ok()) { delete mBlenderShader; @@ -858,7 +884,7 @@ void KX_BlenderMaterial::SetBlenderGLSLShader(void) KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()") { - return PyInt_FromLong( mMaterial->material_index ); + return PyLong_FromSsize_t( GetMaterialIndex() ); } KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getTexture, "getTexture( index )" ) @@ -890,7 +916,7 @@ static unsigned int GL_array[11] = { KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setBlending , "setBlending( GameLogic.src, GameLogic.dest)") { unsigned int b[2]; - if(PyArg_ParseTuple(args, "ii", &b[0], &b[1])) + if(PyArg_ParseTuple(args, "ii:setBlending", &b[0], &b[1])) { bool value_found[2] = {false, false}; for(int i=0; i<11; i++) @@ -906,11 +932,11 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setBlending , "setBlending( GameLogic.sr if(value_found[0] && value_found[1]) break; } if(!value_found[0] || !value_found[1]) { - PyErr_Format(PyExc_ValueError, "invalid enum."); + PyErr_SetString(PyExc_ValueError, "material.setBlending(int, int): KX_BlenderMaterial, invalid enum."); return NULL; } mUserDefBlend = true; - Py_Return; + Py_RETURN_NONE; } return NULL; } diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h index 4ddf5a924df..cdbdc4bd429 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.h +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h @@ -15,6 +15,10 @@ #include "MT_Vector3.h" #include "MT_Vector4.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + struct MTFace; class KX_Scene; @@ -23,12 +27,11 @@ class KX_BlenderMaterial : public PyObjectPlus, public RAS_IPolyMaterial Py_Header; public: // -------------------------------- - KX_BlenderMaterial( + KX_BlenderMaterial(); + void Initialize( class KX_Scene* scene, BL_Material* mat, - bool skin, - int lightlayer, - PyTypeObject* T=&Type + bool skin ); virtual ~KX_BlenderMaterial(); @@ -67,7 +70,12 @@ public: MTFace* GetMTFace(void) const; unsigned int* GetMCol(void) const; - + BL_Texture * getTex (unsigned int idx) { + return (idx < MAXTEX) ? mTextures + idx : NULL; + } + Image * getImage (unsigned int idx) { + return (idx < MAXTEX && mMaterial) ? mMaterial->img[idx] : NULL; + } // for ipos void UpdateIPO( MT_Vector4 rgba, MT_Vector3 specrgb, @@ -76,8 +84,7 @@ public: ); // -------------------------------- - virtual PyObject* _getattr(const STR_String& attr); - virtual int _setattr(const STR_String& attr, PyObject *pyvalue); + virtual PyObject* py_repr(void) { return PyUnicode_FromString(mMaterial->matname.ReadPtr()); } KX_PYMETHOD_DOC( KX_BlenderMaterial, getShader ); KX_PYMETHOD_DOC( KX_BlenderMaterial, getMaterialIndex ); @@ -88,7 +95,7 @@ public: // -------------------------------- // pre calculate to avoid pops/lag at startup - virtual void OnConstruction( ); + virtual void OnConstruction(int layer); static void EndFrame(); @@ -103,12 +110,16 @@ private: bool mModified; bool mConstructed; // if false, don't clean on exit - void SetBlenderGLSLShader(); + void SetBlenderGLSLShader(int layer); void ActivatGLMaterials( RAS_IRasterizer* rasty )const; void ActivateTexGen( RAS_IRasterizer *ras ) const; bool UsesLighting(RAS_IRasterizer *rasty) const; + void GetMaterialRGBAColor(unsigned char *rgba) const; + Material* GetBlenderMaterial() const; + Scene* GetBlenderScene() const; + void ReleaseMaterial(); // message centers void setTexData( bool enable,RAS_IRasterizer *ras); diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp index bf838e60210..db1595db36f 100644 --- a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp +++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp @@ -17,12 +17,17 @@ #include "BulletSoftBody/btSoftBody.h" -KX_BulletPhysicsController::KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna) -: KX_IPhysicsController(dyna,(PHY_IPhysicsController*)this), +KX_BulletPhysicsController::KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna, bool sensor, bool compound) +: KX_IPhysicsController(dyna,sensor,compound,(PHY_IPhysicsController*)this), CcdPhysicsController(ci), -m_savedCollisionFlags(0) +m_savedCollisionFlags(0), +m_savedCollisionFilterGroup(0), +m_savedCollisionFilterMask(0), +m_savedMass(0.0), +m_savedDyna(false), +m_suspended(false), +m_bulletChildShape(NULL) { - } KX_BulletPhysicsController::~KX_BulletPhysicsController () @@ -58,6 +63,24 @@ void KX_BulletPhysicsController::applyImpulse(const MT_Point3& attach, const MT_ } +float KX_BulletPhysicsController::GetLinVelocityMin() +{ + return (float)CcdPhysicsController::GetLinVelocityMin(); +} +void KX_BulletPhysicsController::SetLinVelocityMin(float val) +{ + CcdPhysicsController::SetLinVelocityMin(val); +} + +float KX_BulletPhysicsController::GetLinVelocityMax() +{ + return (float)CcdPhysicsController::GetLinVelocityMax(); +} +void KX_BulletPhysicsController::SetLinVelocityMax(float val) +{ + CcdPhysicsController::SetLinVelocityMax(val); +} + void KX_BulletPhysicsController::SetObject (SG_IObject* object) { SG_Controller::SetObject(object); @@ -69,9 +92,19 @@ void KX_BulletPhysicsController::SetObject (SG_IObject* object) gameobj->SetPhysicsController(this,gameobj->IsDynamic()); CcdPhysicsController::setNewClientInfo(gameobj->getClientInfo()); - + if (m_bSensor) + { + // use a different callback function for sensor object, + // bullet will not synchronize, we must do it explicitely + SG_Callbacks& callbacks = gameobj->GetSGNode()->GetCallBackFunctions(); + callbacks.m_updatefunc = KX_GameObject::SynchronizeTransformFunc; + } } +MT_Scalar KX_BulletPhysicsController::GetRadius() +{ + return MT_Scalar(CcdPhysicsController::GetRadius()); +} void KX_BulletPhysicsController::setMargin (float collisionMargin) { @@ -147,6 +180,20 @@ void KX_BulletPhysicsController::setScaling(const MT_Vector3& scaling) { CcdPhysicsController::setScaling(scaling.x(),scaling.y(),scaling.z()); } +void KX_BulletPhysicsController::SetTransform() +{ + btVector3 pos; + btVector3 scale; + float ori[12]; + m_MotionState->getWorldPosition(pos.m_floats[0],pos.m_floats[1],pos.m_floats[2]); + m_MotionState->getWorldScaling(scale.m_floats[0],scale.m_floats[1],scale.m_floats[2]); + m_MotionState->getWorldOrientation(ori); + btMatrix3x3 rot(ori[0], ori[4], ori[8], + ori[1], ori[5], ori[9], + ori[2], ori[6], ori[10]); + CcdPhysicsController::forceWorldTransform(rot, pos); +} + MT_Scalar KX_BulletPhysicsController::GetMass() { if (GetSoftBody()) @@ -161,9 +208,18 @@ MT_Scalar KX_BulletPhysicsController::GetMass() } -MT_Scalar KX_BulletPhysicsController::GetRadius() +MT_Vector3 KX_BulletPhysicsController::GetLocalInertia() { - return MT_Scalar(CcdPhysicsController::GetRadius()); + MT_Vector3 inertia(0.f, 0.f, 0.f); + btVector3 inv_inertia; + if (GetRigidBody()) { + inv_inertia = GetRigidBody()->getInvInertiaDiagLocal(); + if (!btFuzzyZero(inv_inertia.getX()) && + !btFuzzyZero(inv_inertia.getY()) && + !btFuzzyZero(inv_inertia.getZ())) + inertia = MT_Vector3(1.f/inv_inertia.getX(), 1.f/inv_inertia.getY(), 1.f/inv_inertia.getZ()); + } + return inertia; } MT_Vector3 KX_BulletPhysicsController::getReactionForce() @@ -175,36 +231,187 @@ void KX_BulletPhysicsController::setRigidBody(bool rigid) { } +/* This function dynamically adds the collision shape of another controller to + the current controller shape provided it is a compound shape. + The idea is that dynamic parenting on a compound object will dynamically extend the shape +*/ +void KX_BulletPhysicsController::AddCompoundChild(KX_IPhysicsController* child) +{ + if (child == NULL || !IsCompound()) + return; + // other controller must be a bullet controller too + // verify that body and shape exist and match + KX_BulletPhysicsController* childCtrl = dynamic_cast<KX_BulletPhysicsController*>(child); + btRigidBody* rootBody = GetRigidBody(); + btRigidBody* childBody = childCtrl->GetRigidBody(); + if (!rootBody || !childBody) + return; + const btCollisionShape* rootShape = rootBody->getCollisionShape(); + const btCollisionShape* childShape = childBody->getCollisionShape(); + if (!rootShape || + !childShape || + rootShape->getShapeType() != COMPOUND_SHAPE_PROXYTYPE || + childShape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) + return; + btCompoundShape* compoundShape = (btCompoundShape*)rootShape; + // compute relative transformation between parent and child + btTransform rootTrans; + btTransform childTrans; + rootBody->getMotionState()->getWorldTransform(rootTrans); + childBody->getMotionState()->getWorldTransform(childTrans); + btVector3 rootScale = rootShape->getLocalScaling(); + rootScale[0] = 1.0/rootScale[0]; + rootScale[1] = 1.0/rootScale[1]; + rootScale[2] = 1.0/rootScale[2]; + // relative scale = child_scale/parent_scale + btVector3 relativeScale = childShape->getLocalScaling()*rootScale; + btMatrix3x3 rootRotInverse = rootTrans.getBasis().transpose(); + // relative pos = parent_rot^-1 * ((parent_pos-child_pos)/parent_scale) + btVector3 relativePos = rootRotInverse*((childTrans.getOrigin()-rootTrans.getOrigin())*rootScale); + // relative rot = parent_rot^-1 * child_rot + btMatrix3x3 relativeRot = rootRotInverse*childTrans.getBasis(); + // create a proxy shape info to store the transformation + CcdShapeConstructionInfo* proxyShapeInfo = new CcdShapeConstructionInfo(); + // store the transformation to this object shapeinfo + proxyShapeInfo->m_childTrans.setOrigin(relativePos); + proxyShapeInfo->m_childTrans.setBasis(relativeRot); + proxyShapeInfo->m_childScale.setValue(relativeScale[0], relativeScale[1], relativeScale[2]); + // we will need this to make sure that we remove the right proxy later when unparenting + proxyShapeInfo->m_userData = childCtrl; + proxyShapeInfo->SetProxy(childCtrl->GetShapeInfo()->AddRef()); + // add to parent compound shapeinfo + GetShapeInfo()->AddShape(proxyShapeInfo); + // create new bullet collision shape from the object shapeinfo and set scaling + btCollisionShape* newChildShape = proxyShapeInfo->CreateBulletShape(childCtrl->GetMargin()); + newChildShape->setLocalScaling(relativeScale); + // add bullet collision shape to parent compound collision shape + compoundShape->addChildShape(proxyShapeInfo->m_childTrans,newChildShape); + // remember we created this shape + childCtrl->m_bulletChildShape = newChildShape; + // recompute inertia of parent + if (!rootBody->isStaticOrKinematicObject()) + { + btVector3 localInertia; + float mass = 1.f/rootBody->getInvMass(); + compoundShape->calculateLocalInertia(mass,localInertia); + rootBody->setMassProps(mass,localInertia); + } + // must update the broadphase cache, + GetPhysicsEnvironment()->refreshCcdPhysicsController(this); + // remove the children + GetPhysicsEnvironment()->disableCcdPhysicsController(childCtrl); +} + +/* Reverse function of the above, it will remove a shape from a compound shape + provided that the former was added to the later using AddCompoundChild() +*/ +void KX_BulletPhysicsController::RemoveCompoundChild(KX_IPhysicsController* child) +{ + if (child == NULL || !IsCompound()) + return; + // other controller must be a bullet controller too + // verify that body and shape exist and match + KX_BulletPhysicsController* childCtrl = dynamic_cast<KX_BulletPhysicsController*>(child); + btRigidBody* rootBody = GetRigidBody(); + btRigidBody* childBody = childCtrl->GetRigidBody(); + if (!rootBody || !childBody) + return; + const btCollisionShape* rootShape = rootBody->getCollisionShape(); + if (!rootShape || + rootShape->getShapeType() != COMPOUND_SHAPE_PROXYTYPE) + return; + btCompoundShape* compoundShape = (btCompoundShape*)rootShape; + // retrieve the shapeInfo + CcdShapeConstructionInfo* childShapeInfo = childCtrl->GetShapeInfo(); + CcdShapeConstructionInfo* rootShapeInfo = GetShapeInfo(); + // and verify that the child is part of the parent + int i = rootShapeInfo->FindChildShape(childShapeInfo, childCtrl); + if (i < 0) + return; + rootShapeInfo->RemoveChildShape(i); + if (childCtrl->m_bulletChildShape) + { + int numChildren = compoundShape->getNumChildShapes(); + for (i=0; i<numChildren; i++) + { + if (compoundShape->getChildShape(i) == childCtrl->m_bulletChildShape) + { + compoundShape->removeChildShapeByIndex(i); + compoundShape->recalculateLocalAabb(); + break; + } + } + delete childCtrl->m_bulletChildShape; + childCtrl->m_bulletChildShape = NULL; + } + // recompute inertia of parent + if (!rootBody->isStaticOrKinematicObject()) + { + btVector3 localInertia; + float mass = 1.f/rootBody->getInvMass(); + compoundShape->calculateLocalInertia(mass,localInertia); + rootBody->setMassProps(mass,localInertia); + } + // must update the broadphase cache, + GetPhysicsEnvironment()->refreshCcdPhysicsController(this); + // reactivate the children + GetPhysicsEnvironment()->enableCcdPhysicsController(childCtrl); +} + +void KX_BulletPhysicsController::SetMass(MT_Scalar newmass) +{ + btRigidBody *body = GetRigidBody(); + if (body && !m_suspended && newmass>MT_EPSILON && GetMass()>MT_EPSILON) + { + btVector3 grav = body->getGravity(); + btVector3 accel = grav / GetMass(); + + btBroadphaseProxy* handle = body->getBroadphaseHandle(); + GetPhysicsEnvironment()->updateCcdPhysicsController(this, + newmass, + body->getCollisionFlags(), + handle->m_collisionFilterGroup, + handle->m_collisionFilterMask); + body->setGravity(accel); + } +} + void KX_BulletPhysicsController::SuspendDynamics(bool ghost) { btRigidBody *body = GetRigidBody(); - if (body && body->getActivationState() != DISABLE_SIMULATION) + if (body && !m_suspended && !IsSensor()) { btBroadphaseProxy* handle = body->getBroadphaseHandle(); m_savedCollisionFlags = body->getCollisionFlags(); m_savedMass = GetMass(); + m_savedDyna = m_bDyna; m_savedCollisionFilterGroup = handle->m_collisionFilterGroup; m_savedCollisionFilterMask = handle->m_collisionFilterMask; - body->setActivationState(DISABLE_SIMULATION); + m_suspended = true; GetPhysicsEnvironment()->updateCcdPhysicsController(this, 0.0, btCollisionObject::CF_STATIC_OBJECT|((ghost)?btCollisionObject::CF_NO_CONTACT_RESPONSE:(m_savedCollisionFlags&btCollisionObject::CF_NO_CONTACT_RESPONSE)), btBroadphaseProxy::StaticFilter, btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter); + m_bDyna = false; } } void KX_BulletPhysicsController::RestoreDynamics() { btRigidBody *body = GetRigidBody(); - if (body && body->getActivationState() == DISABLE_SIMULATION) + if (body && m_suspended) { + // before make sure any position change that was done in this logic frame are accounted for + SetTransform(); GetPhysicsEnvironment()->updateCcdPhysicsController(this, m_savedMass, m_savedCollisionFlags, m_savedCollisionFilterGroup, m_savedCollisionFilterMask); - GetRigidBody()->forceActivationState(ACTIVE_TAG); + body->activate(); + m_bDyna = m_savedDyna; + m_suspended = false; } } @@ -236,10 +443,10 @@ SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode) childit!= destnode->GetSGChildren().end(); ++childit ) { - KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); - if (clientgameobj) + KX_GameObject *clientgameobj_child = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); + if (clientgameobj_child) { - parentKxCtrl = (KX_BulletPhysicsController*)clientgameobj->GetPhysicsController(); + parentKxCtrl = (KX_BulletPhysicsController*)clientgameobj_child->GetPhysicsController(); parentctrl = parentKxCtrl; ccdParent = parentKxCtrl; } @@ -250,6 +457,7 @@ SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode) physicsreplica->setParentCtrl(ccdParent); physicsreplica->PostProcessReplica(motionstate,parentctrl); physicsreplica->m_userdata = (PHY_IPhysicsController*)physicsreplica; + physicsreplica->m_bulletChildShape = NULL; return physicsreplica; } @@ -258,23 +466,24 @@ SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode) void KX_BulletPhysicsController::SetSumoTransform(bool nondynaonly) { - if (GetRigidBody()) - GetRigidBody()->activate(true); - if (!m_bDyna) + if (!m_bDyna && !m_bSensor) { - GetCollisionObject()->setCollisionFlags(GetRigidBody()->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + btCollisionObject* object = GetRigidBody(); + object->setActivationState(ACTIVE_TAG); + object->setCollisionFlags(object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } else { if (!nondynaonly) { + /* btTransform worldTrans; if (GetRigidBody()) { GetRigidBody()->getMotionState()->getWorldTransform(worldTrans); GetRigidBody()->setCenterOfMassTransform(worldTrans); } - + */ /* scaling? if (m_bDyna) diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.h b/source/gameengine/Ketsji/KX_BulletPhysicsController.h index cdcb82c87ca..7fc799abb7e 100644 --- a/source/gameengine/Ketsji/KX_BulletPhysicsController.h +++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.h @@ -9,13 +9,16 @@ class KX_BulletPhysicsController : public KX_IPhysicsController ,public CcdPhysi { private: int m_savedCollisionFlags; + int m_savedActivationState; short int m_savedCollisionFilterGroup; short int m_savedCollisionFilterMask; MT_Scalar m_savedMass; + bool m_savedDyna; + bool m_suspended; + btCollisionShape* m_bulletChildShape; public: - - KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna); + KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna, bool sensor, bool compound); virtual ~KX_BulletPhysicsController (); /////////////////////////////////// @@ -38,9 +41,14 @@ public: virtual void setOrientation(const MT_Matrix3x3& orn); virtual void setPosition(const MT_Point3& pos); virtual void setScaling(const MT_Vector3& scaling); + virtual void SetTransform(); virtual MT_Scalar GetMass(); + virtual void SetMass(MT_Scalar newmass); + virtual MT_Vector3 GetLocalInertia(); virtual MT_Vector3 getReactionForce(); virtual void setRigidBody(bool rigid); + virtual void AddCompoundChild(KX_IPhysicsController* child); + virtual void RemoveCompoundChild(KX_IPhysicsController* child); virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ); @@ -50,7 +58,11 @@ public: virtual SG_Controller* GetReplica(class SG_Node* destnode); virtual MT_Scalar GetRadius(); - + + virtual float GetLinVelocityMin(); + virtual void SetLinVelocityMin(float val); + virtual float GetLinVelocityMax(); + virtual void SetLinVelocityMax(float val); virtual void SetSumoTransform(bool nondynaonly); // todo: remove next line ! @@ -68,6 +80,12 @@ public: // intentionally empty }; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_BulletPhysicsController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //KX_BULLET2PHYSICS_CONTROLLER diff --git a/source/gameengine/Ketsji/KX_CDActuator.cpp b/source/gameengine/Ketsji/KX_CDActuator.cpp deleted file mode 100644 index a5d7f6d799a..00000000000 --- a/source/gameengine/Ketsji/KX_CDActuator.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/** - * KX_CDActuator.cpp - * - * $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - * - */ - -#include "KX_CDActuator.h" -#include "SND_CDObject.h" -#include "KX_GameObject.h" -#include "SND_Scene.h" // needed for replication -#include <iostream> - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -/* ------------------------------------------------------------------------- */ -/* Native functions */ -/* ------------------------------------------------------------------------- */ -KX_CDActuator::KX_CDActuator(SCA_IObject* gameobject, - SND_Scene* soundscene, - KX_CDACT_TYPE type, - int track, - short start, - short end, - PyTypeObject* T) - : SCA_IActuator(gameobject,T) -{ - m_soundscene = soundscene; - m_type = type; - m_track = track; - m_lastEvent = true; - m_isplaying = false; - m_startFrame = start; - m_endFrame = end; - m_gain = SND_CDObject::Instance()->GetGain(); -} - - - -KX_CDActuator::~KX_CDActuator() -{ -} - - -/* hmmm, do we want this? */ -CValue* KX_CDActuator::GetReplica() -{ - KX_CDActuator* replica = new KX_CDActuator(*this); - replica->ProcessReplica(); - - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - return replica; -}; - - - -bool KX_CDActuator::Update() -{ - bool result = false; - bool bNegativeEvent = IsNegativeEvent(); - - RemoveAllEvents(); - - if (!bNegativeEvent) - { - switch (m_type) - { - case KX_CDACT_PLAY_ALL: - { - SND_CDObject::Instance()->SetPlaymode(SND_CD_ALL); - SND_CDObject::Instance()->SetTrack(1); - SND_CDObject::Instance()->SetPlaystate(SND_MUST_PLAY); - result = true; - break; - } - case KX_CDACT_PLAY_TRACK: - { - SND_CDObject::Instance()->SetPlaymode(SND_CD_TRACK); - SND_CDObject::Instance()->SetTrack(m_track); - SND_CDObject::Instance()->SetPlaystate(SND_MUST_PLAY); - result = true; - break; - } - case KX_CDACT_LOOP_TRACK: - { - SND_CDObject::Instance()->SetPlaymode(SND_CD_ALL); - SND_CDObject::Instance()->SetTrack(m_track); - SND_CDObject::Instance()->SetPlaystate(SND_MUST_PLAY); - result = true; - break; - } - case KX_CDACT_STOP: - { - SND_CDObject::Instance()->SetPlaystate(SND_MUST_STOP); - break; - } - case KX_CDACT_PAUSE: - { - SND_CDObject::Instance()->SetPlaystate(SND_MUST_PAUSE); - result = true; - break; - } - case KX_CDACT_RESUME: - { - SND_CDObject::Instance()->SetPlaystate(SND_MUST_RESUME); - result = true; - break; - } - case KX_CDACT_VOLUME: - { - SND_CDObject::Instance()->SetGain(m_gain); - result = true; - break; - } - default: - // implement me !! - break; - } - } - return result; -} - - - -/* ------------------------------------------------------------------------- */ -/* Python functions */ -/* ------------------------------------------------------------------------- */ - - - -/* Integration hooks ------------------------------------------------------- */ -PyTypeObject KX_CDActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_SoundActuator", - sizeof(KX_CDActuator), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 -}; - - - -PyParentObject KX_CDActuator::Parents[] = { - &KX_CDActuator::Type, - &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL -}; - - - -PyMethodDef KX_CDActuator::Methods[] = { - {"startCD",(PyCFunction) KX_CDActuator::sPyStartCD,METH_VARARGS,NULL}, - {"pauseCD",(PyCFunction) KX_CDActuator::sPyPauseCD,METH_VARARGS,NULL}, - {"stopCD",(PyCFunction) KX_CDActuator::sPyStopCD,METH_VARARGS,NULL}, - {"setGain",(PyCFunction) KX_CDActuator::sPySetGain,METH_VARARGS,NULL}, - {"getGain",(PyCFunction) KX_CDActuator::sPyGetGain,METH_VARARGS,NULL}, - {NULL,NULL,NULL,NULL} //Sentinel -}; - - - -PyObject* KX_CDActuator::_getattr(const STR_String& attr) -{ - _getattr_up(SCA_IActuator); -} - - - - -PyObject* KX_CDActuator::PyStartCD(PyObject* self, PyObject* args, PyObject* kwds) -{ - SND_CDObject::Instance()->SetPlaystate(SND_MUST_PLAY); - Py_Return; -} - - - -PyObject* KX_CDActuator::PyPauseCD(PyObject* self, PyObject* args, PyObject* kwds) -{ - SND_CDObject::Instance()->SetPlaystate(SND_MUST_PAUSE); - Py_Return; -} - - - -PyObject* KX_CDActuator::PyStopCD(PyObject* self, PyObject* args, PyObject* kwds) -{ - SND_CDObject::Instance()->SetPlaystate(SND_MUST_STOP); - Py_Return; -} - - - -PyObject* KX_CDActuator::PySetGain(PyObject* self, PyObject* args, PyObject* kwds) -{ - float gain = 1.0; - if (!PyArg_ParseTuple(args, "f", &gain)) - return NULL; - - SND_CDObject::Instance()->SetGain(gain); - - Py_Return; -} - - - -PyObject* KX_CDActuator::PyGetGain(PyObject* self, PyObject* args, PyObject* kwds) -{ - float gain = SND_CDObject::Instance()->GetGain(); - PyObject* result = PyFloat_FromDouble(gain); - - return result; -} diff --git a/source/gameengine/Ketsji/KX_CDActuator.h b/source/gameengine/Ketsji/KX_CDActuator.h deleted file mode 100644 index f46dd99b6dc..00000000000 --- a/source/gameengine/Ketsji/KX_CDActuator.h +++ /dev/null @@ -1,94 +0,0 @@ -/** - * KX_CDActuator.h - * - * $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ - -#ifndef __KX_CDACTUATOR -#define __KX_CDACTUATOR - -#include "SCA_IActuator.h" -#include "SND_CDObject.h" - -class KX_CDActuator : public SCA_IActuator -{ - Py_Header; - bool m_lastEvent; - bool m_isplaying; - /* just some handles to the audio-data... */ - class SND_Scene* m_soundscene; - int m_track; - float m_gain; - short m_startFrame; - short m_endFrame; - -public: - enum KX_CDACT_TYPE - { - KX_CDACT_NODEF = 0, - KX_CDACT_PLAY_ALL, - KX_CDACT_PLAY_TRACK, - KX_CDACT_LOOP_TRACK, - KX_CDACT_VOLUME, - KX_CDACT_STOP, - KX_CDACT_PAUSE, - KX_CDACT_RESUME, - KX_SOUNDACT_MAX - }; - - KX_CDACT_TYPE m_type; - - KX_CDActuator(SCA_IObject* gameobject, - SND_Scene* soundscene, - KX_CDACT_TYPE type, - int track, - short start, - short end, - PyTypeObject* T=&Type); - - ~KX_CDActuator(); - - virtual bool Update(); - - CValue* GetReplica(); - - /* -------------------------------------------------------------------- */ - /* Python interface --------------------------------------------------- */ - /* -------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - - KX_PYMETHOD(KX_CDActuator,StartCD); - KX_PYMETHOD(KX_CDActuator,PauseCD); - KX_PYMETHOD(KX_CDActuator,StopCD); - KX_PYMETHOD(KX_CDActuator,SetGain); - KX_PYMETHOD(KX_CDActuator,GetGain); -}; - -#endif //__KX_CDACTUATOR - diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp index 3830d422138..0832809772d 100644 --- a/source/gameengine/Ketsji/KX_Camera.cpp +++ b/source/gameengine/Ketsji/KX_Camera.cpp @@ -28,6 +28,7 @@ * Camera in the gameengine. Cameras are also used for views. */ +#include "GL/glew.h" #include "KX_Camera.h" #include "KX_Scene.h" #include "KX_PythonInit.h" @@ -41,15 +42,16 @@ KX_Camera::KX_Camera(void* sgReplicationInfo, SG_Callbacks callbacks, const RAS_CameraData& camdata, bool frustum_culling, - PyTypeObject *T) + bool delete_node) : - KX_GameObject(sgReplicationInfo,callbacks,T), + KX_GameObject(sgReplicationInfo,callbacks), m_camdata(camdata), m_dirty(true), m_normalized(false), - m_frustum_culling(frustum_culling && camdata.m_perspective), + m_frustum_culling(frustum_culling), m_set_projection_matrix(false), - m_set_frustum_center(false) + m_set_frustum_center(false), + m_delete_node(delete_node) { // setting a name would be nice... m_name = "cam"; @@ -63,6 +65,12 @@ KX_Camera::KX_Camera(void* sgReplicationInfo, KX_Camera::~KX_Camera() { + if (m_delete_node && m_pSGNode) + { + // for shadow camera, avoids memleak + delete m_pSGNode; + m_pSGNode = NULL; + } } @@ -71,15 +79,16 @@ CValue* KX_Camera::GetReplica() KX_Camera* replica = new KX_Camera(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); - ProcessReplica(replica); + replica->ProcessReplica(); return replica; } - -void KX_Camera::ProcessReplica(KX_Camera* replica) + +void KX_Camera::ProcessReplica() { - KX_GameObject::ProcessReplica(replica); + KX_GameObject::ProcessReplica(); + // replicated camera are always registered in the scene + m_delete_node = false; } MT_Transform KX_Camera::GetWorldToCamera() const @@ -190,6 +199,11 @@ float KX_Camera::GetLens() const return m_camdata.m_lens; } +float KX_Camera::GetScale() const +{ + return m_camdata.m_scale; +} + float KX_Camera::GetCameraNear() const @@ -259,24 +273,94 @@ void KX_Camera::ExtractFrustumSphere() if (m_set_frustum_center) return; - // The most extreme points on the near and far plane. (normalized device coords) - MT_Vector4 hnear(1., 1., 0., 1.), hfar(1., 1., 1., 1.); + // compute sphere for the general case and not only symmetric frustum: + // the mirror code in ImageRender can use very asymmetric frustum. + // We will put the sphere center on the line that goes from origin to the center of the far clipping plane + // This is the optimal position if the frustum is symmetric or very asymmetric and probably close + // to optimal for the general case. The sphere center position is computed so that the distance to + // the near and far extreme frustum points are equal. + + // get the transformation matrix from device coordinate to camera coordinate MT_Matrix4x4 clip_camcs_matrix = m_projection_matrix; clip_camcs_matrix.invert(); - - // Transform to hom camera local space - hnear = clip_camcs_matrix*hnear; - hfar = clip_camcs_matrix*hfar; - - // Tranform to 3d camera local space. - MT_Point3 nearpoint(hnear[0]/hnear[3], hnear[1]/hnear[3], hnear[2]/hnear[3]); - MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]); - - // Compute center - m_frustum_center = MT_Point3(0., 0., - (nearpoint.dot(nearpoint) - farpoint.dot(farpoint))/(2.0*(m_camdata.m_clipend - m_camdata.m_clipstart))); - m_frustum_radius = m_frustum_center.distance(farpoint); - + + if (m_projection_matrix[3][3] == MT_Scalar(0.0)) + { + // frustrum projection + // detect which of the corner of the far clipping plane is the farthest to the origin + MT_Vector4 nfar; // far point in device normalized coordinate + MT_Point3 farpoint; // most extreme far point in camera coordinate + MT_Point3 nearpoint;// most extreme near point in camera coordinate + MT_Point3 farcenter(0.,0.,0.);// center of far cliping plane in camera coordinate + MT_Scalar F=-1.0, N; // square distance of far and near point to origin + MT_Scalar f, n; // distance of far and near point to z axis. f is always > 0 but n can be < 0 + MT_Scalar e, s; // far and near clipping distance (<0) + MT_Scalar c; // slope of center line = distance of far clipping center to z axis / far clipping distance + MT_Scalar z; // projection of sphere center on z axis (<0) + // tmp value + MT_Vector4 npoint(1., 1., 1., 1.); + MT_Vector4 hpoint; + MT_Point3 point; + MT_Scalar len; + for (int i=0; i<4; i++) + { + hpoint = clip_camcs_matrix*npoint; + point.setValue(hpoint[0]/hpoint[3], hpoint[1]/hpoint[3], hpoint[2]/hpoint[3]); + len = point.dot(point); + if (len > F) + { + nfar = npoint; + farpoint = point; + F = len; + } + // rotate by 90 degree along the z axis to walk through the 4 extreme points of the far clipping plane + len = npoint[0]; + npoint[0] = -npoint[1]; + npoint[1] = len; + farcenter += point; + } + // the far center is the average of the far clipping points + farcenter *= 0.25; + // the extreme near point is the opposite point on the near clipping plane + nfar.setValue(-nfar[0], -nfar[1], -1., 1.); + nfar = clip_camcs_matrix*nfar; + nearpoint.setValue(nfar[0]/nfar[3], nfar[1]/nfar[3], nfar[2]/nfar[3]); + // this is a frustrum projection + N = nearpoint.dot(nearpoint); + e = farpoint[2]; + s = nearpoint[2]; + // projection on XY plane for distance to axis computation + MT_Point2 farxy(farpoint[0], farpoint[1]); + // f is forced positive by construction + f = farxy.length(); + // get corresponding point on the near plane + farxy *= s/e; + // this formula preserve the sign of n + n = f*s/e - MT_Point2(nearpoint[0]-farxy[0], nearpoint[1]-farxy[1]).length(); + c = MT_Point2(farcenter[0], farcenter[1]).length()/e; + // the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case + z = (F-N)/(2.0*(e-s+c*(f-n))); + m_frustum_center = MT_Point3(farcenter[0]*z/e, farcenter[1]*z/e, z); + m_frustum_radius = m_frustum_center.distance(farpoint); + } + else + { + // orthographic projection + // The most extreme points on the near and far plane. (normalized device coords) + MT_Vector4 hnear(1., 1., 1., 1.), hfar(-1., -1., -1., 1.); + + // Transform to hom camera local space + hnear = clip_camcs_matrix*hnear; + hfar = clip_camcs_matrix*hfar; + + // Tranform to 3d camera local space. + MT_Point3 nearpoint(hnear[0]/hnear[3], hnear[1]/hnear[3], hnear[2]/hnear[3]); + MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]); + + // just use mediant point + m_frustum_center = (farpoint + nearpoint)*0.5; + m_frustum_radius = m_frustum_center.distance(farpoint); + } // Transform to world space. m_frustum_center = GetCameraToWorld()(m_frustum_center); m_frustum_radius /= fabs(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]); @@ -403,161 +487,71 @@ int KX_Camera::GetViewportTop() const PyMethodDef KX_Camera::Methods[] = { KX_PYMETHODTABLE(KX_Camera, sphereInsideFrustum), - KX_PYMETHODTABLE(KX_Camera, boxInsideFrustum), - KX_PYMETHODTABLE(KX_Camera, pointInsideFrustum), - KX_PYMETHODTABLE(KX_Camera, getCameraToWorld), - KX_PYMETHODTABLE(KX_Camera, getWorldToCamera), - KX_PYMETHODTABLE(KX_Camera, getProjectionMatrix), - KX_PYMETHODTABLE(KX_Camera, setProjectionMatrix), - KX_PYMETHODTABLE(KX_Camera, enableViewport), + KX_PYMETHODTABLE_O(KX_Camera, boxInsideFrustum), + KX_PYMETHODTABLE_O(KX_Camera, pointInsideFrustum), + KX_PYMETHODTABLE_NOARGS(KX_Camera, getCameraToWorld), + KX_PYMETHODTABLE_NOARGS(KX_Camera, getWorldToCamera), KX_PYMETHODTABLE(KX_Camera, setViewport), - KX_PYMETHODTABLE(KX_Camera, setOnTop), - + KX_PYMETHODTABLE_NOARGS(KX_Camera, setOnTop), + KX_PYMETHODTABLE_O(KX_Camera, getScreenPosition), + KX_PYMETHODTABLE(KX_Camera, getScreenVect), + KX_PYMETHODTABLE(KX_Camera, getScreenRay), {NULL,NULL} //Sentinel }; -char KX_Camera::doc[] = "Module KX_Camera\n\n" -"Constants:\n" -"\tINSIDE\n" -"\tINTERSECT\n" -"\tOUTSIDE\n" -"Attributes:\n" -"\tlens -> float\n" -"\t\tThe camera's lens value\n" -"\tnear -> float\n" -"\t\tThe camera's near clip distance\n" -"\tfar -> float\n" -"\t\tThe camera's far clip distance\n" -"\tfrustum_culling -> bool\n" -"\t\tNon zero if this camera is frustum culling.\n" -"\tprojection_matrix -> [[float]]\n" -"\t\tThis camera's projection matrix.\n" -"\tmodelview_matrix -> [[float]] (read only)\n" -"\t\tThis camera's model view matrix.\n" -"\t\tRegenerated every frame from the camera's position and orientation.\n" -"\tcamera_to_world -> [[float]] (read only)\n" -"\t\tThis camera's camera to world transform.\n" -"\t\tRegenerated every frame from the camera's position and orientation.\n" -"\tworld_to_camera -> [[float]] (read only)\n" -"\t\tThis camera's world to camera transform.\n" -"\t\tRegenerated every frame from the camera's position and orientation.\n" -"\t\tThis is camera_to_world inverted.\n"; - -PyTypeObject KX_Camera::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_Camera", - sizeof(KX_Camera), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, - doc +PyAttributeDef KX_Camera::Attributes[] = { + + KX_PYATTRIBUTE_BOOL_RW("frustum_culling", KX_Camera, m_frustum_culling), + KX_PYATTRIBUTE_RW_FUNCTION("perspective", KX_Camera, pyattr_get_perspective, pyattr_set_perspective), + + KX_PYATTRIBUTE_RW_FUNCTION("lens", KX_Camera, pyattr_get_lens, pyattr_set_lens), + KX_PYATTRIBUTE_RW_FUNCTION("near", KX_Camera, pyattr_get_near, pyattr_set_near), + KX_PYATTRIBUTE_RW_FUNCTION("far", KX_Camera, pyattr_get_far, pyattr_set_far), + + KX_PYATTRIBUTE_RW_FUNCTION("useViewport", KX_Camera, pyattr_get_use_viewport, pyattr_set_use_viewport), + + KX_PYATTRIBUTE_RW_FUNCTION("projection_matrix", KX_Camera, pyattr_get_projection_matrix, pyattr_set_projection_matrix), + KX_PYATTRIBUTE_RO_FUNCTION("modelview_matrix", KX_Camera, pyattr_get_modelview_matrix), + KX_PYATTRIBUTE_RO_FUNCTION("camera_to_world", KX_Camera, pyattr_get_camera_to_world), + KX_PYATTRIBUTE_RO_FUNCTION("world_to_camera", KX_Camera, pyattr_get_world_to_camera), + + /* Grrr, functions for constants? */ + KX_PYATTRIBUTE_RO_FUNCTION("INSIDE", KX_Camera, pyattr_get_INSIDE), + KX_PYATTRIBUTE_RO_FUNCTION("OUTSIDE", KX_Camera, pyattr_get_OUTSIDE), + KX_PYATTRIBUTE_RO_FUNCTION("INTERSECT", KX_Camera, pyattr_get_INTERSECT), + + { NULL } //Sentinel }; -PyParentObject KX_Camera::Parents[] = { - &KX_Camera::Type, +PyTypeObject KX_Camera::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "KX_Camera", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, + &KX_GameObject::Sequence, + &KX_GameObject::Mapping, + 0,0,0, + NULL, + NULL, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &KX_GameObject::Type, - &SCA_IObject::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; -PyObject* KX_Camera::_getattr(const STR_String& attr) -{ - if (attr == "INSIDE") - return PyInt_FromLong(INSIDE); /* new ref */ - if (attr == "OUTSIDE") - return PyInt_FromLong(OUTSIDE); /* new ref */ - if (attr == "INTERSECT") - return PyInt_FromLong(INTERSECT); /* new ref */ - - if (attr == "lens") - return PyFloat_FromDouble(GetLens()); /* new ref */ - if (attr == "near") - return PyFloat_FromDouble(GetCameraNear()); /* new ref */ - if (attr == "far") - return PyFloat_FromDouble(GetCameraFar()); /* new ref */ - if (attr == "frustum_culling") - return PyInt_FromLong(m_frustum_culling); /* new ref */ - if (attr == "perspective") - return PyInt_FromLong(m_camdata.m_perspective); /* new ref */ - if (attr == "projection_matrix") - return PyObjectFrom(GetProjectionMatrix()); /* new ref */ - if (attr == "modelview_matrix") - return PyObjectFrom(GetModelviewMatrix()); /* new ref */ - if (attr == "camera_to_world") - return PyObjectFrom(GetCameraToWorld()); /* new ref */ - if (attr == "world_to_camera") - return PyObjectFrom(GetWorldToCamera()); /* new ref */ - - _getattr_up(KX_GameObject); -} - -int KX_Camera::_setattr(const STR_String &attr, PyObject *pyvalue) -{ - if (PyInt_Check(pyvalue)) - { - if (attr == "frustum_culling") - { - m_frustum_culling = PyInt_AsLong(pyvalue); - return 0; - } - - if (attr == "perspective") - { - m_camdata.m_perspective = PyInt_AsLong(pyvalue); - return 0; - } - } - - if (PyFloat_Check(pyvalue)) - { - if (attr == "lens") - { - m_camdata.m_lens = PyFloat_AsDouble(pyvalue); - m_set_projection_matrix = false; - return 0; - } - if (attr == "near") - { - m_camdata.m_clipstart = PyFloat_AsDouble(pyvalue); - m_set_projection_matrix = false; - return 0; - } - if (attr == "far") - { - m_camdata.m_clipend = PyFloat_AsDouble(pyvalue); - m_set_projection_matrix = false; - return 0; - } - } - - if (PyObject_IsMT_Matrix(pyvalue, 4)) - { - if (attr == "projection_matrix") - { - MT_Matrix4x4 mat; - if (PyMatTo(pyvalue, mat)) - { - SetProjectionMatrix(mat); - return 0; - } - return 1; - } - } - return KX_GameObject::_setattr(attr, pyvalue); -} - -KX_PYMETHODDEF_DOC(KX_Camera, sphereInsideFrustum, +KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, sphereInsideFrustum, "sphereInsideFrustum(center, radius) -> Integer\n" "\treturns INSIDE, OUTSIDE or INTERSECT if the given sphere is\n" "\tinside/outside/intersects this camera's viewing frustum.\n\n" @@ -577,21 +571,21 @@ KX_PYMETHODDEF_DOC(KX_Camera, sphereInsideFrustum, { PyObject *pycenter; float radius; - if (PyArg_ParseTuple(args, "Of", &pycenter, &radius)) + if (PyArg_ParseTuple(args, "Of:sphereInsideFrustum", &pycenter, &radius)) { MT_Point3 center; if (PyVecTo(pycenter, center)) { - return PyInt_FromLong(SphereInsideFrustum(center, radius)); /* new ref */ + return PyLong_FromSsize_t(SphereInsideFrustum(center, radius)); /* new ref */ } } - PyErr_SetString(PyExc_TypeError, "sphereInsideFrustum: Expected arguments: (center, radius)"); + PyErr_SetString(PyExc_TypeError, "camera.sphereInsideFrustum(center, radius): KX_Camera, expected arguments: (center, radius)"); return NULL; } -KX_PYMETHODDEF_DOC(KX_Camera, boxInsideFrustum, +KX_PYMETHODDEF_DOC_O(KX_Camera, boxInsideFrustum, "boxInsideFrustum(box) -> Integer\n" "\treturns INSIDE, OUTSIDE or INTERSECT if the given box is\n" "\tinside/outside/intersects this camera's viewing frustum.\n\n" @@ -616,34 +610,27 @@ KX_PYMETHODDEF_DOC(KX_Camera, boxInsideFrustum, "\t\t# Box is outside the frustum !\n" ) { - PyObject *pybox; - if (PyArg_ParseTuple(args, "O", &pybox)) + unsigned int num_points = PySequence_Size(value); + if (num_points != 8) { - unsigned int num_points = PySequence_Size(pybox); - if (num_points != 8) - { - PyErr_Format(PyExc_TypeError, "boxInsideFrustum: Expected eight (8) points, got %d", num_points); + PyErr_Format(PyExc_TypeError, "camera.boxInsideFrustum(box): KX_Camera, expected eight (8) points, got %d", num_points); + return NULL; + } + + MT_Point3 box[8]; + for (unsigned int p = 0; p < 8 ; p++) + { + PyObject *item = PySequence_GetItem(value, p); /* new ref */ + bool error = !PyVecTo(item, box[p]); + Py_DECREF(item); + if (error) return NULL; - } - - MT_Point3 box[8]; - for (unsigned int p = 0; p < 8 ; p++) - { - PyObject *item = PySequence_GetItem(pybox, p); /* new ref */ - bool error = !PyVecTo(item, box[p]); - Py_DECREF(item); - if (error) - return NULL; - } - - return PyInt_FromLong(BoxInsideFrustum(box)); /* new ref */ } - PyErr_SetString(PyExc_TypeError, "boxInsideFrustum: Expected argument: list of points."); - return NULL; + return PyLong_FromSsize_t(BoxInsideFrustum(box)); /* new ref */ } -KX_PYMETHODDEF_DOC(KX_Camera, pointInsideFrustum, +KX_PYMETHODDEF_DOC_O(KX_Camera, pointInsideFrustum, "pointInsideFrustum(point) -> Bool\n" "\treturns 1 if the given point is inside this camera's viewing frustum.\n\n" "\tpoint = The point to test (in world coordinates.)\n\n" @@ -660,16 +647,16 @@ KX_PYMETHODDEF_DOC(KX_Camera, pointInsideFrustum, ) { MT_Point3 point; - if (PyVecArgTo(args, point)) + if (PyVecTo(value, point)) { - return PyInt_FromLong(PointInsideFrustum(point)); /* new ref */ + return PyLong_FromSsize_t(PointInsideFrustum(point)); /* new ref */ } - PyErr_SetString(PyExc_TypeError, "pointInsideFrustum: Expected point argument."); + PyErr_SetString(PyExc_TypeError, "camera.pointInsideFrustum(point): KX_Camera, expected point argument."); return NULL; } -KX_PYMETHODDEF_DOC(KX_Camera, getCameraToWorld, +KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, getCameraToWorld, "getCameraToWorld() -> Matrix4x4\n" "\treturns the camera to world transformation matrix, as a list of four lists of four values.\n\n" "\tie: [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])\n" @@ -678,7 +665,7 @@ KX_PYMETHODDEF_DOC(KX_Camera, getCameraToWorld, return PyObjectFrom(GetCameraToWorld()); /* new ref */ } -KX_PYMETHODDEF_DOC(KX_Camera, getWorldToCamera, +KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, getWorldToCamera, "getWorldToCamera() -> Matrix4x4\n" "\treturns the world to camera transformation matrix, as a list of four lists of four values.\n\n" "\tie: [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])\n" @@ -687,114 +674,360 @@ KX_PYMETHODDEF_DOC(KX_Camera, getWorldToCamera, return PyObjectFrom(GetWorldToCamera()); /* new ref */ } -KX_PYMETHODDEF_DOC(KX_Camera, getProjectionMatrix, -"getProjectionMatrix() -> Matrix4x4\n" -"\treturns this camera's projection matrix, as a list of four lists of four values.\n\n" -"\tie: [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])\n" -) +KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, setViewport, +"setViewport(left, bottom, right, top)\n" +"Sets this camera's viewport\n") { - return PyObjectFrom(GetProjectionMatrix()); /* new ref */ + int left, bottom, right, top; + if (!PyArg_ParseTuple(args,"iiii:setViewport",&left, &bottom, &right, &top)) + return NULL; + + SetViewport(left, bottom, right, top); + Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(KX_Camera, setProjectionMatrix, -"setProjectionMatrix(MT_Matrix4x4 m) -> None\n" -"\tSets this camera's projection matrix\n" -"\n" -"\tExample:\n" -"\timport GameLogic\n" -"\t# Set a perspective projection matrix\n" -"\tdef Perspective(left, right, bottom, top, near, far):\n" -"\t\tm = MT_Matrix4x4()\n" -"\t\tm[0][0] = m[0][2] = right - left\n" -"\t\tm[1][1] = m[1][2] = top - bottom\n" -"\t\tm[2][2] = m[2][3] = -far - near\n" -"\t\tm[3][2] = -1\n" -"\t\tm[3][3] = 0\n" -"\t\treturn m\n" -"\n" -"\t# Set an orthographic projection matrix\n" -"\tdef Orthographic(left, right, bottom, top, near, far):\n" -"\t\tm = MT_Matrix4x4()\n" -"\t\tm[0][0] = right - left\n" -"\t\tm[0][3] = -right - left\n" -"\t\tm[1][1] = top - bottom\n" -"\t\tm[1][3] = -top - bottom\n" -"\t\tm[2][2] = far - near\n" -"\t\tm[2][3] = -far - near\n" -"\t\tm[3][3] = 1\n" -"\t\treturn m\n" -"\n" -"\t# Set an isometric projection matrix\n" -"\tdef Isometric(left, right, bottom, top, near, far):\n" -"\t\tm = MT_Matrix4x4()\n" -"\t\tm[0][0] = m[0][2] = m[1][1] = 0.8660254037844386\n" -"\t\tm[1][0] = 0.25\n" -"\t\tm[1][2] = -0.25\n" -"\t\tm[3][3] = 1\n" -"\t\treturn m\n" -"\n" -"\t" -"\tco = GameLogic.getCurrentController()\n" -"\tcam = co.getOwner()\n" -"\tcam.setProjectionMatrix(Perspective(-1.0, 1.0, -1.0, 1.0, 0.1, 1))\n") +KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, setOnTop, +"setOnTop()\n" +"Sets this camera's viewport on top\n") +{ + class KX_Scene* scene = KX_GetActiveScene(); + scene->SetCameraOnTop(this); + Py_RETURN_NONE; +} + +PyObject* KX_Camera::pyattr_get_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - PyObject *pymat; - if (PyArg_ParseTuple(args, "O", &pymat)) + KX_Camera* self= static_cast<KX_Camera*>(self_v); + return PyBool_FromLong(self->m_camdata.m_perspective); +} + +int KX_Camera::pyattr_set_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + int param = PyObject_IsTrue( value ); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "camera.perspective = bool: KX_Camera, expected True/False or 0/1"); + return PY_SET_ATTR_FAIL; + } + + self->m_camdata.m_perspective= param; + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_Camera::pyattr_get_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + return PyFloat_FromDouble(self->m_camdata.m_lens); +} + +int KX_Camera::pyattr_set_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + float param = PyFloat_AsDouble(value); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "camera.lens = float: KX_Camera, expected a float greater then zero"); + return PY_SET_ATTR_FAIL; + } + + self->m_camdata.m_lens= param; + self->m_set_projection_matrix = false; + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_Camera::pyattr_get_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + return PyFloat_FromDouble(self->m_camdata.m_clipstart); +} + +int KX_Camera::pyattr_set_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + float param = PyFloat_AsDouble(value); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "camera.near = float: KX_Camera, expected a float greater then zero"); + return PY_SET_ATTR_FAIL; + } + + self->m_camdata.m_clipstart= param; + self->m_set_projection_matrix = false; + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_Camera::pyattr_get_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + return PyFloat_FromDouble(self->m_camdata.m_clipend); +} + +int KX_Camera::pyattr_set_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + float param = PyFloat_AsDouble(value); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "camera.far = float: KX_Camera, expected a float greater then zero"); + return PY_SET_ATTR_FAIL; + } + + self->m_camdata.m_clipend= param; + self->m_set_projection_matrix = false; + return PY_SET_ATTR_SUCCESS; +} + + +PyObject* KX_Camera::pyattr_get_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + return PyBool_FromLong(self->GetViewport()); +} + +int KX_Camera::pyattr_set_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + int param = PyObject_IsTrue( value ); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "camera.useViewport = bool: KX_Camera, expected True or False"); + return PY_SET_ATTR_FAIL; + } + self->EnableViewport((bool)param); + return PY_SET_ATTR_SUCCESS; +} + + +PyObject* KX_Camera::pyattr_get_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + return PyObjectFrom(self->GetProjectionMatrix()); +} + +int KX_Camera::pyattr_set_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + MT_Matrix4x4 mat; + if (!PyMatTo(value, mat)) + return PY_SET_ATTR_FAIL; + + self->SetProjectionMatrix(mat); + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_Camera::pyattr_get_modelview_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + return PyObjectFrom(self->GetModelviewMatrix()); +} + +PyObject* KX_Camera::pyattr_get_camera_to_world(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + return PyObjectFrom(self->GetCameraToWorld()); +} + +PyObject* KX_Camera::pyattr_get_world_to_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Camera* self= static_cast<KX_Camera*>(self_v); + return PyObjectFrom(self->GetWorldToCamera()); +} + + +PyObject* KX_Camera::pyattr_get_INSIDE(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ return PyLong_FromSsize_t(INSIDE); } +PyObject* KX_Camera::pyattr_get_OUTSIDE(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ return PyLong_FromSsize_t(OUTSIDE); } +PyObject* KX_Camera::pyattr_get_INTERSECT(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ return PyLong_FromSsize_t(INTERSECT); } + + +bool ConvertPythonToCamera(PyObject * value, KX_Camera **object, bool py_none_ok, const char *error_prefix) +{ + if (value==NULL) { + PyErr_Format(PyExc_TypeError, "%s, python pointer NULL, should never happen", error_prefix); + *object = NULL; + return false; + } + + if (value==Py_None) { + *object = NULL; + + if (py_none_ok) { + return true; + } else { + PyErr_Format(PyExc_TypeError, "%s, expected KX_Camera or a KX_Camera name, None is invalid", error_prefix); + return false; + } + } + + if (PyUnicode_Check(value)) { + STR_String value_str = _PyUnicode_AsString(value); + *object = KX_GetActiveScene()->FindCamera(value_str); + + if (*object) { + return true; + } else { + PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_Camera in this scene", error_prefix, _PyUnicode_AsString(value)); + return false; + } + } + + if (PyObject_TypeCheck(value, &KX_Camera::Type)) { + *object = static_cast<KX_Camera*>BGE_PROXY_REF(value); + + /* sets the error */ + if (*object==NULL) { + PyErr_Format(PyExc_SystemError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix); + return false; + } + + return true; + } + + *object = NULL; + + if (py_none_ok) { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_Camera, a string or None", error_prefix); + } else { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_Camera or a string", error_prefix); + } + + return false; +} + +KX_PYMETHODDEF_DOC_O(KX_Camera, getScreenPosition, +"getScreenPosition()\n" +) + +{ + MT_Vector3 vect; + KX_GameObject *obj = NULL; + + if (!PyVecTo(value, vect)) { - MT_Matrix4x4 mat; - if (PyMatTo(pymat, mat)) + if(ConvertPythonToGameObject(value, &obj, true, "")) + { + PyErr_Clear(); + vect = MT_Vector3(obj->NodeGetWorldPosition()); + } + else { - SetProjectionMatrix(mat); - Py_Return; + PyErr_SetString(PyExc_TypeError, "Error in getScreenPosition. Expected a Vector3 or a KX_GameObject or a string for a name of a KX_GameObject"); + return NULL; } } - PyErr_SetString(PyExc_TypeError, "setProjectionMatrix: Expected 4x4 list as matrix argument."); + GLint viewport[4]; + GLdouble win[3]; + GLdouble modelmatrix[16]; + GLdouble projmatrix[16]; + + MT_Matrix4x4 m_modelmatrix = this->GetModelviewMatrix(); + MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix(); + + m_modelmatrix.getValue(modelmatrix); + m_projmatrix.getValue(projmatrix); + + glGetIntegerv(GL_VIEWPORT, viewport); + + gluProject(vect[0], vect[1], vect[2], modelmatrix, projmatrix, viewport, &win[0], &win[1], &win[2]); + + vect[0] = (win[0] - viewport[0]) / viewport[2]; + vect[1] = (win[1] - viewport[1]) / viewport[3]; + + vect[1] = 1.0 - vect[1]; //to follow Blender window coordinate system (Top-Down) + + PyObject* ret = PyTuple_New(2); + if(ret){ + PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(vect[0])); + PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(vect[1])); + return ret; + } + return NULL; } -KX_PYMETHODDEF_DOC(KX_Camera, enableViewport, -"enableViewport(viewport)\n" -"Sets this camera's viewport status\n" +KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenVect, +"getScreenVect()\n" ) { - int viewport; - if (PyArg_ParseTuple(args,"i",&viewport)) - { - if(viewport) - EnableViewport(true); - else - EnableViewport(false); - } - else { + double x,y; + if (!PyArg_ParseTuple(args,"dd:getScreenVect",&x,&y)) return NULL; - } - - Py_Return; + + y = 1.0 - y; //to follow Blender window coordinate system (Top-Down) + + MT_Vector3 vect; + MT_Point3 campos, screenpos; + + GLint viewport[4]; + GLdouble win[3]; + GLdouble modelmatrix[16]; + GLdouble projmatrix[16]; + + MT_Matrix4x4 m_modelmatrix = this->GetModelviewMatrix(); + MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix(); + + m_modelmatrix.getValue(modelmatrix); + m_projmatrix.getValue(projmatrix); + + glGetIntegerv(GL_VIEWPORT, viewport); + + vect[0] = x * viewport[2]; + vect[1] = y * viewport[3]; + + vect[0] += viewport[0]; + vect[1] += viewport[1]; + + glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &vect[2]); + gluUnProject(vect[0], vect[1], vect[2], modelmatrix, projmatrix, viewport, &win[0], &win[1], &win[2]); + + campos = this->GetCameraLocation(); + screenpos = MT_Point3(win[0], win[1], win[2]); + vect = campos-screenpos; + + vect.normalize(); + return PyObjectFrom(vect); } -KX_PYMETHODDEF_DOC(KX_Camera, setViewport, -"setViewport(left, bottom, right, top)\n" -"Sets this camera's viewport\n") +KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenRay, +"getScreenRay()\n" +) { - int left, bottom, right, top; - if (PyArg_ParseTuple(args,"iiii",&left, &bottom, &right, &top)) + MT_Vector3 vect; + double x,y,dist; + char *propName = NULL; + + if (!PyArg_ParseTuple(args,"ddd|s:getScreenRay",&x,&y,&dist,&propName)) + return NULL; + + PyObject* argValue = PyTuple_New(2); + if (argValue) { + PyTuple_SET_ITEM(argValue, 0, PyFloat_FromDouble(x)); + PyTuple_SET_ITEM(argValue, 1, PyFloat_FromDouble(y)); + } + + if(!PyVecTo(PygetScreenVect(argValue), vect)) { - SetViewport(left, bottom, right, top); - } else { + Py_DECREF(argValue); + PyErr_SetString(PyExc_TypeError, + "Error in getScreenRay. Invalid 2D coordinate. Expected a normalized 2D screen coordinate, a distance and an optional property argument"); return NULL; } - Py_Return; -} + Py_DECREF(argValue); -KX_PYMETHODDEF_DOC(KX_Camera, setOnTop, -"setOnTop()\n" -"Sets this camera's viewport on top\n") -{ - class KX_Scene* scene; - - scene = PHY_GetActiveScene(); - MT_assert(scene); - scene->SetCameraOnTop(this); - Py_Return; + dist = -dist; + vect += this->GetCameraLocation(); + + argValue = (propName?PyTuple_New(3):PyTuple_New(2)); + if (argValue) { + PyTuple_SET_ITEM(argValue, 0, PyObjectFrom(vect)); + PyTuple_SET_ITEM(argValue, 1, PyFloat_FromDouble(dist)); + if (propName) + PyTuple_SET_ITEM(argValue, 2, PyUnicode_FromString(propName)); + + PyObject* ret= this->PyrayCastTo(argValue,NULL); + Py_DECREF(argValue); + return ret; + } + + return NULL; } + diff --git a/source/gameengine/Ketsji/KX_Camera.h b/source/gameengine/Ketsji/KX_Camera.h index 75d574cd697..bf7a39d93c8 100644 --- a/source/gameengine/Ketsji/KX_Camera.h +++ b/source/gameengine/Ketsji/KX_Camera.h @@ -41,10 +41,14 @@ #include "IntValue.h" #include "RAS_CameraData.h" +/* utility conversion function */ +bool ConvertPythonToCamera(PyObject * value, KX_Camera **object, bool py_none_ok, const char *error_prefix); + class KX_Camera : public KX_GameObject { Py_Header; protected: + friend class KX_Scene; /** Camera parameters (clips distances, focal lenght). These * params are closely tied to Blender. In the gameengine, only the * projection and modelview matrices are relevant. There's a @@ -67,6 +71,7 @@ protected: * Storage for the projection matrix that is passed to the * rasterizer. */ MT_Matrix4x4 m_projection_matrix; + //MT_Matrix4x4 m_projection_matrix1; /** * Storage for the modelview matrix that is passed to the @@ -108,9 +113,9 @@ protected: bool m_set_frustum_center; /** - * Python module doc string. + * whether the camera should delete the node itself (only for shadow camera) */ - static char doc[]; + bool m_delete_node; /** * Extracts the camera clip frames from the projection and world-to-camera matrices. @@ -124,11 +129,21 @@ protected: * Extracts the bound sphere of the view frustum. */ void ExtractFrustumSphere(); + /** + * return the clip plane + */ + MT_Vector4 *GetNormalizedClipPlanes() + { + ExtractClipPlanes(); + NormalizeClipPlanes(); + return m_planes; + } + public: - typedef enum { INSIDE, INTERSECT, OUTSIDE } ; + enum { INSIDE, INTERSECT, OUTSIDE } ; - KX_Camera(void* sgReplicationInfo,SG_Callbacks callbacks,const RAS_CameraData& camdata, bool frustum_culling = true, PyTypeObject *T = &Type); + KX_Camera(void* sgReplicationInfo,SG_Callbacks callbacks,const RAS_CameraData& camdata, bool frustum_culling = true, bool delete_node = false); virtual ~KX_Camera(); /** @@ -139,15 +154,7 @@ public: virtual CValue* GetReplica( ); - - /** - * Inherited from CValue -- Makes sure any internal - * data owned by this class is deep copied. Called internally - */ - virtual void - ProcessReplica( - KX_Camera* replica - ); + virtual void ProcessReplica(); MT_Transform GetWorldToCamera() const; MT_Transform GetCameraToWorld() const; @@ -186,6 +193,8 @@ public: /** Gets the aperture. */ float GetLens() const; + /** Gets the ortho scale. */ + float GetScale() const; /** Gets the near clip distance. */ float GetCameraNear() const; /** Gets the far clip distance. */ @@ -256,23 +265,45 @@ public: */ int GetViewportTop() const; + virtual int GetGameObjectType() { return OBJ_CAMERA; } - KX_PYMETHOD_DOC(KX_Camera, sphereInsideFrustum); - KX_PYMETHOD_DOC(KX_Camera, boxInsideFrustum); - KX_PYMETHOD_DOC(KX_Camera, pointInsideFrustum); + KX_PYMETHOD_DOC_VARARGS(KX_Camera, sphereInsideFrustum); + KX_PYMETHOD_DOC_O(KX_Camera, boxInsideFrustum); + KX_PYMETHOD_DOC_O(KX_Camera, pointInsideFrustum); - KX_PYMETHOD_DOC(KX_Camera, getCameraToWorld); - KX_PYMETHOD_DOC(KX_Camera, getWorldToCamera); - KX_PYMETHOD_DOC(KX_Camera, getProjectionMatrix); - KX_PYMETHOD_DOC(KX_Camera, setProjectionMatrix); + KX_PYMETHOD_DOC_NOARGS(KX_Camera, getCameraToWorld); + KX_PYMETHOD_DOC_NOARGS(KX_Camera, getWorldToCamera); - KX_PYMETHOD_DOC(KX_Camera, enableViewport); - KX_PYMETHOD_DOC(KX_Camera, setViewport); - KX_PYMETHOD_DOC(KX_Camera, setOnTop); + KX_PYMETHOD_DOC_VARARGS(KX_Camera, setViewport); + KX_PYMETHOD_DOC_NOARGS(KX_Camera, setOnTop); - virtual PyObject* _getattr(const STR_String& attr); /* lens, near, far, projection_matrix */ - virtual int _setattr(const STR_String& attr, PyObject *pyvalue); + KX_PYMETHOD_DOC_O(KX_Camera, getScreenPosition); + KX_PYMETHOD_DOC_VARARGS(KX_Camera, getScreenVect); + KX_PYMETHOD_DOC_VARARGS(KX_Camera, getScreenRay); + + static PyObject* pyattr_get_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject* pyattr_get_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject* pyattr_get_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject* pyattr_get_modelview_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_camera_to_world(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_world_to_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + + static PyObject* pyattr_get_INSIDE(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_OUTSIDE(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_INTERSECT(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); }; #endif //__KX_CAMERA diff --git a/source/gameengine/Ketsji/KX_CameraActuator.cpp b/source/gameengine/Ketsji/KX_CameraActuator.cpp index 4d24e83843e..9c00b5991af 100644 --- a/source/gameengine/Ketsji/KX_CameraActuator.cpp +++ b/source/gameengine/Ketsji/KX_CameraActuator.cpp @@ -33,13 +33,11 @@ #include "KX_CameraActuator.h" #include <iostream> #include <math.h> +#include <float.h> #include "KX_GameObject.h" #include "PyObjectPlus.h" -STR_String KX_CameraActuator::X_AXIS_STRING = "x"; -STR_String KX_CameraActuator::Y_AXIS_STRING = "y"; - #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -52,13 +50,12 @@ STR_String KX_CameraActuator::Y_AXIS_STRING = "y"; KX_CameraActuator::KX_CameraActuator( SCA_IObject* gameobj, SCA_IObject *obj, - MT_Scalar hght, - MT_Scalar minhght, - MT_Scalar maxhght, - bool xytog, - PyTypeObject* T + float hght, + float minhght, + float maxhght, + bool xytog ): - SCA_IActuator(gameobj, T), + SCA_IActuator(gameobj), m_ob (obj), m_height (hght), m_minHeight (minhght), @@ -81,8 +78,6 @@ GetReplica( ) { KX_CameraActuator* replica = new KX_CameraActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; }; @@ -355,211 +350,70 @@ CValue *KX_CameraActuator::findObject(char *obName) return NULL; } -bool KX_CameraActuator::string2axischoice(const char *axisString) -{ - bool res = true; - - res = !(axisString == Y_AXIS_STRING); - - return res; -} - /* ------------------------------------------------------------------------- */ /* Python functions */ /* ------------------------------------------------------------------------- */ /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_CameraActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_CameraActuator", - sizeof(KX_CameraActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_CameraActuator::Parents[] = { - &KX_CameraActuator::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_CameraActuator::Methods[] = { - {"setObject",(PyCFunction) KX_CameraActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc}, - {"getObject",(PyCFunction) KX_CameraActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc}, - {"setMin" ,(PyCFunction) KX_CameraActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetMin_doc}, - {"getMin" ,(PyCFunction) KX_CameraActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetMin_doc}, - {"setMax" ,(PyCFunction) KX_CameraActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetMax_doc}, - {"getMax" ,(PyCFunction) KX_CameraActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetMax_doc}, - {"setHeight",(PyCFunction) KX_CameraActuator::sPySetHeight, METH_VARARGS, (PY_METHODCHAR)SetHeight_doc}, - {"getHeight",(PyCFunction) KX_CameraActuator::sPyGetHeight, METH_NOARGS, (PY_METHODCHAR)GetHeight_doc}, - {"setXY" ,(PyCFunction) KX_CameraActuator::sPySetXY, METH_VARARGS, (PY_METHODCHAR)SetXY_doc}, - {"getXY" ,(PyCFunction) KX_CameraActuator::sPyGetXY, METH_VARARGS, (PY_METHODCHAR)GetXY_doc}, {NULL,NULL,NULL,NULL} //Sentinel }; -PyObject* KX_CameraActuator::_getattr(const STR_String& attr) { - _getattr_up(SCA_IActuator); -} -/* get obj ---------------------------------------------------------- */ -const char KX_CameraActuator::GetObject_doc[] = -"getObject(name_only = 1)\n" -"name_only - optional arg, when true will return the KX_GameObject rather then its name\n" -"\tReturns the object this sensor reacts to.\n"; -PyObject* KX_CameraActuator::PyGetObject(PyObject* self, PyObject* args) +PyAttributeDef KX_CameraActuator::Attributes[] = { + KX_PYATTRIBUTE_FLOAT_RW("min",-FLT_MAX,FLT_MAX,KX_CameraActuator,m_minHeight), + KX_PYATTRIBUTE_FLOAT_RW("max",-FLT_MAX,FLT_MAX,KX_CameraActuator,m_maxHeight), + KX_PYATTRIBUTE_FLOAT_RW("height",-FLT_MAX,FLT_MAX,KX_CameraActuator,m_height), + KX_PYATTRIBUTE_BOOL_RW("useXY",KX_CameraActuator,m_x), + KX_PYATTRIBUTE_RW_FUNCTION("object", KX_CameraActuator, pyattr_get_object, pyattr_set_object), + {NULL} +}; + +PyObject* KX_CameraActuator::pyattr_get_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - int ret_name_only = 1; - if (!PyArg_ParseTuple(args, "|i", &ret_name_only)) - return NULL; - - if (!m_ob) + KX_CameraActuator* self= static_cast<KX_CameraActuator*>(self_v); + if (self->m_ob==NULL) Py_RETURN_NONE; - - if (ret_name_only) - return PyString_FromString(m_ob->GetName()); else - return m_ob->AddRef(); + return self->m_ob->GetProxy(); } -/* set obj ---------------------------------------------------------- */ -const char KX_CameraActuator::SetObject_doc[] = -"setObject(object)\n" -"\t- object: KX_GameObject, string or None\n" -"\tSets the object this sensor reacts to.\n"; -PyObject* KX_CameraActuator::PySetObject(PyObject* self, PyObject* value) + +int KX_CameraActuator::pyattr_set_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { + KX_CameraActuator* self= static_cast<KX_CameraActuator*>(self_v); KX_GameObject *gameobj; - if (!ConvertPythonToGameObject(value, &gameobj, true)) - return NULL; // ConvertPythonToGameObject sets the error + if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_CameraActuator")) + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error - if (m_ob != NULL) - m_ob->UnregisterActuator(this); + if (self->m_ob) + self->m_ob->UnregisterActuator(self); - m_ob = (SCA_IObject*)gameobj; - if (m_ob) - m_ob->RegisterActuator(this); + if ((self->m_ob = (SCA_IObject*)gameobj)) + self->m_ob->RegisterActuator(self); - Py_RETURN_NONE; -} - -/* get min ---------------------------------------------------------- */ -const char KX_CameraActuator::GetMin_doc[] = -"getMin\n" -"\tReturns the minimum value set in the Min: field.\n"; -PyObject* KX_CameraActuator::PyGetMin(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - return PyFloat_FromDouble(m_minHeight); -} -/* set min ---------------------------------------------------------- */ -const char KX_CameraActuator::SetMin_doc[] = -"setMin\n" -"\tSets the minimum value.\n"; -PyObject* KX_CameraActuator::PySetMin(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - float min; - if(PyArg_ParseTuple(args,"f", &min)) - { - m_minHeight = min; - Py_Return; - } - return NULL; -} -/* get min ---------------------------------------------------------- */ -const char KX_CameraActuator::GetMax_doc[] = -"getMax\n" -"\tReturns the maximum value set in the Max: field.\n"; -PyObject* KX_CameraActuator::PyGetMax(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - return PyFloat_FromDouble(m_maxHeight); -} -/* set min ---------------------------------------------------------- */ -const char KX_CameraActuator::SetMax_doc[] = -"setMax\n" -"\tSets the maximum value.\n"; -PyObject* KX_CameraActuator::PySetMax(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - float max; - if(PyArg_ParseTuple(args,"f", &max)) - { - m_maxHeight = max; - Py_Return; - } - return NULL; -} -/* get height ---------------------------------------------------------- */ -const char KX_CameraActuator::GetHeight_doc[] = -"getHeight\n" -"\tReturns the height value set in the height: field.\n"; -PyObject* KX_CameraActuator::PyGetHeight(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - return PyFloat_FromDouble(m_height); -} -/* set height ---------------------------------------------------------- */ -const char KX_CameraActuator::SetHeight_doc[] = -"setHeight\n" -"\tSets the height value.\n"; -PyObject* KX_CameraActuator::PySetHeight(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - float height; - if(PyArg_ParseTuple(args,"f", &height)) - { - m_height = height; - Py_Return; - } - return NULL; -} -/* set XY ---------------------------------------------------------- */ -const char KX_CameraActuator::SetXY_doc[] = -"setXY\n" -"\tSets axis the camera tries to get behind.\n" -"\t1=x, 0=y\n"; -PyObject* KX_CameraActuator::PySetXY(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - int value; - if(PyArg_ParseTuple(args,"i", &value)) - { - m_x = value != 0; - Py_Return; - } - return NULL; -} - -/* get XY -------------------------------------------------------------*/ -const char KX_CameraActuator::GetXY_doc[] = -"getXY\n" -"\tGets the axis the camera tries to get behind.\n" -"\tTrue = X, False = Y\n"; -PyObject* KX_CameraActuator::PyGetXY(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - return PyInt_FromLong(m_x); + return PY_SET_ATTR_SUCCESS; } /* eof */ diff --git a/source/gameengine/Ketsji/KX_CameraActuator.h b/source/gameengine/Ketsji/KX_CameraActuator.h index d53d12b3b82..e047e3724ea 100644 --- a/source/gameengine/Ketsji/KX_CameraActuator.h +++ b/source/gameengine/Ketsji/KX_CameraActuator.h @@ -59,13 +59,13 @@ private : //const MT_Scalar m_maxHeight; /** height (float), */ - MT_Scalar m_height; + float m_height; /** min (float), */ - MT_Scalar m_minHeight; + float m_minHeight; /** max (float), */ - MT_Scalar m_maxHeight; + float m_maxHeight; /** xy toggle (pick one): true == x, false == y */ bool m_x; @@ -88,12 +88,10 @@ private : SCA_IObject *gameobj, //const CValue *ob, SCA_IObject *ob, - MT_Scalar hght, - MT_Scalar minhght, - MT_Scalar maxhght, - bool xytog, - PyTypeObject* T=&Type - + float hght, + float minhght, + float maxhght, + bool xytog ); @@ -120,20 +118,9 @@ private : /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); - /* set object to look at */ - KX_PYMETHOD_DOC_O(KX_CameraActuator,SetObject); - /* get current object */ - KX_PYMETHOD_DOC_VARARGS(KX_CameraActuator,GetObject); - KX_PYMETHOD_DOC(KX_CameraActuator,SetMin); - KX_PYMETHOD_DOC(KX_CameraActuator,GetMin); - KX_PYMETHOD_DOC(KX_CameraActuator,SetMax); - KX_PYMETHOD_DOC(KX_CameraActuator,GetMax); - KX_PYMETHOD_DOC(KX_CameraActuator,SetHeight); - KX_PYMETHOD_DOC(KX_CameraActuator,GetHeight); - KX_PYMETHOD_DOC(KX_CameraActuator,SetXY); - KX_PYMETHOD_DOC(KX_CameraActuator,GetXY); + static PyObject* pyattr_get_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); }; diff --git a/source/gameengine/Ketsji/KX_CameraIpoSGController.h b/source/gameengine/Ketsji/KX_CameraIpoSGController.h index 33245e79c23..85d93962a14 100644 --- a/source/gameengine/Ketsji/KX_CameraIpoSGController.h +++ b/source/gameengine/Ketsji/KX_CameraIpoSGController.h @@ -84,6 +84,13 @@ public: m_modify_clipstart = modify; } void AddInterpolator(KX_IInterpolator* interp); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_CameraIpoSGController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // KX_CAMERAIPOSGCONTROLLER_H diff --git a/source/gameengine/Ketsji/KX_ClientObjectInfo.h b/source/gameengine/Ketsji/KX_ClientObjectInfo.h index 5e8af0f040c..74647dd47fd 100644 --- a/source/gameengine/Ketsji/KX_ClientObjectInfo.h +++ b/source/gameengine/Ketsji/KX_ClientObjectInfo.h @@ -29,7 +29,7 @@ #ifndef __KX_CLIENTOBJECT_INFO_H #define __KX_CLIENTOBJECT_INFO_H -#include <SM_Object.h> +/* Note, the way this works with/without sumo is a bit odd */ #include <list> @@ -38,28 +38,27 @@ class KX_GameObject; /** * Client Type and Additional Info. This structure can be use instead of a bare void* pointer, for safeness, and additional info for callbacks */ -struct KX_ClientObjectInfo : public SM_ClientObject +struct KX_ClientObjectInfo { enum clienttype { STATIC, ACTOR, RESERVED1, - RADAR, - NEAR + SENSOR, + OBSENSOR, + OBACTORSENSOR } m_type; KX_GameObject* m_gameobject; void* m_auxilary_info; std::list<SCA_ISensor*> m_sensors; public: KX_ClientObjectInfo(KX_GameObject *gameobject, clienttype type = STATIC, void *auxilary_info = NULL) : - SM_ClientObject(), m_type(type), m_gameobject(gameobject), m_auxilary_info(auxilary_info) {} - KX_ClientObjectInfo(const KX_ClientObjectInfo ©) - : SM_ClientObject(copy), + KX_ClientObjectInfo(const KX_ClientObjectInfo ©) : m_type(copy.m_type), m_gameobject(copy.m_gameobject), m_auxilary_info(copy.m_auxilary_info) @@ -74,6 +73,14 @@ public: } bool isActor() { return m_type <= ACTOR; } + bool isSensor() { return m_type >= SENSOR && m_type <= OBACTORSENSOR; } + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_ClientObjectInfo"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_CLIENTOBJECT_INFO_H diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp index 76357e9c58f..7f1d2c7d53c 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp @@ -36,6 +36,7 @@ #include "MT_Matrix3x3.h" #include "KX_GameObject.h" #include "KX_RayCast.h" +#include "KX_PythonInit.h" // KX_GetActiveScene #ifdef HAVE_CONFIG_H #include <config.h> @@ -54,22 +55,23 @@ KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj, int locrotxyz, int time, int option, - char *property, - PyTypeObject* T) : - m_refDirection(refDir), - m_currentTime(0), - SCA_IActuator(gameobj, T) + char *property) : + SCA_IActuator(gameobj), + m_refDirVector(refDir), + m_currentTime(0) { + m_refDirection[0] = refDir[0]; + m_refDirection[1] = refDir[1]; + m_refDirection[2] = refDir[2]; m_posDampTime = posDampTime; m_rotDampTime = rotDampTime; m_locrot = locrotxyz; m_option = option; m_activeTime = time; if (property) { - strncpy(m_property, property, sizeof(m_property)); - m_property[sizeof(m_property)-1] = 0; + m_property = property; } else { - m_property[0] = 0; + m_property = ""; } /* The units of bounds are determined by the type of constraint. To */ /* make the constraint application easier and more transparent later on, */ @@ -80,13 +82,16 @@ KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj, case KX_ACT_CONSTRAINT_ORIY: case KX_ACT_CONSTRAINT_ORIZ: { - MT_Scalar len = m_refDirection.length(); + MT_Scalar len = m_refDirVector.length(); if (MT_fuzzyZero(len)) { // missing a valid direction std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no valid reference direction!" << std::endl; m_locrot = KX_ACT_CONSTRAINT_NODEF; } else { - m_refDirection /= len; + m_refDirection[0] /= len; + m_refDirection[1] /= len; + m_refDirection[2] /= len; + m_refDirVector /= len; } m_minimumBound = cos(minBound); m_maximumBound = cos(maxBound); @@ -116,7 +121,7 @@ bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* resu bool bFound = false; - if (m_property[0] == 0) + if (m_property.IsEmpty()) { bFound = true; } @@ -126,7 +131,7 @@ bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* resu { if (client->m_auxilary_info) { - bFound = !strcmp(m_property, ((char*)client->m_auxilary_info)); + bFound = !strcmp(m_property.Ptr(), ((char*)client->m_auxilary_info)); } } else @@ -209,7 +214,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) if ((m_maximumBound < (1.0f-FLT_EPSILON)) || (m_minimumBound < (1.0f-FLT_EPSILON))) { // reference direction needs to be evaluated // 1. get the cosine between current direction and target - cosangle = direction.dot(m_refDirection); + cosangle = direction.dot(m_refDirVector); if (cosangle >= (m_maximumBound-FLT_EPSILON) && cosangle <= (m_minimumBound+FLT_EPSILON)) { // no change to do result = true; @@ -218,27 +223,27 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) // 2. define a new reference direction // compute local axis with reference direction as X and // Y in direction X refDirection plane - MT_Vector3 zaxis = m_refDirection.cross(direction); + MT_Vector3 zaxis = m_refDirVector.cross(direction); if (MT_fuzzyZero2(zaxis.length2())) { // direction and refDirection are identical, // choose any other direction to define plane if (direction[0] < 0.9999) - zaxis = m_refDirection.cross(MT_Vector3(1.0,0.0,0.0)); + zaxis = m_refDirVector.cross(MT_Vector3(1.0,0.0,0.0)); else - zaxis = m_refDirection.cross(MT_Vector3(0.0,1.0,0.0)); + zaxis = m_refDirVector.cross(MT_Vector3(0.0,1.0,0.0)); } - MT_Vector3 yaxis = zaxis.cross(m_refDirection); + MT_Vector3 yaxis = zaxis.cross(m_refDirVector); yaxis.normalize(); if (cosangle > m_minimumBound) { // angle is too close to reference direction, // choose a new reference that is exactly at minimum angle - refDirection = m_minimumBound * m_refDirection + m_minimumSine * yaxis; + refDirection = m_minimumBound * m_refDirVector + m_minimumSine * yaxis; } else { // angle is too large, choose new reference direction at maximum angle - refDirection = m_maximumBound * m_refDirection + m_maximumSine * yaxis; + refDirection = m_maximumBound * m_refDirVector + m_maximumSine * yaxis; } } else { - refDirection = m_refDirection; + refDirection = m_refDirVector; } // apply damping on the direction direction = filter*direction + (1.0-filter)*refDirection; @@ -323,7 +328,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) } { MT_Point3 topoint = position + (m_maximumBound) * direction; - PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment(); + PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment(); KX_IPhysicsController *spc = obj->GetPhysicsController(); if (!pe) { @@ -436,7 +441,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) } normal.normalize(); { - PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment(); + PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment(); KX_IPhysicsController *spc = obj->GetPhysicsController(); if (!pe) { @@ -470,7 +475,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) // Fh force is stored in m_maximum MT_Scalar springForce = springExtent * m_maximumBound; // damping is stored in m_refDirection [0] = damping, [1] = rot damping - MT_Scalar springDamp = relativeVelocityRay * m_refDirection[0]; + MT_Scalar springDamp = relativeVelocityRay * m_refDirVector[0]; MT_Vector3 newVelocity = spc->GetLinearVelocity()-(springForce+springDamp)*direction; if (m_option & KX_ACT_CONSTRAINT_NORMAL) { @@ -483,7 +488,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) MT_Vector3 angVelocity = spc->GetAngularVelocity(); // remove component that is parallel to normal angVelocity -= angVelocity.dot(newnormal)*newnormal; - MT_Vector3 angDamp = angVelocity * ((m_refDirection[1]>MT_EPSILON)?m_refDirection[1]:m_refDirection[0]); + MT_Vector3 angDamp = angVelocity * ((m_refDirVector[1]>MT_EPSILON)?m_refDirVector[1]:m_refDirVector[0]); spc->SetAngularVelocity(spc->GetAngularVelocity()+(angSpring-angDamp), false); } } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) { @@ -560,372 +565,57 @@ bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_ConstraintActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_ConstraintActuator", - sizeof(KX_ConstraintActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_ConstraintActuator::Parents[] = { - &KX_ConstraintActuator::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_ConstraintActuator::Methods[] = { - {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, (PY_METHODCHAR)SetDamp_doc}, - {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_NOARGS, (PY_METHODCHAR)GetDamp_doc}, - {"setRotDamp", (PyCFunction) KX_ConstraintActuator::sPySetRotDamp, METH_VARARGS, (PY_METHODCHAR)SetRotDamp_doc}, - {"getRotDamp", (PyCFunction) KX_ConstraintActuator::sPyGetRotDamp, METH_NOARGS, (PY_METHODCHAR)GetRotDamp_doc}, - {"setDirection", (PyCFunction) KX_ConstraintActuator::sPySetDirection, METH_VARARGS, (PY_METHODCHAR)SetDirection_doc}, - {"getDirection", (PyCFunction) KX_ConstraintActuator::sPyGetDirection, METH_NOARGS, (PY_METHODCHAR)GetDirection_doc}, - {"setOption", (PyCFunction) KX_ConstraintActuator::sPySetOption, METH_VARARGS, (PY_METHODCHAR)SetOption_doc}, - {"getOption", (PyCFunction) KX_ConstraintActuator::sPyGetOption, METH_NOARGS, (PY_METHODCHAR)GetOption_doc}, - {"setTime", (PyCFunction) KX_ConstraintActuator::sPySetTime, METH_VARARGS, (PY_METHODCHAR)SetTime_doc}, - {"getTime", (PyCFunction) KX_ConstraintActuator::sPyGetTime, METH_NOARGS, (PY_METHODCHAR)GetTime_doc}, - {"setProperty", (PyCFunction) KX_ConstraintActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, - {"getProperty", (PyCFunction) KX_ConstraintActuator::sPyGetProperty, METH_NOARGS, (PY_METHODCHAR)GetProperty_doc}, - {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetMin_doc}, - {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetMin_doc}, - {"setDistance", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetDistance_doc}, - {"getDistance", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetDistance_doc}, - {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetMax_doc}, - {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetMax_doc}, - {"setRayLength", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetRayLength_doc}, - {"getRayLength", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetRayLength_doc}, - {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, (PY_METHODCHAR)SetLimit_doc}, - {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_NOARGS, (PY_METHODCHAR)GetLimit_doc}, {NULL,NULL} //Sentinel }; -PyObject* KX_ConstraintActuator::_getattr(const STR_String& attr) { - _getattr_up(SCA_IActuator); -} - -/* 2. setDamp */ -const char KX_ConstraintActuator::SetDamp_doc[] = -"setDamp(duration)\n" -"\t- duration: integer\n" -"\tSets the time constant of the orientation and distance constraint.\n" -"\tIf the duration is negative, it is set to 0.\n"; -PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self, - PyObject* args, - PyObject* kwds) { - int dampArg; - if(!PyArg_ParseTuple(args, "i", &dampArg)) { - return NULL; - } - - m_posDampTime = dampArg; - if (m_posDampTime < 0) m_posDampTime = 0; - - Py_Return; -} -/* 3. getDamp */ -const char KX_ConstraintActuator::GetDamp_doc[] = -"getDamp()\n" -"\tReturns the damping parameter.\n"; -PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self){ - return PyInt_FromLong(m_posDampTime); -} - -/* 2. setRotDamp */ -const char KX_ConstraintActuator::SetRotDamp_doc[] = -"setRotDamp(duration)\n" -"\t- duration: integer\n" -"\tSets the time constant of the orientation constraint.\n" -"\tIf the duration is negative, it is set to 0.\n"; -PyObject* KX_ConstraintActuator::PySetRotDamp(PyObject* self, - PyObject* args, - PyObject* kwds) { - int dampArg; - if(!PyArg_ParseTuple(args, "i", &dampArg)) { - return NULL; - } - - m_rotDampTime = dampArg; - if (m_rotDampTime < 0) m_rotDampTime = 0; - - Py_Return; -} -/* 3. getRotDamp */ -const char KX_ConstraintActuator::GetRotDamp_doc[] = -"getRotDamp()\n" -"\tReturns the damping time for application of the constraint.\n"; -PyObject* KX_ConstraintActuator::PyGetRotDamp(PyObject* self){ - return PyInt_FromLong(m_rotDampTime); -} - -/* 2. setDirection */ -const char KX_ConstraintActuator::SetDirection_doc[] = -"setDirection(vector)\n" -"\t- vector: 3-tuple\n" -"\tSets the reference direction in world coordinate for the orientation constraint.\n"; -PyObject* KX_ConstraintActuator::PySetDirection(PyObject* self, - PyObject* args, - PyObject* kwds) { - float x, y, z; - MT_Scalar len; - MT_Vector3 dir; +PyAttributeDef KX_ConstraintActuator::Attributes[] = { + KX_PYATTRIBUTE_INT_RW("damp",0,100,true,KX_ConstraintActuator,m_posDampTime), + KX_PYATTRIBUTE_INT_RW("rotDamp",0,100,true,KX_ConstraintActuator,m_rotDampTime), + KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK("direction",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_refDirection,3,pyattr_check_direction), + KX_PYATTRIBUTE_INT_RW("option",0,0xFFFF,false,KX_ConstraintActuator,m_option), + KX_PYATTRIBUTE_INT_RW("time",0,1000,true,KX_ConstraintActuator,m_activeTime), + KX_PYATTRIBUTE_STRING_RW("propName",0,32,true,KX_ConstraintActuator,m_property), + KX_PYATTRIBUTE_FLOAT_RW("min",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_minimumBound), + KX_PYATTRIBUTE_FLOAT_RW("distance",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_minimumBound), + KX_PYATTRIBUTE_FLOAT_RW("max",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_maximumBound), + KX_PYATTRIBUTE_FLOAT_RW("rayLength",0,2000.f,KX_ConstraintActuator,m_maximumBound), + KX_PYATTRIBUTE_INT_RW("limit",KX_ConstraintActuator::KX_ACT_CONSTRAINT_NODEF+1,KX_ConstraintActuator::KX_ACT_CONSTRAINT_MAX-1,false,KX_ConstraintActuator,m_locrot), + { NULL } //Sentinel +}; - if(!PyArg_ParseTuple(args, "(fff)", &x, &y, &z)) { - return NULL; - } - dir[0] = x; - dir[1] = y; - dir[2] = z; - len = dir.length(); +int KX_ConstraintActuator::pyattr_check_direction(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_ConstraintActuator* act = static_cast<KX_ConstraintActuator*>(self); + MT_Vector3 dir(act->m_refDirection); + MT_Scalar len = dir.length(); if (MT_fuzzyZero(len)) { - std::cout << "Invalid direction" << std::endl; - return NULL; - } - m_refDirection = dir/len; - - Py_Return; -} -/* 3. getDirection */ -const char KX_ConstraintActuator::GetDirection_doc[] = -"getDirection()\n" -"\tReturns the reference direction of the orientation constraint as a 3-tuple.\n"; -PyObject* KX_ConstraintActuator::PyGetDirection(PyObject* self){ - PyObject *retVal = PyList_New(3); - - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_refDirection[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_refDirection[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_refDirection[2])); - return retVal; -} - -/* 2. setOption */ -const char KX_ConstraintActuator::SetOption_doc[] = -"setOption(option)\n" -"\t- option: integer\n" -"\tSets several options of the distance constraint.\n" -"\tBinary combination of the following values:\n" -"\t\t 64 : Activate alignment to surface\n" -"\t\t128 : Detect material rather than property\n" -"\t\t256 : No deactivation if ray does not hit target\n" -"\t\t512 : Activate distance control\n"; -PyObject* KX_ConstraintActuator::PySetOption(PyObject* self, - PyObject* args, - PyObject* kwds) { - int option; - if(!PyArg_ParseTuple(args, "i", &option)) { - return NULL; - } - - m_option = option; - - Py_Return; -} -/* 3. getOption */ -const char KX_ConstraintActuator::GetOption_doc[] = -"getOption()\n" -"\tReturns the option parameter.\n"; -PyObject* KX_ConstraintActuator::PyGetOption(PyObject* self){ - return PyInt_FromLong(m_option); -} - -/* 2. setTime */ -const char KX_ConstraintActuator::SetTime_doc[] = -"setTime(duration)\n" -"\t- duration: integer\n" -"\tSets the activation time of the actuator.\n" -"\tThe actuator disables itself after this many frame.\n" -"\tIf set to 0 or negative, the actuator is not limited in time.\n"; -PyObject* KX_ConstraintActuator::PySetTime(PyObject* self, - PyObject* args, - PyObject* kwds) { - int t; - if(!PyArg_ParseTuple(args, "i", &t)) { - return NULL; - } - - if (t < 0) - t = 0; - m_activeTime = t; - - Py_Return; -} -/* 3. getTime */ -const char KX_ConstraintActuator::GetTime_doc[] = -"getTime()\n" -"\tReturns the time parameter.\n"; -PyObject* KX_ConstraintActuator::PyGetTime(PyObject* self){ - return PyInt_FromLong(m_activeTime); -} - -/* 2. setProperty */ -const char KX_ConstraintActuator::SetProperty_doc[] = -"setProperty(property)\n" -"\t- property: string\n" -"\tSets the name of the property or material for the ray detection of the distance constraint.\n" -"\tIf empty, the ray will detect any collisioning object.\n"; -PyObject* KX_ConstraintActuator::PySetProperty(PyObject* self, - PyObject* args, - PyObject* kwds) { - char *property; - if (!PyArg_ParseTuple(args, "s", &property)) { - return NULL; - } - if (property == NULL) { - m_property[0] = 0; - } else { - strncpy(m_property, property, sizeof(m_property)); - m_property[sizeof(m_property)-1] = 0; + PyErr_SetString(PyExc_ValueError, "actuator.direction = vec: KX_ConstraintActuator, invalid direction"); + return 1; } - - Py_Return; -} -/* 3. getProperty */ -const char KX_ConstraintActuator::GetProperty_doc[] = -"getProperty()\n" -"\tReturns the property parameter.\n"; -PyObject* KX_ConstraintActuator::PyGetProperty(PyObject* self){ - return PyString_FromString(m_property); -} - -/* 4. setDistance */ -const char KX_ConstraintActuator::SetDistance_doc[] = -"setDistance(distance)\n" -"\t- distance: float\n" -"\tSets the target distance in distance constraint\n"; -/* 4. setMin */ -const char KX_ConstraintActuator::SetMin_doc[] = -"setMin(lower_bound)\n" -"\t- lower_bound: float\n" -"\tSets the lower value of the interval to which the value\n" -"\tis clipped.\n"; -PyObject* KX_ConstraintActuator::PySetMin(PyObject* self, - PyObject* args, - PyObject* kwds) { - float minArg; - if(!PyArg_ParseTuple(args, "f", &minArg)) { - return NULL; - } - - switch (m_locrot) { - default: - m_minimumBound = minArg; - break; - case KX_ACT_CONSTRAINT_ROTX: - case KX_ACT_CONSTRAINT_ROTY: - case KX_ACT_CONSTRAINT_ROTZ: - m_minimumBound = MT_radians(minArg); - break; - } - - Py_Return; -} -/* 5. getDistance */ -const char KX_ConstraintActuator::GetDistance_doc[] = -"getDistance()\n" -"\tReturns the distance parameter \n"; -/* 5. getMin */ -const char KX_ConstraintActuator::GetMin_doc[] = -"getMin()\n" -"\tReturns the lower value of the interval to which the value\n" -"\tis clipped.\n"; -PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self) { - return PyFloat_FromDouble(m_minimumBound); -} - -/* 6. setRayLength */ -const char KX_ConstraintActuator::SetRayLength_doc[] = -"setRayLength(length)\n" -"\t- length: float\n" -"\tSets the maximum ray length of the distance constraint\n"; -/* 6. setMax */ -const char KX_ConstraintActuator::SetMax_doc[] = -"setMax(upper_bound)\n" -"\t- upper_bound: float\n" -"\tSets the upper value of the interval to which the value\n" -"\tis clipped.\n"; -PyObject* KX_ConstraintActuator::PySetMax(PyObject* self, - PyObject* args, - PyObject* kwds){ - float maxArg; - if(!PyArg_ParseTuple(args, "f", &maxArg)) { - return NULL; - } - - switch (m_locrot) { - default: - m_maximumBound = maxArg; - break; - case KX_ACT_CONSTRAINT_ROTX: - case KX_ACT_CONSTRAINT_ROTY: - case KX_ACT_CONSTRAINT_ROTZ: - m_maximumBound = MT_radians(maxArg); - break; - } - - Py_Return; -} -/* 7. getRayLength */ -const char KX_ConstraintActuator::GetRayLength_doc[] = -"getRayLength()\n" -"\tReturns the length of the ray\n"; -/* 7. getMax */ -const char KX_ConstraintActuator::GetMax_doc[] = -"getMax()\n" -"\tReturns the upper value of the interval to which the value\n" -"\tis clipped.\n"; -PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self) { - return PyFloat_FromDouble(m_maximumBound); -} - - -/* This setter/getter probably for the constraint type */ -/* 8. setLimit */ -const char KX_ConstraintActuator::SetLimit_doc[] = -"setLimit(type)\n" -"\t- type: integer\n" -"\t 1 : LocX\n" -"\t 2 : LocY\n" -"\t 3 : LocZ\n" -"\t 7 : Distance along +X axis\n" -"\t 8 : Distance along +Y axis\n" -"\t 9 : Distance along +Z axis\n" -"\t 10 : Distance along -X axis\n" -"\t 11 : Distance along -Y axis\n" -"\t 12 : Distance along -Z axis\n" -"\t 13 : Align X axis\n" -"\t 14 : Align Y axis\n" -"\t 15 : Align Z axis\n" -"\tSets the type of constraint.\n"; -PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self, - PyObject* args, - PyObject* kwds) { - int locrotArg; - if(!PyArg_ParseTuple(args, "i", &locrotArg)) { - return NULL; - } - - if (IsValidMode((KX_CONSTRAINTTYPE)locrotArg)) m_locrot = locrotArg; - - Py_Return; -} -/* 9. getLimit */ -const char KX_ConstraintActuator::GetLimit_doc[] = -"getLimit()\n" -"\tReturns the type of constraint.\n"; -PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self) { - return PyInt_FromLong(m_locrot); + act->m_refDirVector = dir/len; + return 0; } /* eof */ diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.h b/source/gameengine/Ketsji/KX_ConstraintActuator.h index 28b9b1e6a0b..9b6ed59e75c 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.h +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.h @@ -56,7 +56,8 @@ protected: // sinus of maximum angle float m_maximumSine; // reference direction - MT_Vector3 m_refDirection; + float m_refDirection[3]; + MT_Vector3 m_refDirVector; // same as m_refDirection // locrotxyz choice (pick one): only one choice allowed at a time! int m_locrot; // active time of actuator @@ -65,7 +66,7 @@ protected: // option int m_option; // property to check - char m_property[32]; + STR_String m_property; // hit object KX_GameObject* m_hitObject; @@ -125,14 +126,11 @@ protected: int locrot, int time, int option, - char *property, - PyTypeObject* T=&Type); + char *property); virtual ~KX_ConstraintActuator(); virtual CValue* GetReplica() { KX_ConstraintActuator* replica = new KX_ConstraintActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; }; @@ -142,30 +140,9 @@ protected: /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); + static int pyattr_check_direction(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_check_min(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - KX_PYMETHOD_DOC(KX_ConstraintActuator,SetDamp); - KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetDamp); - KX_PYMETHOD_DOC(KX_ConstraintActuator,SetRotDamp); - KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetRotDamp); - KX_PYMETHOD_DOC(KX_ConstraintActuator,SetDirection); - KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetDirection); - KX_PYMETHOD_DOC(KX_ConstraintActuator,SetOption); - KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetOption); - KX_PYMETHOD_DOC(KX_ConstraintActuator,SetTime); - KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetTime); - KX_PYMETHOD_DOC(KX_ConstraintActuator,SetProperty); - KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetProperty); - KX_PYMETHOD_DOC(KX_ConstraintActuator,SetMin); - KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetMin); - static const char SetDistance_doc[]; - static const char GetDistance_doc[]; - KX_PYMETHOD_DOC(KX_ConstraintActuator,SetMax); - KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetMax); - static const char SetRayLength_doc[]; - static const char GetRayLength_doc[]; - KX_PYMETHOD_DOC(KX_ConstraintActuator,SetLimit); - KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetLimit); }; #endif //__KX_CONSTRAINTACTUATOR diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp index c9095ff34f6..54e083b48f0 100644 --- a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp @@ -38,8 +38,8 @@ KX_ConstraintWrapper::KX_ConstraintWrapper( PHY_ConstraintType ctype, int constraintId, - PHY_IPhysicsEnvironment* physenv,PyTypeObject *T) : - PyObjectPlus(T), + PHY_IPhysicsEnvironment* physenv) : + PyObjectPlus(), m_constraintId(constraintId), m_constraintType(ctype), m_physenv(physenv) @@ -48,87 +48,70 @@ KX_ConstraintWrapper::KX_ConstraintWrapper( KX_ConstraintWrapper::~KX_ConstraintWrapper() { } -//python integration methods -PyObject* KX_ConstraintWrapper::PyTestMethod(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - - Py_RETURN_NONE; -} -PyObject* KX_ConstraintWrapper::PyGetConstraintId(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_ConstraintWrapper::PyGetConstraintId() { - return PyInt_FromLong(m_constraintId); + return PyLong_FromSsize_t(m_constraintId); } - - -//python specific stuff -PyTypeObject KX_ConstraintWrapper::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_ConstraintWrapper", - sizeof(KX_ConstraintWrapper), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 -}; - -PyParentObject KX_ConstraintWrapper::Parents[] = { - &KX_ConstraintWrapper::Type, - NULL -}; - -PyObject* KX_ConstraintWrapper::_getattr(const STR_String& attr) +PyObject* KX_ConstraintWrapper::PyGetParam(PyObject* args, PyObject* kwds) { - //here you can search for existing data members (like mass,friction etc.) - _getattr_up(PyObjectPlus); + int dof; + float value; + + if (!PyArg_ParseTuple(args,"i:getParam",&dof)) + return NULL; + + value = m_physenv->getConstraintParam(m_constraintId,dof); + return PyFloat_FromDouble(value); + } -int KX_ConstraintWrapper::_setattr(const STR_String& attr,PyObject* pyobj) +PyObject* KX_ConstraintWrapper::PySetParam(PyObject* args, PyObject* kwds) { + int dof; + float minLimit,maxLimit; - PyTypeObject* type = pyobj->ob_type; - int result = 1; + if (!PyArg_ParseTuple(args,"iff:setParam",&dof,&minLimit,&maxLimit)) + return NULL; + + m_physenv->setConstraintParam(m_constraintId,dof,minLimit,maxLimit); + Py_RETURN_NONE; +} - if (type == &PyList_Type) - { - result = 0; - } - if (type == &PyFloat_Type) - { - result = 0; - } - if (type == &PyInt_Type) - { - result = 0; - } - if (type == &PyString_Type) - { - result = 0; - } - if (result) - result = PyObjectPlus::_setattr(attr,pyobj); - return result; +//python specific stuff +PyTypeObject KX_ConstraintWrapper::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "KX_ConstraintWrapper", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &PyObjectPlus::Type, + 0,0,0,0,0,0, + py_base_new }; - PyMethodDef KX_ConstraintWrapper::Methods[] = { - {"testMethod",(PyCFunction) KX_ConstraintWrapper::sPyTestMethod, METH_VARARGS}, - {"getConstraintId",(PyCFunction) KX_ConstraintWrapper::sPyGetConstraintId, METH_VARARGS}, + {"getConstraintId",(PyCFunction) KX_ConstraintWrapper::sPyGetConstraintId, METH_NOARGS}, + {"setParam",(PyCFunction) KX_ConstraintWrapper::sPySetParam, METH_VARARGS}, + {"getParam",(PyCFunction) KX_ConstraintWrapper::sPyGetParam, METH_VARARGS}, {NULL,NULL} //Sentinel }; + +PyAttributeDef KX_ConstraintWrapper::Attributes[] = { + //KX_PYATTRIBUTE_TODO("constraintId"), + { NULL } //Sentinel +}; diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.h b/source/gameengine/Ketsji/KX_ConstraintWrapper.h index 79fb3dc21aa..74670944415 100644 --- a/source/gameengine/Ketsji/KX_ConstraintWrapper.h +++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.h @@ -35,15 +35,14 @@ class KX_ConstraintWrapper : public PyObjectPlus { Py_Header; - virtual PyObject* _getattr(const STR_String& attr); - virtual int _setattr(const STR_String& attr, PyObject *value); public: - KX_ConstraintWrapper(PHY_ConstraintType ctype,int constraintId,class PHY_IPhysicsEnvironment* physenv,PyTypeObject *T = &Type); + KX_ConstraintWrapper(PHY_ConstraintType ctype,int constraintId,class PHY_IPhysicsEnvironment* physenv); virtual ~KX_ConstraintWrapper (); int getConstraintId() { return m_constraintId;}; - KX_PYMETHOD(KX_ConstraintWrapper,TestMethod); - KX_PYMETHOD(KX_ConstraintWrapper,GetConstraintId); + KX_PYMETHOD_NOARGS(KX_ConstraintWrapper,GetConstraintId); + KX_PYMETHOD(KX_ConstraintWrapper,SetParam); + KX_PYMETHOD(KX_ConstraintWrapper,GetParam); private: int m_constraintId; diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h b/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h index 53486cecf73..147bd238009 100644 --- a/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h +++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h @@ -32,11 +32,8 @@ /* These are defined by the build system... */ //but the build system is broken, because it doesn't allow for 2 or more defines at once. //Please leave Sumo _AND_ Bullet enabled -#define USE_SUMO_SOLID #define USE_BULLET -//#define USE_ODE - //on visual studio 7/8, always enable BULLET for now //you can have multiple physics engines running anyway, and //the scons build system doesn't really support this at the moment. @@ -47,6 +44,7 @@ class RAS_MeshObject; class KX_Scene; +struct DerivedMesh; typedef enum { KX_BOUNDBOX, @@ -82,6 +80,7 @@ struct KX_ObjectProperties bool m_ghost; class KX_GameObject* m_dynamic_parent; bool m_isactor; + bool m_sensor; bool m_concave; bool m_isdeformable; bool m_disableSleeping; @@ -124,10 +123,21 @@ struct KX_ObjectProperties float m_soft_kAHR; /* Anchors hardness [0,1] */ int m_soft_collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */ int m_soft_numclusteriterations; /* number of iterations to refine collision clusters*/ + float m_soft_welding; /* threshold to remove duplicate/nearby vertices */ ///////////////////////// + bool m_lockXaxis; + bool m_lockYaxis; + bool m_lockZaxis; + bool m_lockXRotaxis; + bool m_lockYRotaxis; + bool m_lockZRotaxis; + + ///////////////////////// double m_margin; + float m_contactProcessingThreshold; + KX_BoundBoxClass m_boundclass; union { KX_BoxBounds box; @@ -135,20 +145,6 @@ struct KX_ObjectProperties } m_boundobject; }; -#ifdef USE_ODE - - -void KX_ConvertODEEngineObject(KX_GameObject* gameobj, - RAS_MeshObject* meshobj, - KX_Scene* kxscene, - struct PHY_ShapeProps* shapeprops, - struct PHY_MaterialProps* smmaterial, - struct KX_ObjectProperties* objprop); - - -#endif //USE_ODE - - void KX_ConvertDynamoObject(KX_GameObject* gameobj, RAS_MeshObject* meshobj, KX_Scene* kxscene, @@ -156,31 +152,19 @@ void KX_ConvertDynamoObject(KX_GameObject* gameobj, struct PHY_MaterialProps* smmaterial, struct KX_ObjectProperties* objprop); -#ifdef USE_SUMO_SOLID - -void KX_ConvertSumoObject( class KX_GameObject* gameobj, - class RAS_MeshObject* meshobj, - class KX_Scene* kxscene, - struct PHY_ShapeProps* shapeprops, - struct PHY_MaterialProps* smmaterial, - struct KX_ObjectProperties* objprop); - -void KX_ClearSumoSharedShapes(); -bool KX_ReInstanceShapeFromMesh(RAS_MeshObject* meshobj); - -#endif #ifdef USE_BULLET void KX_ConvertBulletObject( class KX_GameObject* gameobj, class RAS_MeshObject* meshobj, + struct DerivedMesh* dm, class KX_Scene* kxscene, struct PHY_ShapeProps* shapeprops, struct PHY_MaterialProps* smmaterial, struct KX_ObjectProperties* objprop); void KX_ClearBulletSharedShapes(); -//bool KX_ReInstanceShapeFromMesh(RAS_MeshObject* meshobj); +bool KX_ReInstanceBulletShapeFromMesh(KX_GameObject *gameobj, KX_GameObject *from_gameobj, RAS_MeshObject* from_meshobj); #endif #endif //KX_CONVERTPHYSICSOBJECTS diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp index 0e7a6d92ec1..04e82d21cf4 100644 --- a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp +++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp @@ -32,9 +32,8 @@ #include "MT_assert.h" -// defines USE_ODE to choose physics engine #include "KX_ConvertPhysicsObject.h" -#include "KX_GameObject.h" +#include "BL_DeformableGameObject.h" #include "RAS_MeshObject.h" #include "KX_Scene.h" #include "SYS_System.h" @@ -52,597 +51,10 @@ #include "KX_MotionState.h" // bridge between motionstate and scenegraph node -#ifdef USE_ODE - -#include "KX_OdePhysicsController.h" -#include "OdePhysicsEnvironment.h" -#endif //USE_ODE - - -// USE_SUMO_SOLID is defined in headerfile KX_ConvertPhysicsObject.h -#ifdef USE_SUMO_SOLID - - -#include "SumoPhysicsEnvironment.h" -#include "KX_SumoPhysicsController.h" - - -// sumo physics specific -#include "SM_Object.h" -#include "SM_FhObject.h" -#include "SM_Scene.h" -#include "SM_ClientObjectInfo.h" - -#include "KX_SumoPhysicsController.h" - -struct KX_PhysicsInstance -{ - DT_VertexBaseHandle m_vertexbase; - RAS_DisplayArray* m_darray; - RAS_IPolyMaterial* m_material; - - KX_PhysicsInstance(DT_VertexBaseHandle vertex_base, RAS_DisplayArray *darray, RAS_IPolyMaterial* mat) - : m_vertexbase(vertex_base), - m_darray(darray), - m_material(mat) - { - } - - ~KX_PhysicsInstance() - { - DT_DeleteVertexBase(m_vertexbase); - } -}; - -static GEN_Map<GEN_HashedPtr,DT_ShapeHandle> map_gamemesh_to_sumoshape; -static GEN_Map<GEN_HashedPtr, KX_PhysicsInstance*> map_gamemesh_to_instance; - -// forward declarations -static void BL_RegisterSumoObject(KX_GameObject* gameobj,class SM_Scene* sumoScene,class SM_Object* sumoObj,const STR_String& matname,bool isDynamic,bool isActor); -static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope); - -void KX_ConvertSumoObject( KX_GameObject* gameobj, - RAS_MeshObject* meshobj, - KX_Scene* kxscene, - PHY_ShapeProps* kxshapeprops, - PHY_MaterialProps* kxmaterial, - struct KX_ObjectProperties* objprop) - - -{ - SM_ShapeProps* smprop = new SM_ShapeProps; - - smprop->m_ang_drag = kxshapeprops->m_ang_drag; - smprop->m_do_anisotropic = kxshapeprops->m_do_anisotropic; - smprop->m_do_fh = kxshapeprops->m_do_fh; - smprop->m_do_rot_fh = kxshapeprops->m_do_rot_fh ; - smprop->m_friction_scaling[0] = kxshapeprops->m_friction_scaling[0]; - smprop->m_friction_scaling[1] = kxshapeprops->m_friction_scaling[1]; - smprop->m_friction_scaling[2] = kxshapeprops->m_friction_scaling[2]; - smprop->m_inertia = MT_Vector3(1., 1., 1.) * kxshapeprops->m_inertia; - smprop->m_lin_drag = kxshapeprops->m_lin_drag; - smprop->m_mass = kxshapeprops->m_mass; - smprop->m_radius = objprop->m_radius; - - - SM_MaterialProps* smmaterial = new SM_MaterialProps; - - smmaterial->m_fh_damping = kxmaterial->m_fh_damping; - smmaterial->m_fh_distance = kxmaterial->m_fh_distance; - smmaterial->m_fh_normal = kxmaterial->m_fh_normal; - smmaterial->m_fh_spring = kxmaterial->m_fh_spring; - smmaterial->m_friction = kxmaterial->m_friction; - smmaterial->m_restitution = kxmaterial->m_restitution; - - SumoPhysicsEnvironment* sumoEnv = - (SumoPhysicsEnvironment*)kxscene->GetPhysicsEnvironment(); - - SM_Scene* sceneptr = sumoEnv->GetSumoScene(); - - SM_Object* sumoObj=NULL; - - if (objprop->m_dyna && objprop->m_isactor) - { - DT_ShapeHandle shape = NULL; - bool polytope = false; - switch (objprop->m_boundclass) - { - case KX_BOUNDBOX: - shape = DT_NewBox(objprop->m_boundobject.box.m_extends[0], - objprop->m_boundobject.box.m_extends[1], - objprop->m_boundobject.box.m_extends[2]); - smprop->m_inertia.scale(objprop->m_boundobject.box.m_extends[0]*objprop->m_boundobject.box.m_extends[0], - objprop->m_boundobject.box.m_extends[1]*objprop->m_boundobject.box.m_extends[1], - objprop->m_boundobject.box.m_extends[2]*objprop->m_boundobject.box.m_extends[2]); - smprop->m_inertia *= smprop->m_mass/MT_Vector3(objprop->m_boundobject.box.m_extends).length(); - break; - case KX_BOUNDCYLINDER: - shape = DT_NewCylinder(smprop->m_radius, objprop->m_boundobject.c.m_height); - smprop->m_inertia.scale(smprop->m_mass*smprop->m_radius*smprop->m_radius, - smprop->m_mass*smprop->m_radius*smprop->m_radius, - smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height); - break; - case KX_BOUNDCONE: - shape = DT_NewCone(objprop->m_radius, objprop->m_boundobject.c.m_height); - smprop->m_inertia.scale(smprop->m_mass*smprop->m_radius*smprop->m_radius, - smprop->m_mass*smprop->m_radius*smprop->m_radius, - smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height); - break; - /* Dynamic mesh objects. WARNING! slow. */ - case KX_BOUNDPOLYTOPE: - polytope = true; - // fall through - case KX_BOUNDMESH: - if (meshobj && meshobj->NumPolygons() > 0) - { - if ((shape = CreateShapeFromMesh(meshobj, polytope))) - { - // TODO: calculate proper inertia - smprop->m_inertia *= smprop->m_mass*smprop->m_radius*smprop->m_radius; - break; - } - } - /* If CreateShapeFromMesh fails, fall through and use sphere */ - default: - case KX_BOUNDSPHERE: - shape = DT_NewSphere(objprop->m_radius); - smprop->m_inertia *= smprop->m_mass*smprop->m_radius*smprop->m_radius; - break; - - } - - sumoObj = new SM_Object(shape, !objprop->m_ghost?smmaterial:NULL,smprop,NULL); - - sumoObj->setRigidBody(objprop->m_angular_rigidbody?true:false); - - BL_RegisterSumoObject(gameobj,sceneptr,sumoObj,"",true, true); - - } - else { - // non physics object - if (meshobj) - { - int numpolys = meshobj->NumPolygons(); - { - - DT_ShapeHandle complexshape=0; - bool polytope = false; - - switch (objprop->m_boundclass) - { - case KX_BOUNDBOX: - complexshape = DT_NewBox(objprop->m_boundobject.box.m_extends[0], objprop->m_boundobject.box.m_extends[1], objprop->m_boundobject.box.m_extends[2]); - break; - case KX_BOUNDSPHERE: - complexshape = DT_NewSphere(objprop->m_boundobject.c.m_radius); - break; - case KX_BOUNDCYLINDER: - complexshape = DT_NewCylinder(objprop->m_boundobject.c.m_radius, objprop->m_boundobject.c.m_height); - break; - case KX_BOUNDCONE: - complexshape = DT_NewCone(objprop->m_boundobject.c.m_radius, objprop->m_boundobject.c.m_height); - break; - case KX_BOUNDPOLYTOPE: - polytope = true; - // fall through - default: - case KX_BOUNDMESH: - if (numpolys>0) - { - complexshape = CreateShapeFromMesh(meshobj, polytope); - //std::cout << "Convert Physics Mesh: " << meshobj->GetName() << std::endl; -/* if (!complexshape) - { - // Something has to be done here - if the object has no polygons, it will not be able to have - // sensors attached to it. - DT_Vector3 pt = {0., 0., 0.}; - complexshape = DT_NewSphere(1.0); - objprop->m_ghost = evilObject = true; - } */ - } - break; - } - - if (complexshape) - { - SM_Object *dynamicParent = NULL; - - if (objprop->m_dynamic_parent) - { - // problem is how to find the dynamic parent - // in the scenegraph - KX_SumoPhysicsController* sumoctrl = - (KX_SumoPhysicsController*) - objprop->m_dynamic_parent->GetPhysicsController(); - - if (sumoctrl) - { - dynamicParent = sumoctrl->GetSumoObject(); - } - - MT_assert(dynamicParent); - } - - - sumoObj = new SM_Object(complexshape,!objprop->m_ghost?smmaterial:NULL,NULL, dynamicParent); - const STR_String& matname=meshobj->GetMaterialName(0); - - - BL_RegisterSumoObject(gameobj,sceneptr, - sumoObj, - matname, - objprop->m_dyna, - objprop->m_isactor); - } - } - } - } - - // physics object get updated here ! - - - // lazy evaluation because we might not support scaling !gameobj->UpdateTransform(); - - if (objprop->m_in_active_layer && sumoObj) - { - sceneptr->add(*sumoObj); - } - +extern "C"{ + #include "BKE_DerivedMesh.h" } - - -static void BL_RegisterSumoObject( - KX_GameObject* gameobj, - class SM_Scene* sumoScene, - class SM_Object* sumoObj, - const STR_String& matname, - bool isDynamic, - bool isActor) -{ - PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode()); - - // need easy access, not via 'node' etc. - KX_SumoPhysicsController* physicscontroller = new KX_SumoPhysicsController(sumoScene,sumoObj,motionstate,isDynamic); - gameobj->SetPhysicsController(physicscontroller,isDynamic); - - - if (!gameobj->getClientInfo()) - std::cout << "BL_RegisterSumoObject: WARNING: Object " << gameobj->GetName() << " has no client info" << std::endl; - physicscontroller->setNewClientInfo(gameobj->getClientInfo()); - - - gameobj->GetSGNode()->AddSGController(physicscontroller); - - gameobj->getClientInfo()->m_type = (isActor ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC); - - // store materialname in auxinfo, needed for touchsensors - gameobj->getClientInfo()->m_auxilary_info = (matname.Length() ? (void*)(matname.ReadPtr()+2) : NULL); - - physicscontroller->SetObject(gameobj->GetSGNode()); -} - -static DT_ShapeHandle InstancePhysicsComplex(RAS_MeshObject* meshobj, RAS_DisplayArray *darray, RAS_IPolyMaterial *mat) -{ - // instance a mesh from a single vertex array & material - const RAS_TexVert *vertex_array = &darray->m_vertex[0]; - DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getXYZ(), sizeof(RAS_TexVert)); - - DT_ShapeHandle shape = DT_NewComplexShape(vertex_base); - - std::vector<DT_Index> indices; - for (int p = 0; p < meshobj->NumPolygons(); p++) - { - RAS_Polygon* poly = meshobj->GetPolygon(p); - - // only add polygons that have the collisionflag set - if (poly->IsCollider()) - { - DT_Begin(); - DT_VertexIndex(poly->GetVertexOffset(0)); - DT_VertexIndex(poly->GetVertexOffset(1)); - DT_VertexIndex(poly->GetVertexOffset(2)); - DT_End(); - - // tesselate - if (poly->VertexCount() == 4) - { - DT_Begin(); - DT_VertexIndex(poly->GetVertexOffset(0)); - DT_VertexIndex(poly->GetVertexOffset(2)); - DT_VertexIndex(poly->GetVertexOffset(3)); - DT_End(); - } - } - } - - //DT_VertexIndices(indices.size(), &indices[0]); - DT_EndComplexShape(); - - map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, darray, mat)); - return shape; -} - -static DT_ShapeHandle InstancePhysicsPolytope(RAS_MeshObject* meshobj, RAS_DisplayArray *darray, RAS_IPolyMaterial *mat) -{ - // instance a mesh from a single vertex array & material - const RAS_TexVert *vertex_array = &darray->m_vertex[0]; - DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getXYZ(), sizeof(RAS_TexVert)); - - std::vector<DT_Index> indices; - for (int p = 0; p < meshobj->NumPolygons(); p++) - { - RAS_Polygon* poly = meshobj->GetPolygon(p); - - // only add polygons that have the collisionflag set - if (poly->IsCollider()) - { - indices.push_back(poly->GetVertexOffset(0)); - indices.push_back(poly->GetVertexOffset(1)); - indices.push_back(poly->GetVertexOffset(2)); - - if (poly->VertexCount() == 4) - indices.push_back(poly->GetVertexOffset(3)); - } - } - - DT_ShapeHandle shape = DT_NewPolytope(vertex_base); - DT_VertexIndices(indices.size(), &indices[0]); - DT_EndPolytope(); - - map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, darray, mat)); - return shape; -} - -// This will have to be a method in a class somewhere... -// Update SOLID with a changed physics mesh. -// not used... yet. -bool KX_ReInstanceShapeFromMesh(RAS_MeshObject* meshobj) -{ - KX_PhysicsInstance *instance = *map_gamemesh_to_instance[GEN_HashedPtr(meshobj)]; - if (instance) - { - const RAS_TexVert *vertex_array = &instance->m_darray->m_vertex[0]; - DT_ChangeVertexBase(instance->m_vertexbase, vertex_array[0].getXYZ()); - return true; - } - return false; -} - -static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope) -{ - - DT_ShapeHandle *shapeptr = map_gamemesh_to_sumoshape[GEN_HashedPtr(meshobj)]; - // Mesh has already been converted: reuse - if (shapeptr) - { - return *shapeptr; - } - - // Mesh has no polygons! - int numpolys = meshobj->NumPolygons(); - if (!numpolys) - { - return NULL; - } - - // Count the number of collision polygons and check they all come from the same - // vertex array - int numvalidpolys = 0; - RAS_DisplayArray *darray = NULL; - RAS_IPolyMaterial *poly_material = NULL; - bool reinstance = true; - - for (int p=0; p<numpolys; p++) - { - RAS_Polygon* poly = meshobj->GetPolygon(p); - - // only add polygons that have the collisionflag set - if (poly->IsCollider()) - { - // check polygon is from the same vertex array - if (poly->GetDisplayArray() != darray) - { - if (darray == NULL) - darray = poly->GetDisplayArray(); - else - { - reinstance = false; - darray = NULL; - } - } - - // check poly is from the same material - if (poly->GetMaterial()->GetPolyMaterial() != poly_material) - { - if (poly_material) - { - reinstance = false; - poly_material = NULL; - } - else - poly_material = poly->GetMaterial()->GetPolyMaterial(); - } - - // count the number of collision polys - numvalidpolys++; - - // We have one collision poly, and we can't reinstance, so we - // might as well break here. - if (!reinstance) - break; - } - } - - // No collision polygons - if (numvalidpolys < 1) - return NULL; - - DT_ShapeHandle shape; - if (reinstance) - { - if (polytope) - shape = InstancePhysicsPolytope(meshobj, darray, poly_material); - else - shape = InstancePhysicsComplex(meshobj, darray, poly_material); - } - else - { - if (polytope) - { - std::cout << "CreateShapeFromMesh: " << meshobj->GetName() << " is not suitable for polytope." << std::endl; - if (!poly_material) - std::cout << " Check mesh materials." << std::endl; - if (darray == NULL) - std::cout << " Check number of vertices." << std::endl; - } - - shape = DT_NewComplexShape(NULL); - - numvalidpolys = 0; - - for (int p2=0; p2<numpolys; p2++) - { - RAS_Polygon* poly = meshobj->GetPolygon(p2); - - // only add polygons that have the collisionflag set - if (poly->IsCollider()) - { /* We have to tesselate here because SOLID can only raycast triangles */ - DT_Begin(); - /* V1, V2, V3 */ - DT_Vertex(poly->GetVertex(2)->getXYZ()); - DT_Vertex(poly->GetVertex(1)->getXYZ()); - DT_Vertex(poly->GetVertex(0)->getXYZ()); - - numvalidpolys++; - DT_End(); - - if (poly->VertexCount() == 4) - { - DT_Begin(); - /* V1, V3, V4 */ - DT_Vertex(poly->GetVertex(3)->getXYZ()); - DT_Vertex(poly->GetVertex(2)->getXYZ()); - DT_Vertex(poly->GetVertex(0)->getXYZ()); - - numvalidpolys++; - DT_End(); - } - - } - } - - DT_EndComplexShape(); - } - - if (numvalidpolys > 0) - { - map_gamemesh_to_sumoshape.insert(GEN_HashedPtr(meshobj),shape); - return shape; - } - - delete shape; - return NULL; -} - -void KX_ClearSumoSharedShapes() -{ - int numshapes = map_gamemesh_to_sumoshape.size(); - int i; - for (i=0;i<numshapes ;i++) - { - DT_ShapeHandle shape = *map_gamemesh_to_sumoshape.at(i); - DT_DeleteShape(shape); - } - - map_gamemesh_to_sumoshape.clear(); - - for (i=0; i < map_gamemesh_to_instance.size(); i++) - delete *map_gamemesh_to_instance.at(i); - - map_gamemesh_to_instance.clear(); -} - - - - - -#endif //USE_SUMO_SOLID - - -#ifdef USE_ODE - -void KX_ConvertODEEngineObject(KX_GameObject* gameobj, - RAS_MeshObject* meshobj, - KX_Scene* kxscene, - struct PHY_ShapeProps* shapeprops, - struct PHY_MaterialProps* smmaterial, - struct KX_ObjectProperties* objprop) -{ - - // not yet, future extension :) - bool dyna=objprop->m_dyna; - bool fullRigidBody= ( objprop->m_dyna && objprop->m_angular_rigidbody) != 0; - bool phantom = objprop->m_ghost; - class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode()); - - class ODEPhysicsEnvironment* odeEnv = - (ODEPhysicsEnvironment*)kxscene->GetPhysicsEnvironment(); - - dxSpace* space = odeEnv->GetOdeSpace(); - dxWorld* world = odeEnv->GetOdeWorld(); - - bool isSphere = false; - - switch (objprop->m_boundclass) - { - case KX_BOUNDBOX: - { - - KX_OdePhysicsController* physicscontroller = - new KX_OdePhysicsController( - dyna, - fullRigidBody, - phantom, - motionstate, - space, - world, - shapeprops->m_mass, - smmaterial->m_friction, - smmaterial->m_restitution, - isSphere, - objprop->m_boundobject.box.m_center, - objprop->m_boundobject.box.m_extends, - objprop->m_boundobject.c.m_radius - ); - - gameobj->SetPhysicsController(physicscontroller); - physicscontroller->setNewClientInfo(gameobj->getClientInfo()); - gameobj->GetSGNode()->AddSGController(physicscontroller); - - bool isActor = objprop->m_isactor; - STR_String materialname; - if (meshobj) - materialname = meshobj->GetMaterialName(0); - - const char* matname = materialname.ReadPtr(); - - - physicscontroller->SetObject(gameobj->GetSGNode()); - - break; - } - default: - { - } - }; - -} - - -#endif // USE_ODE - - #ifdef USE_BULLET #include "CcdPhysicsEnvironment.h" @@ -670,11 +82,11 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj, class KX_SoftBodyDeformer : public RAS_Deformer { - class RAS_MeshObject* m_pMeshObject; - class KX_GameObject* m_gameobj; + class RAS_MeshObject* m_pMeshObject; + class BL_DeformableGameObject* m_gameobj; public: - KX_SoftBodyDeformer(RAS_MeshObject* pMeshObject,KX_GameObject* gameobj) + KX_SoftBodyDeformer(RAS_MeshObject* pMeshObject,BL_DeformableGameObject* gameobj) :m_pMeshObject(pMeshObject), m_gameobj(gameobj) { @@ -687,7 +99,15 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj, }; virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map) { - //printf("relink\n"); + void **h_obj = (*map)[m_gameobj]; + + if (h_obj) { + m_gameobj = (BL_DeformableGameObject*)(*h_obj); + m_pMeshObject = m_gameobj->GetMesh(0); + } else { + m_gameobj = NULL; + m_pMeshObject = NULL; + } } virtual bool Apply(class RAS_IPolyMaterial *polymat) { @@ -749,14 +169,27 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj, virtual bool Update(void) { //printf("update\n"); + m_bDynamic = true; return true;//?? } - virtual RAS_Deformer *GetReplica(class KX_GameObject* replica) + virtual bool UpdateBuckets(void) { - KX_SoftBodyDeformer* deformer = new KX_SoftBodyDeformer(replica->GetMesh(0),replica); - return deformer; + // this is to update the mesh slots outside the rasterizer, + // no need to do it for this deformer, it's done in any case in Apply() + return false; } + virtual RAS_Deformer *GetReplica() + { + KX_SoftBodyDeformer* deformer = new KX_SoftBodyDeformer(*this); + deformer->ProcessReplica(); + return deformer; + } + virtual void ProcessReplica() + { + // we have two pointers to deal with but we cannot do it now, will be done in Relink + m_bDynamic = false; + } virtual bool SkipVertexTransform() { return true; @@ -771,6 +204,7 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj, void KX_ConvertBulletObject( class KX_GameObject* gameobj, class RAS_MeshObject* meshobj, + struct DerivedMesh* dm, class KX_Scene* kxscene, struct PHY_ShapeProps* shapeprops, struct PHY_MaterialProps* smmaterial, @@ -782,12 +216,12 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, bool isbulletdyna = false; + bool isbulletsensor = false; CcdConstructionInfo ci; class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode()); class CcdShapeConstructionInfo *shapeInfo = new CcdShapeConstructionInfo(); - if (!objprop->m_dyna) { ci.m_collisionFlags |= btCollisionObject::CF_STATIC_OBJECT; @@ -801,9 +235,12 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, ci.m_gravity = btVector3(0,0,0); ci.m_localInertiaTensor =btVector3(0,0,0); ci.m_mass = objprop->m_dyna ? shapeprops->m_mass : 0.f; + ci.m_clamp_vel_min = shapeprops->m_clamp_vel_min; + ci.m_clamp_vel_max = shapeprops->m_clamp_vel_max; ci.m_margin = objprop->m_margin; shapeInfo->m_radius = objprop->m_radius; isbulletdyna = objprop->m_dyna; + isbulletsensor = objprop->m_sensor; ci.m_localInertiaTensor = btVector3(ci.m_mass/3.f,ci.m_mass/3.f,ci.m_mass/3.f); @@ -823,7 +260,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, //bm = new MultiSphereShape(inertiaHalfExtents,,&trans.getOrigin(),&radius,1); shapeInfo->m_shapeType = PHY_SHAPE_SPHERE; - bm = shapeInfo->CreateBulletShape(); + bm = shapeInfo->CreateBulletShape(ci.m_margin); break; }; case KX_BOUNDBOX: @@ -836,7 +273,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, shapeInfo->m_halfExtend /= 2.0; shapeInfo->m_halfExtend = shapeInfo->m_halfExtend.absolute(); shapeInfo->m_shapeType = PHY_SHAPE_BOX; - bm = shapeInfo->CreateBulletShape(); + bm = shapeInfo->CreateBulletShape(ci.m_margin); break; }; case KX_BOUNDCYLINDER: @@ -847,7 +284,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, objprop->m_boundobject.c.m_height * 0.5f ); shapeInfo->m_shapeType = PHY_SHAPE_CYLINDER; - bm = shapeInfo->CreateBulletShape(); + bm = shapeInfo->CreateBulletShape(ci.m_margin); break; } @@ -856,43 +293,41 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, shapeInfo->m_radius = objprop->m_boundobject.c.m_radius; shapeInfo->m_height = objprop->m_boundobject.c.m_height; shapeInfo->m_shapeType = PHY_SHAPE_CONE; - bm = shapeInfo->CreateBulletShape(); + bm = shapeInfo->CreateBulletShape(ci.m_margin); break; } case KX_BOUNDPOLYTOPE: { - shapeInfo->SetMesh(meshobj, true,false); - bm = shapeInfo->CreateBulletShape(); + shapeInfo->SetMesh(meshobj, dm,true,false); + bm = shapeInfo->CreateBulletShape(ci.m_margin); break; } case KX_BOUNDMESH: { - - if (!ci.m_mass ||objprop->m_softbody) - { - // mesh shapes can be shared, check first if we already have a shape on that mesh - class CcdShapeConstructionInfo *sharedShapeInfo = CcdShapeConstructionInfo::FindMesh(meshobj, false); - if (sharedShapeInfo != NULL) - { - delete shapeInfo; - shapeInfo = sharedShapeInfo; - shapeInfo->AddRef(); - } else - { - shapeInfo->SetMesh(meshobj, false,false); - } - if (objprop->m_softbody) - shapeInfo->setVertexWeldingThreshold(0.01f); //todo: expose this to the UI + bool useGimpact = ((ci.m_mass || isbulletsensor) && !objprop->m_softbody); - bm = shapeInfo->CreateBulletShape(); - //no moving concave meshes, so don't bother calculating inertia - //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); + // mesh shapes can be shared, check first if we already have a shape on that mesh + class CcdShapeConstructionInfo *sharedShapeInfo = CcdShapeConstructionInfo::FindMesh(meshobj, dm, false,useGimpact); + if (sharedShapeInfo != NULL) + { + delete shapeInfo; + shapeInfo = sharedShapeInfo; + shapeInfo->AddRef(); } else { - shapeInfo->SetMesh(meshobj, false,true); - bm = shapeInfo->CreateBulletShape(); + shapeInfo->SetMesh(meshobj, dm, false,useGimpact); + } + + // Soft bodies require welding. Only avoid remove doubles for non-soft bodies! + if (objprop->m_softbody) + { + shapeInfo->setVertexWeldingThreshold1(objprop->m_soft_welding); //todo: expose this to the UI } + bm = shapeInfo->CreateBulletShape(ci.m_margin); + //should we compute inertia for dynamic shape? + //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); + break; } } @@ -907,7 +342,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, return; } - bm->setMargin(ci.m_margin); + //bm->setMargin(ci.m_margin); if (objprop->m_isCompoundChild) @@ -922,39 +357,27 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, assert(colShape->isCompound()); btCompoundShape* compoundShape = (btCompoundShape*)colShape; - // compute the local transform from parent, this may include a parent inverse node + // compute the local transform from parent, this may include several node in the chain SG_Node* gameNode = gameobj->GetSGNode(); - SG_Node* parentInverseNode = gameNode->GetSGParent(); - if (parentInverseNode && parentInverseNode->GetSGClientObject() != NULL) - // this is not a parent inverse node, cancel it - parentInverseNode = NULL; - // now combine the parent inverse node and the game node - MT_Point3 childPos = gameNode->GetLocalPosition(); - MT_Matrix3x3 childRot = gameNode->GetLocalOrientation(); - MT_Vector3 childScale = gameNode->GetLocalScale(); - if (parentInverseNode) - { - const MT_Point3& parentInversePos = parentInverseNode->GetLocalPosition(); - const MT_Matrix3x3& parentInverseRot = parentInverseNode->GetLocalOrientation(); - const MT_Vector3& parentInverseScale = parentInverseNode->GetLocalScale(); - childRot = parentInverseRot * childRot; - childScale = parentInverseScale * childScale; - childPos = parentInversePos+parentInverseScale*(parentInverseRot*childPos); - } - - shapeInfo->m_childScale.setValue(childScale.x(),childScale.y(),childScale.z()); + SG_Node* parentNode = objprop->m_dynamic_parent->GetSGNode(); + // relative transform + MT_Vector3 parentScale = parentNode->GetWorldScaling(); + parentScale[0] = MT_Scalar(1.0)/parentScale[0]; + parentScale[1] = MT_Scalar(1.0)/parentScale[1]; + parentScale[2] = MT_Scalar(1.0)/parentScale[2]; + MT_Vector3 relativeScale = gameNode->GetWorldScaling() * parentScale; + MT_Matrix3x3 parentInvRot = parentNode->GetWorldOrientation().transposed(); + MT_Vector3 relativePos = parentInvRot*((gameNode->GetWorldPosition()-parentNode->GetWorldPosition())*parentScale); + MT_Matrix3x3 relativeRot = parentInvRot*gameNode->GetWorldOrientation(); + + shapeInfo->m_childScale.setValue(relativeScale[0],relativeScale[1],relativeScale[2]); bm->setLocalScaling(shapeInfo->m_childScale); - - shapeInfo->m_childTrans.setOrigin(btVector3(childPos.x(),childPos.y(),childPos.z())); - float rotval[12]; - childRot.getValue(rotval); - btMatrix3x3 newRot; - newRot.setValue(rotval[0],rotval[1],rotval[2],rotval[4],rotval[5],rotval[6],rotval[8],rotval[9],rotval[10]); - newRot = newRot.transpose(); - - shapeInfo->m_childTrans.setBasis(newRot); + shapeInfo->m_childTrans.getOrigin().setValue(relativePos[0],relativePos[1],relativePos[2]); + float rot[12]; + relativeRot.getValue(rot); + shapeInfo->m_childTrans.getBasis().setFromOpenGLSubMatrix(rot); + parentShapeInfo->AddShape(shapeInfo); - compoundShape->addChildShape(shapeInfo->m_childTrans,bm); //do some recalc? //recalc inertia for rigidbody @@ -965,6 +388,8 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, compoundShape->calculateLocalInertia(mass,localInertia); rigidbody->setMassProps(mass,localInertia); } + // delete motionstate as it's not used + delete motionstate; return; } @@ -1077,32 +502,57 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, ci.m_soft_numclusteriterations= objprop->m_soft_numclusteriterations; /* number of iterations to refine collision clusters*/ //////////////////// - - ci.m_collisionFilterGroup = (isbulletdyna) ? short(CcdConstructionInfo::DefaultFilter) : short(CcdConstructionInfo::StaticFilter); - ci.m_collisionFilterMask = (isbulletdyna) ? short(CcdConstructionInfo::AllFilter) : short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter); + ci.m_collisionFilterGroup = + (isbulletsensor) ? short(CcdConstructionInfo::SensorFilter) : + (isbulletdyna) ? short(CcdConstructionInfo::DefaultFilter) : + short(CcdConstructionInfo::StaticFilter); + ci.m_collisionFilterMask = + (isbulletsensor) ? short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter) : + (isbulletdyna) ? short(CcdConstructionInfo::AllFilter) : + short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter); ci.m_bRigid = objprop->m_dyna && objprop->m_angular_rigidbody; + + ci.m_contactProcessingThreshold = objprop->m_contactProcessingThreshold;//todo: expose this in advanced settings, just like margin, default to 10000 or so ci.m_bSoft = objprop->m_softbody; + ci.m_bSensor = isbulletsensor; MT_Vector3 scaling = gameobj->NodeGetWorldScaling(); ci.m_scaling.setValue(scaling[0], scaling[1], scaling[2]); - KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna); + KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna,isbulletsensor,objprop->m_hasCompoundChildren); // shapeInfo is reference counted, decrement now as we don't use it anymore if (shapeInfo) shapeInfo->Release(); - if (objprop->m_in_active_layer) + gameobj->SetPhysicsController(physicscontroller,isbulletdyna); + // don't add automatically sensor object, they are added when a collision sensor is registered + if (!isbulletsensor && objprop->m_in_active_layer) { env->addCcdPhysicsController( physicscontroller); } - - - - gameobj->SetPhysicsController(physicscontroller,isbulletdyna); physicscontroller->setNewClientInfo(gameobj->getClientInfo()); { btRigidBody* rbody = physicscontroller->GetRigidBody(); - if (rbody && objprop->m_disableSleeping) - rbody->setActivationState(DISABLE_DEACTIVATION); + if (rbody) + { + if (objprop->m_angular_rigidbody) + { + btVector3 linearFactor( + objprop->m_lockXaxis? 0 : 1, + objprop->m_lockYaxis? 0 : 1, + objprop->m_lockZaxis? 0 : 1); + btVector3 angularFactor( + objprop->m_lockXRotaxis? 0 : 1, + objprop->m_lockYRotaxis? 0 : 1, + objprop->m_lockZRotaxis? 0 : 1); + rbody->setLinearFactor(linearFactor); + rbody->setAngularFactor(angularFactor); + } + + if (rbody && objprop->m_disableSleeping) + { + rbody->setActivationState(DISABLE_DEACTIVATION); + } + } } CcdPhysicsController* parentCtrl = objprop->m_dynamic_parent ? (KX_BulletPhysicsController*)objprop->m_dynamic_parent->GetPhysicsController() : 0; @@ -1136,7 +586,9 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, } bool isActor = objprop->m_isactor; - gameobj->getClientInfo()->m_type = (isActor ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC); + gameobj->getClientInfo()->m_type = + (isbulletsensor) ? ((isActor) ? KX_ClientObjectInfo::OBACTORSENSOR : KX_ClientObjectInfo::OBSENSOR) : + (isActor) ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC; // store materialname in auxinfo, needed for touchsensors if (meshobj) { @@ -1164,9 +616,8 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, if (softBody && gameobj->GetMesh(0))//only the first mesh, if any { //should be a mesh then, so add a soft body deformer - KX_SoftBodyDeformer* softbodyDeformer = new KX_SoftBodyDeformer( gameobj->GetMesh(0),gameobj); + KX_SoftBodyDeformer* softbodyDeformer = new KX_SoftBodyDeformer( gameobj->GetMesh(0),(BL_DeformableGameObject*)gameobj); gameobj->SetDeformer(softbodyDeformer); - } } @@ -1177,5 +628,44 @@ void KX_ClearBulletSharedShapes() { } -#endif +/* Refresh the physics object from either an object or a mesh. + * gameobj must be valid + * from_gameobj and from_meshobj can be NULL + * + * when setting the mesh, the following vars get priority + * 1) from_meshobj - creates the phys mesh from RAS_MeshObject + * 2) from_gameobj - creates the phys mesh from the DerivedMesh where possible, else the RAS_MeshObject + * 3) gameobj - update the phys mesh from DerivedMesh or RAS_MeshObject + * + * Most of the logic behind this is in shapeInfo->UpdateMesh(...) + */ +bool KX_ReInstanceBulletShapeFromMesh(KX_GameObject *gameobj, KX_GameObject *from_gameobj, RAS_MeshObject* from_meshobj) +{ + KX_BulletPhysicsController *spc= static_cast<KX_BulletPhysicsController*>((gameobj->GetPhysicsController())); + CcdShapeConstructionInfo *shapeInfo; + + /* if this is the child of a compound shape this can happen + * dont support compound shapes for now */ + if(spc==NULL) + return false; + + shapeInfo = spc->GetShapeInfo(); + + if(shapeInfo->m_shapeType != PHY_SHAPE_MESH || spc->GetSoftBody()) + return false; + + spc->DeleteControllerShape(); + + if(from_gameobj==NULL && from_meshobj==NULL) + from_gameobj= gameobj; + + /* updates the arrays used for making the new bullet mesh */ + shapeInfo->UpdateMesh(from_gameobj, from_meshobj); + /* create the new bullet mesh */ + btCollisionShape* bm= shapeInfo->CreateBulletShape(spc->getConstructionInfo().m_margin); + + spc->ReplaceControllerShape(bm); + return true; +} +#endif diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp new file mode 100644 index 00000000000..daa31379985 --- /dev/null +++ b/source/gameengine/Ketsji/KX_Dome.cpp @@ -0,0 +1,2056 @@ +/* $Id$ +----------------------------------------------------------------------------- + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. + +Contributor(s): Dalai Felinto + +This code is originally inspired on some of the ideas and codes from Paul Bourke. +Developed as part of a Research and Development project for SAT - La Société des arts technologiques. +----------------------------------------------------------------------------- +*/ + +#include "KX_Dome.h" + +#include <structmember.h> +#include <float.h> +#include <math.h> + +#include "DNA_scene_types.h" +#include "RAS_CameraData.h" +#include "BLI_arithb.h" + +#include "GL/glew.h" + +// constructor +KX_Dome::KX_Dome ( + RAS_ICanvas* canvas, + /// rasterizer + RAS_IRasterizer* rasterizer, + /// render tools + RAS_IRenderTools* rendertools, + /// engine + KX_KetsjiEngine* engine, + + short res, //resolution of the mesh + short mode, //mode - fisheye, truncated, warped, panoramic, ... + short angle, + float resbuf, //size adjustment of the buffer + short tilt, + struct Text* warptext + +): + dlistSupported(false), + canvaswidth(-1), canvasheight(-1), + m_drawingmode(engine->GetDrawType()), + m_resolution(res), + m_mode(mode), + m_angle(angle), + m_resbuffer(resbuf), + m_tilt(tilt), + m_canvas(canvas), + m_rasterizer(rasterizer), + m_rendertools(rendertools), + m_engine(engine) +{ + warp.usemesh = false; + fboSupported = false; + + if (mode >= DOME_NUM_MODES) + m_mode = DOME_FISHEYE; + + if (warptext) // it there is a text data try to warp it + { + char *buf; + buf = txt_to_buf(warptext); + if (buf) + { + warp.usemesh = ParseWarpMesh(STR_String(buf)); + MEM_freeN(buf); + } + } + + //setting the viewport size + GLuint viewport[4]={0}; + glGetIntegerv(GL_VIEWPORT,(GLint *)viewport); + + SetViewPort(viewport); + + switch(m_mode){ + case DOME_FISHEYE: + if (m_angle <= 180){ + cubetop.resize(1); + cubebottom.resize(1); + cubeleft.resize(2); + cuberight.resize(2); + + CreateMeshDome180(); + m_numfaces = 4; + }else if (m_angle > 180){ + cubetop.resize(2); + cubebottom.resize(2); + cubeleft.resize(2); + cubefront.resize(2); + cuberight.resize(2); + + CreateMeshDome250(); + m_numfaces = 5; + } break; + case DOME_ENVMAP: + m_angle = 360; + m_numfaces = 6; + break; + case DOME_PANORAM_SPH: + cubeleft.resize(2); + cubeleftback.resize(2); + cuberight.resize(2); + cuberightback.resize(2); + cubetop.resize(2); + cubebottom.resize(2); + + m_angle = 360; + CreateMeshPanorama(); + m_numfaces = 6; + break; + default: //DOME_TRUNCATED_FRONT and DOME_TRUNCATED_REAR + if (m_angle <= 180){ + cubetop.resize(1); + cubebottom.resize(1); + cubeleft.resize(2); + cuberight.resize(2); + + CreateMeshDome180(); + m_numfaces = 4; + }else if (m_angle > 180){ + cubetop.resize(2); + cubebottom.resize(2); + cubeleft.resize(2); + cubefront.resize(2); + cuberight.resize(2); + + CreateMeshDome250(); + m_numfaces = 5; + } break; + } + + m_numimages =(warp.usemesh?m_numfaces+1:m_numfaces); + + CalculateCameraOrientation(); + + CreateGLImages(); + + if(warp.usemesh) + fboSupported = CreateFBO(); + + dlistSupported = CreateDL(); +} + +// destructor +KX_Dome::~KX_Dome (void) +{ + ClearGLImages(); + + if(fboSupported) + glDeleteFramebuffersEXT(1, &warp.fboId); + + if(dlistSupported) + glDeleteLists(dlistId, (GLsizei) m_numimages); +} + +void KX_Dome::SetViewPort(GLuint viewport[4]) +{ + if(canvaswidth != m_viewport.GetWidth() || canvasheight != m_viewport.GetHeight()) + { + m_viewport.SetLeft(viewport[0]); + m_viewport.SetBottom(viewport[1]); + m_viewport.SetRight(viewport[2]); + m_viewport.SetTop(viewport[3]); + + CalculateImageSize(); + } +} + +void KX_Dome::CreateGLImages(void) +{ + glGenTextures(m_numimages, (GLuint*)&domefacesId); + + for (int j=0;j<m_numfaces;j++){ + glBindTexture(GL_TEXTURE_2D, domefacesId[j]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, m_imagesize, m_imagesize, 0, GL_RGB8, + GL_UNSIGNED_BYTE, 0); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, m_imagesize, m_imagesize, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + if(warp.usemesh){ + glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, warp.imagesize, warp.imagesize, 0, GL_RGB8, + GL_UNSIGNED_BYTE, 0); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, warp.imagesize, warp.imagesize, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } +} + +void KX_Dome::ClearGLImages(void) +{ + glDeleteTextures(m_numimages, (GLuint*)&domefacesId); +/* + for (int i=0;i<m_numimages;i++) + if(glIsTexture(domefacesId[i])) + glDeleteTextures(1, (GLuint*)&domefacesId[i]); +*/ +} + +void KX_Dome::CalculateImageSize(void) +{ +/* +- determine the minimum buffer size +- reduce the buffer for better performace +- create a power of 2 texture bigger than the buffer +*/ +/* +Blender handles Canvas size differently when in fullscreen mode. +We are manually checking for that. Although it's a hack, it works. + +Bug reported here: #18655 - Inconsistency of pixels in canvas dimensions when in maximized mode (affecting BGE Dome) +http://projects.blender.org/tracker/?func=detail&aid=18655&group_id=9&atid=125 +*/ + + canvaswidth = m_canvas->GetWidth(); + canvasheight = m_canvas->GetHeight(); + + bool fullscreen(false); //XXX HACK + fullscreen = (canvaswidth != m_viewport.GetWidth()); + + m_buffersize = (canvaswidth > canvasheight?canvasheight:canvaswidth); + m_buffersize = (int)(m_buffersize*m_resbuffer); //reduce buffer size for better performance + + if (fullscreen) //XXX HACK + m_buffersize --; + + int i = 0; + while ((1 << i) <= m_buffersize) + i++; + m_imagesize = (1 << i); + + if (warp.usemesh){ + // warp FBO needs to be up to twice as big as m_buffersize to get more resolution + warp.imagesize = m_imagesize; + if (m_buffersize == m_imagesize) + warp.imagesize *= 2; + + //if FBO is not working/supported, we use the canvas dimension as buffer + warp.bufferwidth = canvaswidth; + warp.bufferheight = canvasheight; + } + + //XXX HACK + canvaswidth = m_viewport.GetWidth(); + canvasheight = m_viewport.GetHeight(); +} + +bool KX_Dome::CreateDL(){ + dlistId = glGenLists((GLsizei) m_numimages); + if (dlistId != 0) { + if(m_mode == DOME_FISHEYE || m_mode == DOME_TRUNCATED_FRONT || m_mode == DOME_TRUNCATED_REAR){ + glNewList(dlistId, GL_COMPILE); + GLDrawTriangles(cubetop, nfacestop); + glEndList(); + + glNewList(dlistId+1, GL_COMPILE); + GLDrawTriangles(cubebottom, nfacesbottom); + glEndList(); + + glNewList(dlistId+2, GL_COMPILE); + GLDrawTriangles(cubeleft, nfacesleft); + glEndList(); + + glNewList(dlistId+3, GL_COMPILE); + GLDrawTriangles(cuberight, nfacesright); + glEndList(); + + if (m_angle > 180){ + glNewList(dlistId+4, GL_COMPILE); + GLDrawTriangles(cubefront, nfacesfront); + glEndList(); + } + } + else if (m_mode == DOME_PANORAM_SPH) + { + glNewList(dlistId, GL_COMPILE); + GLDrawTriangles(cubetop, nfacestop); + glEndList(); + + glNewList(dlistId+1, GL_COMPILE); + GLDrawTriangles(cubebottom, nfacesbottom); + glEndList(); + + glNewList(dlistId+2, GL_COMPILE); + GLDrawTriangles(cubeleft, nfacesleft); + glEndList(); + + glNewList(dlistId+3, GL_COMPILE); + GLDrawTriangles(cuberight, nfacesright); + glEndList(); + + glNewList(dlistId+4, GL_COMPILE); + GLDrawTriangles(cubeleftback, nfacesleftback); + glEndList(); + + glNewList(dlistId+5, GL_COMPILE); + GLDrawTriangles(cuberightback, nfacesrightback); + glEndList(); + } + + if(warp.usemesh){ + glNewList((dlistId + m_numfaces), GL_COMPILE); + GLDrawWarpQuads(); + glEndList(); + } + + //clearing the vectors + cubetop.clear(); + cubebottom.clear(); + cuberight.clear(); + cubeleft.clear(); + cubefront.clear(); + cubeleftback.clear(); + cuberightback.clear(); + warp.nodes.clear(); + + } else // genList failed + return false; + + return true; +} + +bool KX_Dome::CreateFBO(void) +{ + if (!GLEW_EXT_framebuffer_object) + { + printf("Dome Error: FrameBuffer unsupported. Using low resolution warp image."); + return false; + } + + glGenFramebuffersEXT(1, &warp.fboId); + if(warp.fboId==0) + { + printf("Dome Error: Invalid frame buffer object. Using low resolution warp image."); + return false; + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, warp.fboId); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, domefacesId[m_numfaces], 0); + + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + if(status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) + { + printf("Dome Error: FrameBuffer settings unsupported. Using low resolution warp image."); + return false; + } + else if(status != GL_FRAMEBUFFER_COMPLETE_EXT) + { + glDeleteFramebuffersEXT(1, &warp.fboId); + return false; + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + //nothing failed: we can use the whole FBO as buffersize + warp.bufferwidth = warp.bufferheight = warp.imagesize; + return true; +} + +void KX_Dome::GLDrawTriangles(vector <DomeFace>& face, int nfaces) +{ + int i,j; + glBegin(GL_TRIANGLES); + for (i=0;i<nfaces;i++) { + for (j=0;j<3;j++) { + glTexCoord2f(face[i].u[j],face[i].v[j]); + glVertex3f((GLfloat)face[i].verts[j][0],(GLfloat)face[i].verts[j][1],(GLfloat)face[i].verts[j][2]); + } + } + glEnd(); +} + +void KX_Dome::GLDrawWarpQuads(void) +{ + int i, j, i2; + + float uv_width = (float)(warp.bufferwidth) / warp.imagesize; + float uv_height = (float)(warp.bufferheight) / warp.imagesize; + + if(warp.mode ==2 ){ + glBegin(GL_QUADS); + for (i=0;i<warp.n_height-1;i++) { + for (j=0;j<warp.n_width-1;j++) { + if(warp.nodes[i][j].i < 0 || warp.nodes[i+1][j].i < 0 || warp.nodes[i+1][j+1].i < 0 || warp.nodes[i][j+1].i < 0) + continue; + + glColor3f(warp.nodes[i][j].i, warp.nodes[i][j].i, warp.nodes[i][j].i); + glTexCoord2f((warp.nodes[i][j].u * uv_width), (warp.nodes[i][j].v * uv_height)); + glVertex3f(warp.nodes[i][j].x, warp.nodes[i][j].y,0.0); + + glColor3f(warp.nodes[i+1][j].i, warp.nodes[i+1][j].i, warp.nodes[i+1][j].i); + glTexCoord2f((warp.nodes[i+1][j].u * uv_width), (warp.nodes[i+1][j].v * uv_height)); + glVertex3f(warp.nodes[i+1][j].x, warp.nodes[i+1][j].y,0.0); + + glColor3f(warp.nodes[i+1][j+1].i, warp.nodes[i+1][j+1].i, warp.nodes[i+1][j+1].i); + glTexCoord2f((warp.nodes[i+1][j+1].u * uv_width), (warp.nodes[i+1][j+1].v * uv_height)); + glVertex3f(warp.nodes[i+1][j+1].x, warp.nodes[i+1][j+1].y,0.0); + + glColor3f(warp.nodes[i][j+1].i, warp.nodes[i][j+1].i, warp.nodes[i][j+1].i); + glTexCoord2f((warp.nodes[i][j+1].u * uv_width), (warp.nodes[i][j+1].v * uv_height)); + glVertex3f(warp.nodes[i][j+1].x, warp.nodes[i][j+1].y,0.0); + } + } + glEnd(); + } + else if (warp.mode == 1){ + glBegin(GL_QUADS); + for (i=0;i<warp.n_height-1;i++) { + for (j=0;j<warp.n_width-1;j++) { + i2 = (i+1) % warp.n_width; // Wrap around, i = warp.n_width = 0 + + if (warp.nodes[i][j].i < 0 || warp.nodes[i2][j].i < 0 || warp.nodes[i2][j+1].i < 0 || warp.nodes[i][j+1].i < 0) + continue; + + glColor3f(warp.nodes[i][j].i,warp.nodes[i][j].i,warp.nodes[i][j].i); + glTexCoord2f((warp.nodes[i][j].u * uv_width), (warp.nodes[i][j].v * uv_height)); + glVertex3f(warp.nodes[i][j].x,warp.nodes[i][j].y,0.0); + + glColor3f(warp.nodes[i2][j].i,warp.nodes[i2][j].i,warp.nodes[i2][j].i); + glTexCoord2f((warp.nodes[i2][j].u * uv_width), (warp.nodes[i2][j].v * uv_height)); + glVertex3f(warp.nodes[i2][j].x,warp.nodes[i2][j].y,0.0); + + glColor3f(warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i); + glTexCoord2f((warp.nodes[i2][j+1].u * uv_width), (warp.nodes[i2][j+1].v * uv_height)); + glVertex3f(warp.nodes[i2][j+1].x,warp.nodes[i2][j+1].y,0.0); + + glColor3f(warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i); + glTexCoord2f((warp.nodes[i2][j+1].u * uv_width), (warp.nodes[i2][j+1].v * uv_height)); + glVertex3f(warp.nodes[i2][j+1].x,warp.nodes[i2][j+1].y,0.0); + + } + } + glEnd(); + } else{ + printf("Dome Error: Warp Mode %d unsupported. Try 1 for Polar Mesh or 2 for Fisheye.\n", warp.mode); + } +} + + +bool KX_Dome::ParseWarpMesh(STR_String text) +{ +/* +//Notes about the supported data format: +File example:: + mode + width height + n0_x n0_y n0_u n0_v n0_i + n1_x n1_y n1_u n1_v n1_i + n2_x n1_y n2_u n2_v n2_i + n3_x n3_y n3_u n3_v n3_i + (...) +First line is the image type the mesh is support to be applied to: 2 = fisheye, 1=radial +Tthe next line has the mesh dimensions +Rest of the lines are the nodes of the mesh. Each line has x y u v i + (x,y) are the normalised screen coordinates + (u,v) texture coordinates + i a multiplicative intensity factor + +x varies from -screen aspect to screen aspect +y varies from -1 to 1 +u and v vary from 0 to 1 +i ranges from 0 to 1, if negative don't draw that mesh node +*/ + int i; + int nodeX=0, nodeY=0; + + vector<STR_String> columns, lines; + + lines = text.Explode('\n'); + if(lines.size() < 6){ + printf("Dome Error: Warp Mesh File with insufficient data!\n"); + return false; + } + columns = lines[1].Explode(' '); + if(columns.size() == 1) + columns = lines[1].Explode('\t'); + + if(columns.size() !=2){ + printf("Dome Error: Warp Mesh File incorrect. The second line should contain: width height.\n"); + return false; + } + + warp.mode = atoi(lines[0]);// 1 = radial, 2 = fisheye + + warp.n_width = atoi(columns[0]); + warp.n_height = atoi(columns[1]); + + if ((int)lines.size() < 2 + (warp.n_width * warp.n_height)){ + printf("Dome Error: Warp Mesh File with insufficient data!\n"); + return false; + }else{ + warp.nodes = vector<vector<WarpMeshNode> > (warp.n_height, vector<WarpMeshNode>(warp.n_width)); + + for(i=2; i-2 < (warp.n_width*warp.n_height); i++){ + columns = lines[i].Explode(' '); + if(columns.size() == 1) + columns = lines[i].Explode('\t'); + + if (columns.size() == 5){ + nodeX = (i-2)%warp.n_width; + nodeY = ((i-2) - nodeX) / warp.n_width; + + warp.nodes[nodeY][nodeX].x = atof(columns[0]); + warp.nodes[nodeY][nodeX].y = atof(columns[1]); + warp.nodes[nodeY][nodeX].u = atof(columns[2]); + warp.nodes[nodeY][nodeX].v = atof(columns[3]); + warp.nodes[nodeY][nodeX].i = atof(columns[4]); + } + else{ + warp.nodes.clear(); + printf("Dome Error: Warp Mesh File with wrong number of fields. You should use 5: x y u v i.\n"); + return false; + } + } + } + return true; +} + +void KX_Dome::CreateMeshDome180(void) +{ +/* +1)- Define the faces of half of a cube + - each face is made out of 2 triangles +2) Subdivide the faces + - more resolution == more curved lines +3) Spherize the cube + - normalize the verts +4) Flatten onto xz plane + - transform it onto an equidistant spherical projection techniques to transform the sphere onto a dome image +*/ + int i,j; + float sqrt_2 = sqrt(2.0); + float uv_ratio = (float)(m_buffersize-1) / m_imagesize; + + m_radangle = m_angle * M_PI/180.0;//calculates the radians angle, used for flattening + + //creating faces for the env mapcube 180º Dome + // Top Face - just a triangle + cubetop[0].verts[0][0] = -sqrt_2 / 2.0; + cubetop[0].verts[0][1] = 0.0; + cubetop[0].verts[0][2] = 0.5; + cubetop[0].u[0] = 0.0; + cubetop[0].v[0] = uv_ratio; + + cubetop[0].verts[1][0] = 0.0; + cubetop[0].verts[1][1] = sqrt_2 / 2.0; + cubetop[0].verts[1][2] = 0.5; + cubetop[0].u[1] = 0.0; + cubetop[0].v[1] = 0.0; + + cubetop[0].verts[2][0] = sqrt_2 / 2.0; + cubetop[0].verts[2][1] = 0.0; + cubetop[0].verts[2][2] = 0.5; + cubetop[0].u[2] = uv_ratio; + cubetop[0].v[2] = 0.0; + + nfacestop = 1; + + /* Bottom face - just a triangle */ + cubebottom[0].verts[0][0] = -sqrt_2 / 2.0; + cubebottom[0].verts[0][1] = 0.0; + cubebottom[0].verts[0][2] = -0.5; + cubebottom[0].u[0] = uv_ratio; + cubebottom[0].v[0] = 0.0; + + cubebottom[0].verts[1][0] = sqrt_2 / 2.0; + cubebottom[0].verts[1][1] = 0; + cubebottom[0].verts[1][2] = -0.5; + cubebottom[0].u[1] = 0.0; + cubebottom[0].v[1] = uv_ratio; + + cubebottom[0].verts[2][0] = 0.0; + cubebottom[0].verts[2][1] = sqrt_2 / 2.0; + cubebottom[0].verts[2][2] = -0.5; + cubebottom[0].u[2] = 0.0; + cubebottom[0].v[2] = 0.0; + + nfacesbottom = 1; + + /* Left face - two triangles */ + + cubeleft[0].verts[0][0] = -sqrt_2 / 2.0; + cubeleft[0].verts[0][1] = .0; + cubeleft[0].verts[0][2] = -0.5; + cubeleft[0].u[0] = 0.0; + cubeleft[0].v[0] = 0.0; + + cubeleft[0].verts[1][0] = 0.0; + cubeleft[0].verts[1][1] = sqrt_2 / 2.0; + cubeleft[0].verts[1][2] = -0.5; + cubeleft[0].u[1] = uv_ratio; + cubeleft[0].v[1] = 0.0; + + cubeleft[0].verts[2][0] = -sqrt_2 / 2.0; + cubeleft[0].verts[2][1] = 0.0; + cubeleft[0].verts[2][2] = 0.5; + cubeleft[0].u[2] = 0.0; + cubeleft[0].v[2] = uv_ratio; + + //second triangle + cubeleft[1].verts[0][0] = -sqrt_2 / 2.0; + cubeleft[1].verts[0][1] = 0.0; + cubeleft[1].verts[0][2] = 0.5; + cubeleft[1].u[0] = 0.0; + cubeleft[1].v[0] = uv_ratio; + + cubeleft[1].verts[1][0] = 0.0; + cubeleft[1].verts[1][1] = sqrt_2 / 2.0; + cubeleft[1].verts[1][2] = -0.5; + cubeleft[1].u[1] = uv_ratio; + cubeleft[1].v[1] = 0.0; + + cubeleft[1].verts[2][0] = 0.0; + cubeleft[1].verts[2][1] = sqrt_2 / 2.0; + cubeleft[1].verts[2][2] = 0.5; + cubeleft[1].u[2] = uv_ratio; + cubeleft[1].v[2] = uv_ratio; + + nfacesleft = 2; + + /* Right face - two triangles */ + cuberight[0].verts[0][0] = 0.0; + cuberight[0].verts[0][1] = sqrt_2 / 2.0; + cuberight[0].verts[0][2] = -0.5; + cuberight[0].u[0] = 0.0; + cuberight[0].v[0] = 0.0; + + cuberight[0].verts[1][0] = sqrt_2 / 2.0; + cuberight[0].verts[1][1] = 0.0; + cuberight[0].verts[1][2] = -0.5; + cuberight[0].u[1] = uv_ratio; + cuberight[0].v[1] = 0.0; + + cuberight[0].verts[2][0] = sqrt_2 / 2.0; + cuberight[0].verts[2][1] = 0.0; + cuberight[0].verts[2][2] = 0.5; + cuberight[0].u[2] = uv_ratio; + cuberight[0].v[2] = uv_ratio; + + //second triangle + cuberight[1].verts[0][0] = 0.0; + cuberight[1].verts[0][1] = sqrt_2 / 2.0; + cuberight[1].verts[0][2] = -0.5; + cuberight[1].u[0] = 0.0; + cuberight[1].v[0] = 0.0; + + cuberight[1].verts[1][0] = sqrt_2 / 2.0; + cuberight[1].verts[1][1] = 0.0; + cuberight[1].verts[1][2] = 0.5; + cuberight[1].u[1] = uv_ratio; + cuberight[1].v[1] = uv_ratio; + + cuberight[1].verts[2][0] = 0.0; + cuberight[1].verts[2][1] = sqrt_2 / 2.0; + cuberight[1].verts[2][2] = 0.5; + cuberight[1].u[2] = 0.0; + cuberight[1].v[2] = uv_ratio; + + nfacesright = 2; + + //Refine a triangular mesh by bisecting each edge forms 3 new triangles for each existing triangle on each iteration + //Could be made more efficient for drawing if the triangles were ordered in a fan. Not that important since we are using DisplayLists + + for(i=0;i<m_resolution;i++){ + cubetop.resize(4*nfacestop); + SplitFace(cubetop,&nfacestop); + cubebottom.resize(4*nfacesbottom); + SplitFace(cubebottom,&nfacesbottom); + cubeleft.resize(4*nfacesleft); + SplitFace(cubeleft,&nfacesleft); + cuberight.resize(4*nfacesright); + SplitFace(cuberight,&nfacesright); + } + + // Turn into a hemisphere + for(j=0;j<3;j++){ + for(i=0;i<nfacestop;i++) + cubetop[i].verts[j].normalize(); + for(i=0;i<nfacesbottom;i++) + cubebottom[i].verts[j].normalize(); + for(i=0;i<nfacesleft;i++) + cubeleft[i].verts[j].normalize(); + for(i=0;i<nfacesright;i++) + cuberight[i].verts[j].normalize(); + } + + //flatten onto xz plane + for(i=0;i<nfacestop;i++) + FlattenDome(cubetop[i].verts); + for(i=0;i<nfacesbottom;i++) + FlattenDome(cubebottom[i].verts); + for(i=0;i<nfacesleft;i++) + FlattenDome(cubeleft[i].verts); + for(i=0;i<nfacesright;i++) + FlattenDome(cuberight[i].verts); + +} + +void KX_Dome::CreateMeshDome250(void) +{ +/* +1)- Define the faces of a cube without the back face + - each face is made out of 2 triangles +2) Subdivide the faces + - more resolution == more curved lines +3) Spherize the cube + - normalize the verts +4) Flatten onto xz plane + - transform it onto an equidistant spherical projection techniques to transform the sphere onto a dome image +*/ + + int i,j; + float uv_height, uv_base; + float verts_height; + + float rad_ang = m_angle * MT_PI / 180.0; + float uv_ratio = (float)(m_buffersize-1) / m_imagesize; + + m_radangle = m_angle * M_PI/180.0;//calculates the radians angle, used for flattening +/* +verts_height is the exactly needed height of the cube faces (not always 1.0). +When we want some horizontal information (e.g. for horizontal 220º domes) we don't need to create and tesselate the whole cube. +Therefore the lateral cube faces could be small, and the tesselate mesh would be completely used. +(if we always worked with verts_height = 1.0, we would be discarding a lot of the calculated and tesselated geometry). + +So I came out with this formula: +verts_height = tan((rad_ang/2) - (MT_PI/2))*sqrt(2.0); + +Here we take half the sphere(rad_ang/2) and subtract a quarter of it (MT_PI/2) +Therefore we have the lenght in radians of the dome/sphere over the horizon. +Once we take the tangent of that angle, you have the verts coordinate corresponding to the verts on the side faces. +Then we need to multiply it by sqrt(2.0) to get the coordinate of the verts on the diagonal of the original cube. +*/ + verts_height = tan((rad_ang/2) - (MT_PI/2))*sqrt(2.0); + + uv_height = uv_ratio * ((verts_height/2) + 0.5); + uv_base = uv_ratio * (1.0 - ((verts_height/2) + 0.5)); + + //creating faces for the env mapcube 180º Dome + // Front Face - 2 triangles + cubefront[0].verts[0][0] =-1.0; + cubefront[0].verts[0][1] = 1.0; + cubefront[0].verts[0][2] =-1.0; + cubefront[0].u[0] = 0.0; + cubefront[0].v[0] = 0.0; + + cubefront[0].verts[1][0] = 1.0; + cubefront[0].verts[1][1] = 1.0; + cubefront[0].verts[1][2] = 1.0; + cubefront[0].u[1] = uv_ratio; + cubefront[0].v[1] = uv_ratio; + + cubefront[0].verts[2][0] =-1.0; + cubefront[0].verts[2][1] = 1.0; + cubefront[0].verts[2][2] = 1.0; + cubefront[0].u[2] = 0.0; + cubefront[0].v[2] = uv_ratio; + + //second triangle + cubefront[1].verts[0][0] = 1.0; + cubefront[1].verts[0][1] = 1.0; + cubefront[1].verts[0][2] = 1.0; + cubefront[1].u[0] = uv_ratio; + cubefront[1].v[0] = uv_ratio; + + cubefront[1].verts[1][0] =-1.0; + cubefront[1].verts[1][1] = 1.0; + cubefront[1].verts[1][2] =-1.0; + cubefront[1].u[1] = 0.0; + cubefront[1].v[1] = 0.0; + + cubefront[1].verts[2][0] = 1.0; + cubefront[1].verts[2][1] = 1.0; + cubefront[1].verts[2][2] =-1.0; + cubefront[1].u[2] = uv_ratio; + cubefront[1].v[2] = 0.0; + + nfacesfront = 2; + + // Left Face - 2 triangles + cubeleft[0].verts[0][0] =-1.0; + cubeleft[0].verts[0][1] = 1.0; + cubeleft[0].verts[0][2] =-1.0; + cubeleft[0].u[0] = uv_ratio; + cubeleft[0].v[0] = 0.0; + + cubeleft[0].verts[1][0] =-1.0; + cubeleft[0].verts[1][1] =-verts_height; + cubeleft[0].verts[1][2] = 1.0; + cubeleft[0].u[1] = uv_base; + cubeleft[0].v[1] = uv_ratio; + + cubeleft[0].verts[2][0] =-1.0; + cubeleft[0].verts[2][1] =-verts_height; + cubeleft[0].verts[2][2] =-1.0; + cubeleft[0].u[2] = uv_base; + cubeleft[0].v[2] = 0.0; + + //second triangle + cubeleft[1].verts[0][0] =-1.0; + cubeleft[1].verts[0][1] =-verts_height; + cubeleft[1].verts[0][2] = 1.0; + cubeleft[1].u[0] = uv_base; + cubeleft[1].v[0] = uv_ratio; + + cubeleft[1].verts[1][0] =-1.0; + cubeleft[1].verts[1][1] = 1.0; + cubeleft[1].verts[1][2] =-1.0; + cubeleft[1].u[1] = uv_ratio; + cubeleft[1].v[1] = 0.0; + + cubeleft[1].verts[2][0] =-1.0; + cubeleft[1].verts[2][1] = 1.0; + cubeleft[1].verts[2][2] = 1.0; + cubeleft[1].u[2] = uv_ratio; + cubeleft[1].v[2] = uv_ratio; + + nfacesleft = 2; + + // right Face - 2 triangles + cuberight[0].verts[0][0] = 1.0; + cuberight[0].verts[0][1] = 1.0; + cuberight[0].verts[0][2] = 1.0; + cuberight[0].u[0] = 0.0; + cuberight[0].v[0] = uv_ratio; + + cuberight[0].verts[1][0] = 1.0; + cuberight[0].verts[1][1] =-verts_height; + cuberight[0].verts[1][2] =-1.0; + cuberight[0].u[1] = uv_height; + cuberight[0].v[1] = 0.0; + + cuberight[0].verts[2][0] = 1.0; + cuberight[0].verts[2][1] =-verts_height; + cuberight[0].verts[2][2] = 1.0; + cuberight[0].u[2] = uv_height; + cuberight[0].v[2] = uv_ratio; + + //second triangle + cuberight[1].verts[0][0] = 1.0; + cuberight[1].verts[0][1] =-verts_height; + cuberight[1].verts[0][2] =-1.0; + cuberight[1].u[0] = uv_height; + cuberight[1].v[0] = 0.0; + + cuberight[1].verts[1][0] = 1.0; + cuberight[1].verts[1][1] = 1.0; + cuberight[1].verts[1][2] = 1.0; + cuberight[1].u[1] = 0.0; + cuberight[1].v[1] = uv_ratio; + + cuberight[1].verts[2][0] = 1.0; + cuberight[1].verts[2][1] = 1.0; + cuberight[1].verts[2][2] =-1.0; + cuberight[1].u[2] = 0.0; + cuberight[1].v[2] = 0.0; + + nfacesright = 2; + + // top Face - 2 triangles + cubetop[0].verts[0][0] =-1.0; + cubetop[0].verts[0][1] = 1.0; + cubetop[0].verts[0][2] = 1.0; + cubetop[0].u[0] = 0.0; + cubetop[0].v[0] = 0.0; + + cubetop[0].verts[1][0] = 1.0; + cubetop[0].verts[1][1] =-verts_height; + cubetop[0].verts[1][2] = 1.0; + cubetop[0].u[1] = uv_ratio; + cubetop[0].v[1] = uv_height; + + cubetop[0].verts[2][0] =-1.0; + cubetop[0].verts[2][1] =-verts_height; + cubetop[0].verts[2][2] = 1.0; + cubetop[0].u[2] = 0.0; + cubetop[0].v[2] = uv_height; + + //second triangle + cubetop[1].verts[0][0] = 1.0; + cubetop[1].verts[0][1] =-verts_height; + cubetop[1].verts[0][2] = 1.0; + cubetop[1].u[0] = uv_ratio; + cubetop[1].v[0] = uv_height; + + cubetop[1].verts[1][0] =-1.0; + cubetop[1].verts[1][1] = 1.0; + cubetop[1].verts[1][2] = 1.0; + cubetop[1].u[1] = 0.0; + cubetop[1].v[1] = 0.0; + + cubetop[1].verts[2][0] = 1.0; + cubetop[1].verts[2][1] = 1.0; + cubetop[1].verts[2][2] = 1.0; + cubetop[1].u[2] = uv_ratio; + cubetop[1].v[2] = 0.0; + + nfacestop = 2; + + // bottom Face - 2 triangles + cubebottom[0].verts[0][0] =-1.0; + cubebottom[0].verts[0][1] =-verts_height; + cubebottom[0].verts[0][2] =-1.0; + cubebottom[0].u[0] = 0.0; + cubebottom[0].v[0] = uv_base; + + cubebottom[0].verts[1][0] = 1.0; + cubebottom[0].verts[1][1] = 1.0; + cubebottom[0].verts[1][2] =-1.0; + cubebottom[0].u[1] = uv_ratio; + cubebottom[0].v[1] = uv_ratio; + + cubebottom[0].verts[2][0] =-1.0; + cubebottom[0].verts[2][1] = 1.0; + cubebottom[0].verts[2][2] =-1.0; + cubebottom[0].u[2] = 0.0; + cubebottom[0].v[2] = uv_ratio; + + //second triangle + cubebottom[1].verts[0][0] = 1.0; + cubebottom[1].verts[0][1] = 1.0; + cubebottom[1].verts[0][2] =-1.0; + cubebottom[1].u[0] = uv_ratio; + cubebottom[1].v[0] = uv_ratio; + + cubebottom[1].verts[1][0] =-1.0; + cubebottom[1].verts[1][1] =-verts_height; + cubebottom[1].verts[1][2] =-1.0; + cubebottom[1].u[1] = 0.0; + cubebottom[1].v[1] = uv_base; + + cubebottom[1].verts[2][0] = 1.0; + cubebottom[1].verts[2][1] =-verts_height; + cubebottom[1].verts[2][2] =-1.0; + cubebottom[1].u[2] = uv_ratio; + cubebottom[1].v[2] = uv_base; + + nfacesbottom = 2; + + //Refine a triangular mesh by bisecting each edge forms 3 new triangles for each existing triangle on each iteration + //It could be made more efficient for drawing if the triangles were ordered in a strip! + + for(i=0;i<m_resolution;i++){ + cubefront.resize(4*nfacesfront); + SplitFace(cubefront,&nfacesfront); + cubetop.resize(4*nfacestop); + SplitFace(cubetop,&nfacestop); + cubebottom.resize(4*nfacesbottom); + SplitFace(cubebottom,&nfacesbottom); + cubeleft.resize(4*nfacesleft); + SplitFace(cubeleft,&nfacesleft); + cuberight.resize(4*nfacesright); + SplitFace(cuberight,&nfacesright); + } + + // Turn into a hemisphere/sphere + for(j=0;j<3;j++){ + for(i=0;i<nfacesfront;i++) + cubefront[i].verts[j].normalize(); + for(i=0;i<nfacestop;i++) + cubetop[i].verts[j].normalize(); + for(i=0;i<nfacesbottom;i++) + cubebottom[i].verts[j].normalize(); + for(i=0;i<nfacesleft;i++) + cubeleft[i].verts[j].normalize(); + for(i=0;i<nfacesright;i++) + cuberight[i].verts[j].normalize(); + } + + //flatten onto xz plane + for(i=0;i<nfacesfront;i++) + FlattenDome(cubefront[i].verts); + for(i=0;i<nfacestop;i++) + FlattenDome(cubetop[i].verts); + for(i=0;i<nfacesbottom;i++) + FlattenDome(cubebottom[i].verts); + for(i=0;i<nfacesleft;i++) + FlattenDome(cubeleft[i].verts); + for(i=0;i<nfacesright;i++) + FlattenDome(cuberight[i].verts); +} + +void KX_Dome::CreateMeshPanorama(void) +{ +/* +1)- Define the faces of a cube without the top and bottom faces + - each face is made out of 2 triangles +2) Subdivide the faces + - more resolution == more curved lines +3) Spherize the cube + - normalize the verts t +4) Flatten onto xz plane + - use spherical projection techniques to transform the sphere onto a flat panorama +*/ + int i,j; + + float sqrt_2 = sqrt(2.0); + float uv_ratio = (float)(m_buffersize-1) / m_imagesize; + + /* Top face - two triangles */ + cubetop[0].verts[0][0] = -sqrt_2; + cubetop[0].verts[0][1] = 0.0; + cubetop[0].verts[0][2] = 1.0; + cubetop[0].u[0] = 0.0; + cubetop[0].v[0] = uv_ratio; + + cubetop[0].verts[1][0] = 0.0; + cubetop[0].verts[1][1] = sqrt_2; + cubetop[0].verts[1][2] = 1.0; + cubetop[0].u[1] = 0.0; + cubetop[0].v[1] = 0.0; + + //second triangle + cubetop[0].verts[2][0] = sqrt_2; + cubetop[0].verts[2][1] = 0.0; + cubetop[0].verts[2][2] = 1.0; + cubetop[0].u[2] = uv_ratio; + cubetop[0].v[2] = 0.0; + + cubetop[1].verts[0][0] = sqrt_2; + cubetop[1].verts[0][1] = 0.0; + cubetop[1].verts[0][2] = 1.0; + cubetop[1].u[0] = uv_ratio; + cubetop[1].v[0] = 0.0; + + cubetop[1].verts[1][0] = 0.0; + cubetop[1].verts[1][1] = -sqrt_2; + cubetop[1].verts[1][2] = 1.0; + cubetop[1].u[1] = uv_ratio; + cubetop[1].v[1] = uv_ratio; + + cubetop[1].verts[2][0] = -sqrt_2; + cubetop[1].verts[2][1] = 0.0; + cubetop[1].verts[2][2] = 1.0; + cubetop[1].u[2] = 0.0; + cubetop[1].v[2] = uv_ratio; + + nfacestop = 2; + + /* Bottom face - two triangles */ + cubebottom[0].verts[0][0] = -sqrt_2; + cubebottom[0].verts[0][1] = 0.0; + cubebottom[0].verts[0][2] = -1.0; + cubebottom[0].u[0] = uv_ratio; + cubebottom[0].v[0] = 0.0; + + cubebottom[0].verts[1][0] = sqrt_2; + cubebottom[0].verts[1][1] = 0.0; + cubebottom[0].verts[1][2] = -1.0; + cubebottom[0].u[1] = 0.0; + cubebottom[0].v[1] = uv_ratio; + + cubebottom[0].verts[2][0] = 0.0; + cubebottom[0].verts[2][1] = sqrt_2; + cubebottom[0].verts[2][2] = -1.0; + cubebottom[0].u[2] = 0.0; + cubebottom[0].v[2] = 0.0; + + //second triangle + cubebottom[1].verts[0][0] = sqrt_2; + cubebottom[1].verts[0][1] = 0.0; + cubebottom[1].verts[0][2] = -1.0; + cubebottom[1].u[0] = 0.0; + cubebottom[1].v[0] = uv_ratio; + + cubebottom[1].verts[1][0] = -sqrt_2; + cubebottom[1].verts[1][1] = 0.0; + cubebottom[1].verts[1][2] = -1.0; + cubebottom[1].u[1] = uv_ratio; + cubebottom[1].v[1] = 0.0; + + cubebottom[1].verts[2][0] = 0.0; + cubebottom[1].verts[2][1] = -sqrt_2; + cubebottom[1].verts[2][2] = -1.0; + cubebottom[1].u[2] = uv_ratio; + cubebottom[1].v[2] = uv_ratio; + + nfacesbottom = 2; + + /* Left Back (135º) face - two triangles */ + + cubeleftback[0].verts[0][0] = 0; + cubeleftback[0].verts[0][1] = -sqrt_2; + cubeleftback[0].verts[0][2] = -1.0; + cubeleftback[0].u[0] = 0; + cubeleftback[0].v[0] = 0; + + cubeleftback[0].verts[1][0] = -sqrt_2; + cubeleftback[0].verts[1][1] = 0; + cubeleftback[0].verts[1][2] = -1.0; + cubeleftback[0].u[1] = uv_ratio; + cubeleftback[0].v[1] = 0; + + cubeleftback[0].verts[2][0] = 0; + cubeleftback[0].verts[2][1] = -sqrt_2; + cubeleftback[0].verts[2][2] = 1.0; + cubeleftback[0].u[2] = 0; + cubeleftback[0].v[2] = uv_ratio; + + //second triangle + cubeleftback[1].verts[0][0] = 0; + cubeleftback[1].verts[0][1] = -sqrt_2; + cubeleftback[1].verts[0][2] = 1.0; + cubeleftback[1].u[0] = 0; + cubeleftback[1].v[0] = uv_ratio; + + cubeleftback[1].verts[1][0] = -sqrt_2; + cubeleftback[1].verts[1][1] = 0; + cubeleftback[1].verts[1][2] = -1.0; + cubeleftback[1].u[1] = uv_ratio; + cubeleftback[1].v[1] = 0; + + cubeleftback[1].verts[2][0] = -sqrt_2; + cubeleftback[1].verts[2][1] = 0; + cubeleftback[1].verts[2][2] = 1.0; + cubeleftback[1].u[2] = uv_ratio; + cubeleftback[1].v[2] = uv_ratio; + + nfacesleftback = 2; + + /* Left face - two triangles */ + + cubeleft[0].verts[0][0] = -sqrt_2; + cubeleft[0].verts[0][1] = 0; + cubeleft[0].verts[0][2] = -1.0; + cubeleft[0].u[0] = 0; + cubeleft[0].v[0] = 0; + + cubeleft[0].verts[1][0] = 0; + cubeleft[0].verts[1][1] = sqrt_2; + cubeleft[0].verts[1][2] = -1.0; + cubeleft[0].u[1] = uv_ratio; + cubeleft[0].v[1] = 0; + + cubeleft[0].verts[2][0] = -sqrt_2; + cubeleft[0].verts[2][1] = 0; + cubeleft[0].verts[2][2] = 1.0; + cubeleft[0].u[2] = 0; + cubeleft[0].v[2] = uv_ratio; + + //second triangle + cubeleft[1].verts[0][0] = -sqrt_2; + cubeleft[1].verts[0][1] = 0; + cubeleft[1].verts[0][2] = 1.0; + cubeleft[1].u[0] = 0; + cubeleft[1].v[0] = uv_ratio; + + cubeleft[1].verts[1][0] = 0; + cubeleft[1].verts[1][1] = sqrt_2; + cubeleft[1].verts[1][2] = -1.0; + cubeleft[1].u[1] = uv_ratio; + cubeleft[1].v[1] = 0; + + cubeleft[1].verts[2][0] = 0; + cubeleft[1].verts[2][1] = sqrt_2; + cubeleft[1].verts[2][2] = 1.0; + cubeleft[1].u[2] = uv_ratio; + cubeleft[1].v[2] = uv_ratio; + + nfacesleft = 2; + + /* Right face - two triangles */ + cuberight[0].verts[0][0] = 0; + cuberight[0].verts[0][1] = sqrt_2; + cuberight[0].verts[0][2] = -1.0; + cuberight[0].u[0] = 0; + cuberight[0].v[0] = 0; + + cuberight[0].verts[1][0] = sqrt_2; + cuberight[0].verts[1][1] = 0; + cuberight[0].verts[1][2] = -1.0; + cuberight[0].u[1] = uv_ratio; + cuberight[0].v[1] = 0; + + cuberight[0].verts[2][0] = sqrt_2; + cuberight[0].verts[2][1] = 0; + cuberight[0].verts[2][2] = 1.0; + cuberight[0].u[2] = uv_ratio; + cuberight[0].v[2] = uv_ratio; + + //second triangle + cuberight[1].verts[0][0] = 0; + cuberight[1].verts[0][1] = sqrt_2; + cuberight[1].verts[0][2] = -1.0; + cuberight[1].u[0] = 0; + cuberight[1].v[0] = 0; + + cuberight[1].verts[1][0] = sqrt_2; + cuberight[1].verts[1][1] = 0; + cuberight[1].verts[1][2] = 1.0; + cuberight[1].u[1] = uv_ratio; + cuberight[1].v[1] = uv_ratio; + + cuberight[1].verts[2][0] = 0; + cuberight[1].verts[2][1] = sqrt_2; + cuberight[1].verts[2][2] = 1.0; + cuberight[1].u[2] = 0; + cuberight[1].v[2] = uv_ratio; + + nfacesright = 2; + + /* Right Back (-135º) face - two triangles */ + cuberightback[0].verts[0][0] = sqrt_2; + cuberightback[0].verts[0][1] = 0; + cuberightback[0].verts[0][2] = -1.0; + cuberightback[0].u[0] = 0; + cuberightback[0].v[0] = 0; + + cuberightback[0].verts[1][0] = 0; + cuberightback[0].verts[1][1] = -sqrt_2; + cuberightback[0].verts[1][2] = -1.0; + cuberightback[0].u[1] = uv_ratio; + cuberightback[0].v[1] = 0; + + cuberightback[0].verts[2][0] = 0; + cuberightback[0].verts[2][1] = -sqrt_2; + cuberightback[0].verts[2][2] = 1.0; + cuberightback[0].u[2] = uv_ratio; + cuberightback[0].v[2] = uv_ratio; + + //second triangle + cuberightback[1].verts[0][0] = sqrt_2; + cuberightback[1].verts[0][1] = 0; + cuberightback[1].verts[0][2] = -1.0; + cuberightback[1].u[0] = 0; + cuberightback[1].v[0] = 0; + + cuberightback[1].verts[1][0] = 0; + cuberightback[1].verts[1][1] = -sqrt_2; + cuberightback[1].verts[1][2] = 1.0; + cuberightback[1].u[1] = uv_ratio; + cuberightback[1].v[1] = uv_ratio; + + cuberightback[1].verts[2][0] = sqrt_2; + cuberightback[1].verts[2][1] = 0; + cuberightback[1].verts[2][2] = 1.0; + cuberightback[1].u[2] = 0; + cuberightback[1].v[2] = uv_ratio; + + nfacesrightback = 2; + + // Subdivide the faces + for(i=0;i<m_resolution;i++) + { + cubetop.resize(4*nfacestop); + SplitFace(cubetop,&nfacestop); + + cubebottom.resize(4*nfacesbottom); + SplitFace(cubebottom,&nfacesbottom); + + cubeleft.resize(4*nfacesleft); + SplitFace(cubeleft,&nfacesleft); + + cuberight.resize(4*nfacesright); + SplitFace(cuberight,&nfacesright); + + cubeleftback.resize(4*nfacesleftback); + SplitFace(cubeleftback,&nfacesleftback); + + cuberightback.resize(4*nfacesrightback); + SplitFace(cuberightback,&nfacesrightback); + } + + // Spherize the cube + for(j=0;j<3;j++) + { + for(i=0;i<nfacestop;i++) + cubetop[i].verts[j].normalize(); + + for(i=0;i<nfacesbottom;i++) + cubebottom[i].verts[j].normalize(); + + for(i=0;i<nfacesleftback;i++) + cubeleftback[i].verts[j].normalize(); + + for(i=0;i<nfacesleft;i++) + cubeleft[i].verts[j].normalize(); + + for(i=0;i<nfacesright;i++) + cuberight[i].verts[j].normalize(); + + for(i=0;i<nfacesrightback;i++) + cuberightback[i].verts[j].normalize(); + } + + //Flatten onto xz plane + for(i=0;i<nfacesleftback;i++) + FlattenPanorama(cubeleftback[i].verts); + + for(i=0;i<nfacesleft;i++) + FlattenPanorama(cubeleft[i].verts); + + for(i=0;i<nfacesright;i++) + FlattenPanorama(cuberight[i].verts); + + for(i=0;i<nfacesrightback;i++) + FlattenPanorama(cuberightback[i].verts); + + for(i=0;i<nfacestop;i++) + FlattenPanorama(cubetop[i].verts); + + for(i=0;i<nfacesbottom;i++) + FlattenPanorama(cubebottom[i].verts); +} + +void KX_Dome::FlattenDome(MT_Vector3 verts[3]) +{ + double phi, r; + + for (int i=0;i<3;i++){ + r = atan2(sqrt(verts[i][0]*verts[i][0] + verts[i][2]*verts[i][2]), verts[i][1]); + r /= m_radangle/2; + + phi = atan2(verts[i][2], verts[i][0]); + + verts[i][0] = r * cos(phi); + verts[i][1] = 0; + verts[i][2] = r * sin(phi); + + if (r > 1.0){ + //round the border + verts[i][0] = cos(phi); + verts[i][1] = -3.0; + verts[i][2] = sin(phi); + } + } +} + +void KX_Dome::FlattenPanorama(MT_Vector3 verts[3]) +{ +// it creates a full spherical panoramic (360º) + int i; + double phi; + bool edge=false; + + for (i=0;i<3;i++){ + phi = atan2(verts[i][1], verts[i][0]); + phi *= -1.0; //flipping + + if (phi == -MT_PI) //It's on the edge + edge=true; + + verts[i][0] = phi / MT_PI; + verts[i][1] = 0; + + verts[i][2] = atan2(verts[i][2], 1.0); + verts[i][2] /= MT_PI / 2; + } + if(edge){ + bool right=false; + + for (i=0;i<3;i++){ + if(fmod(verts[i][0],1.0) > 0.0){ + right=true; + break; + } + } + if(right){ + for (i=0;i<3;i++){ + if(verts[i][0] < 0.0) + verts[i][0] *= -1.0; + } + } + } +} + +void KX_Dome::SplitFace(vector <DomeFace>& face, int *nfaces) +{ + int i; + int n1, n2; + + n1 = n2 = *nfaces; + + for(i=0;i<n1;i++){ + + face[n2].verts[0] = (face[i].verts[0] + face[i].verts[1]) /2; + face[n2].verts[1] = face[i].verts[1]; + face[n2].verts[2] = (face[i].verts[1] + face[i].verts[2]) /2; + face[n2].u[0] = (face[i].u[0] + face[i].u[1]) /2; + face[n2].u[1] = face[i].u[1]; + face[n2].u[2] = (face[i].u[1] + face[i].u[2]) /2; + face[n2].v[0] = (face[i].v[0] + face[i].v[1]) /2; + face[n2].v[1] = face[i].v[1]; + face[n2].v[2] = (face[i].v[1] + face[i].v[2]) /2; + + face[n2+1].verts[0] = (face[i].verts[1] + face[i].verts[2]) /2; + face[n2+1].verts[1] = face[i].verts[2]; + face[n2+1].verts[2] = (face[i].verts[2] + face[i].verts[0]) /2; + face[n2+1].u[0] = (face[i].u[1] + face[i].u[2]) /2; + face[n2+1].u[1] = face[i].u[2]; + face[n2+1].u[2] = (face[i].u[2] + face[i].u[0]) /2; + face[n2+1].v[0] = (face[i].v[1] + face[i].v[2]) /2; + face[n2+1].v[1] = face[i].v[2]; + face[n2+1].v[2] = (face[i].v[2] + face[i].v[0]) /2; + + face[n2+2].verts[0] = (face[i].verts[0] + face[i].verts[1]) /2; + face[n2+2].verts[1] = (face[i].verts[1] + face[i].verts[2]) /2; + face[n2+2].verts[2] = (face[i].verts[2] + face[i].verts[0]) /2; + face[n2+2].u[0] = (face[i].u[0] + face[i].u[1]) /2; + face[n2+2].u[1] = (face[i].u[1] + face[i].u[2]) /2; + face[n2+2].u[2] = (face[i].u[2] + face[i].u[0]) /2; + face[n2+2].v[0] = (face[i].v[0] + face[i].v[1]) /2; + face[n2+2].v[1] = (face[i].v[1] + face[i].v[2]) /2; + face[n2+2].v[2] = (face[i].v[2] + face[i].v[0]) /2; + + //face[i].verts[0] = face[i].verts[0] ; + face[i].verts[1] = (face[i].verts[0] + face[i].verts[1]) /2; + face[i].verts[2] = (face[i].verts[0] + face[i].verts[2]) /2; + //face[i].u[0] = face[i].u[0]; + face[i].u[1] = (face[i].u[0] + face[i].u[1]) /2; + face[i].u[2] = (face[i].u[0] + face[i].u[2]) /2; + //face[i].v[0] = face[i].v[0] ; + face[i].v[1] = (face[i].v[0] + face[i].v[1]) /2; + face[i].v[2] = (face[i].v[0] + face[i].v[2]) /2; + + n2 += 3; // number of faces + } + *nfaces = n2; +} + +void KX_Dome::CalculateFrustum(KX_Camera * cam) +{ + /* + // manually creating a 90º Field of View Frustum + + the original formula: + top = tan(fov*3.14159/360.0) * near [for fov in degrees] + fov*0.5 = arctan ((top-bottom)*0.5 / near) [for fov in radians] + bottom = -top + left = aspect * bottom + right = aspect * top + + // the equivalent GLU call is: + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(90.0,1.0,cam->GetCameraNear(),cam->GetCameraFar()); + */ + + RAS_FrameFrustum m_frustrum; //90 deg. Frustum + + m_frustrum.camnear = cam->GetCameraNear(); + m_frustrum.camfar = cam->GetCameraFar(); + +// float top = tan(90.0*MT_PI/360.0) * m_frustrum.camnear; + float top = m_frustrum.camnear; // for deg = 90º, tan = 1 + + m_frustrum.x1 = -top; + m_frustrum.x2 = top; + m_frustrum.y1 = -top; + m_frustrum.y2 = top; + + m_projmat = m_rasterizer->GetFrustumMatrix( + m_frustrum.x1, m_frustrum.x2, m_frustrum.y1, m_frustrum.y2, m_frustrum.camnear, m_frustrum.camfar); + +} + +void KX_Dome::CalculateCameraOrientation() +{ +/* +Uses 4 cameras for angles up to 180º +Uses 5 cameras for angles up to 250º +Uses 6 cameras for angles up to 360º +*/ + int i; + float deg45 = MT_PI / 4; + MT_Scalar c = cos(deg45); + MT_Scalar s = sin(deg45); + + if (m_angle <= 180 && (m_mode == DOME_FISHEYE + || m_mode == DOME_TRUNCATED_FRONT + || m_mode == DOME_TRUNCATED_REAR)){ + + m_locRot[0] = MT_Matrix3x3( // 90º - Top + c, -s, 0.0, + 0.0,0.0, -1.0, + s, c, 0.0); + + m_locRot[1] = MT_Matrix3x3( // 90º - Bottom + -s, c, 0.0, + 0.0,0.0, 1.0, + s, c, 0.0); + + m_locRot[2] = MT_Matrix3x3( // 45º - Left + c, 0.0, s, + 0, 1.0, 0.0, + -s, 0.0, c); + + m_locRot[3] = MT_Matrix3x3( // 45º - Right + c, 0.0, -s, + 0.0, 1.0, 0.0, + s, 0.0, c); + + } else if (m_mode == DOME_ENVMAP || (m_angle > 180 && (m_mode == DOME_FISHEYE + || m_mode == DOME_TRUNCATED_FRONT + || m_mode == DOME_TRUNCATED_REAR))){ + + m_locRot[0] = MT_Matrix3x3( // 90º - Top + 1.0, 0.0, 0.0, + 0.0, 0.0,-1.0, + 0.0, 1.0, 0.0); + + m_locRot[1] = MT_Matrix3x3( // 90º - Bottom + 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, + 0.0,-1.0, 0.0); + + m_locRot[2] = MT_Matrix3x3( // -90º - Left + 0.0, 0.0, 1.0, + 0.0, 1.0, 0.0, + -1.0, 0.0, 0.0); + + m_locRot[3] = MT_Matrix3x3( // 90º - Right + 0.0, 0.0,-1.0, + 0.0, 1.0, 0.0, + 1.0, 0.0, 0.0); + + m_locRot[4] = MT_Matrix3x3( // 0º - Front + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + + m_locRot[5] = MT_Matrix3x3( // 180º - Back - USED for ENVMAP only + -1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0,-1.0); + + } else if (m_mode == DOME_PANORAM_SPH){ + + m_locRot[0] = MT_Matrix3x3( // Top + c, s, 0.0, + 0.0,0.0, -1.0, + -s, c, 0.0); + + m_locRot[1] = MT_Matrix3x3( // Bottom + c, s, 0.0, + 0.0 ,0.0, 1.0, + s, -c, 0.0); + + m_locRot[2] = MT_Matrix3x3( // 45º - Left + -s, 0.0, c, + 0, 1.0, 0.0, + -c, 0.0, -s); + + m_locRot[3] = MT_Matrix3x3( // 45º - Right + c, 0.0, s, + 0, 1.0, 0.0, + -s, 0.0, c); + + m_locRot[4] = MT_Matrix3x3( // 135º - LeftBack + -s, 0.0, -c, + 0.0, 1.0, 0.0, + c, 0.0, -s); + + m_locRot[5] = MT_Matrix3x3( // 135º - RightBack + c, 0.0, -s, + 0.0, 1.0, 0.0, + s, 0.0, c); + } + + // rotating the camera in horizontal axis + if (m_tilt) + { + float tiltdeg = ((m_tilt % 360) * 2 * MT_PI) / 360; + c = cos(tiltdeg); + s = sin(tiltdeg); + + MT_Matrix3x3 tilt_mat = MT_Matrix3x3( + 1.0, 0.0, 0.0, + 0.0, c, -s, + 0.0, s, c + ); + + for (i =0;i<6;i++) + m_locRot[i] = tilt_mat * m_locRot[i]; + } +} + +void KX_Dome::RotateCamera(KX_Camera* cam, int i) +{ +// I'm not using it, I'm doing inline calls for these commands +// but it's nice to have it here in case I need it + + MT_Matrix3x3 camori = cam->GetSGNode()->GetLocalOrientation(); + + cam->NodeSetLocalOrientation(camori*m_locRot[i]); + cam->NodeUpdateGS(0.f); + + MT_Transform camtrans(cam->GetWorldToCamera()); + MT_Matrix4x4 viewmat(camtrans); + m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective); + cam->SetModelviewMatrix(viewmat); + + // restore the original orientation + cam->NodeSetLocalOrientation(camori); + cam->NodeUpdateGS(0.f); +} + +void KX_Dome::Draw(void) +{ + + if (fboSupported){ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, warp.fboId); + + glViewport(0,0,warp.imagesize, warp.imagesize); + glScissor(0,0,warp.imagesize, warp.imagesize); + } + + switch(m_mode){ + case DOME_FISHEYE: + DrawDomeFisheye(); + break; + case DOME_ENVMAP: + DrawEnvMap(); + break; + case DOME_PANORAM_SPH: + DrawPanorama(); + break; + case DOME_TRUNCATED_FRONT: + DrawDomeFisheye(); + break; + case DOME_TRUNCATED_REAR: + DrawDomeFisheye(); + break; + } + + if(warp.usemesh) + { + if(fboSupported) + { + m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight()); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + else + { + glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_viewport.GetLeft(), m_viewport.GetBottom(), warp.bufferwidth, warp.bufferheight); + } + DrawDomeWarped(); + } +} + +void KX_Dome::DrawEnvMap(void) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + // Making the viewport always square + + int can_width = m_viewport.GetRight(); + int can_height = m_viewport.GetTop(); + + float ortho_width, ortho_height; + + if (warp.usemesh) + glOrtho((-1.0), 1.0, (-0.66), 0.66, -20.0, 10.0); //stretch the image to reduce resolution lost + + else { + if (can_width/3 <= can_height/2){ + ortho_width = 1.0; + ortho_height = (float)can_height/can_width; + }else{ + ortho_height = 2.0f / 3; + ortho_width = (float)can_width/can_height * ortho_height; + } + + glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0); + } + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(0.0,0.0,1.0, 0.0,0.0,0.0, 0.0,1.0,0.0); + + glPolygonMode(GL_FRONT, GL_FILL); + glShadeModel(GL_SMOOTH); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + + glEnable(GL_TEXTURE_2D); + glColor3f(1.0,1.0,1.0); + + float uv_ratio = (float)(m_buffersize-1) / m_imagesize; + double onebythree = 1.0f / 3; + + // domefacesId[0] => (top) + glBindTexture(GL_TEXTURE_2D, domefacesId[0]); + glBegin(GL_QUADS); + glTexCoord2f(uv_ratio,uv_ratio); + glVertex3f( onebythree, 0.0f, 3.0f); + glTexCoord2f(0.0,uv_ratio); + glVertex3f(-onebythree, 0.0f, 3.0f); + glTexCoord2f(0.0,0.0); + glVertex3f(-onebythree,-2 * onebythree, 3.0f); + glTexCoord2f(uv_ratio,0.0); + glVertex3f(onebythree,-2 * onebythree, 3.0f); + glEnd(); + + // domefacesId[1] => (bottom) + glBindTexture(GL_TEXTURE_2D, domefacesId[1]); + glBegin(GL_QUADS); + glTexCoord2f(uv_ratio,uv_ratio); + glVertex3f(-onebythree, 0.0f, 3.0f); + glTexCoord2f(0.0,uv_ratio); + glVertex3f(-1.0f, 0.0f, 3.0f); + glTexCoord2f(0.0,0.0); + glVertex3f(-1.0f,-2 * onebythree, 3.0f); + glTexCoord2f(uv_ratio,0.0); + glVertex3f(-onebythree,-2 * onebythree, 3.0f); + glEnd(); + + // domefacesId[2] => -90º (left) + glBindTexture(GL_TEXTURE_2D, domefacesId[2]); + glBegin(GL_QUADS); + glTexCoord2f(uv_ratio,uv_ratio); + glVertex3f(-onebythree, 2 * onebythree, 3.0f); + glTexCoord2f(0.0,uv_ratio); + glVertex3f(-1.0f, 2 * onebythree, 3.0f); + glTexCoord2f(0.0,0.0); + glVertex3f(-1.0f, 0.0f, 3.0f); + glTexCoord2f(uv_ratio,0.0); + glVertex3f(-onebythree, 0.0f, 3.0f); + glEnd(); + + // domefacesId[3] => 90º (right) + glBindTexture(GL_TEXTURE_2D, domefacesId[3]); + glBegin(GL_QUADS); + glTexCoord2f(uv_ratio,uv_ratio); + glVertex3f( 1.0f, 2 * onebythree, 3.0f); + glTexCoord2f(0.0,uv_ratio); + glVertex3f( onebythree, 2 * onebythree, 3.0f); + glTexCoord2f(0.0,0.0); + glVertex3f( onebythree, 0.0f, 3.0f); + glTexCoord2f(uv_ratio,0.0); + glVertex3f(1.0f, 0.0f, 3.0f); + glEnd(); + + // domefacesId[4] => 0º (front) + glBindTexture(GL_TEXTURE_2D, domefacesId[4]); + glBegin(GL_QUADS); + glTexCoord2f(uv_ratio,uv_ratio); + glVertex3f( 1.0f, 0.0f, 3.0f); + glTexCoord2f(0.0,uv_ratio); + glVertex3f( onebythree, 0.0f, 3.0f); + glTexCoord2f(0.0,0.0); + glVertex3f( onebythree,-2 * onebythree, 3.0f); + glTexCoord2f(uv_ratio,0.0); + glVertex3f(1.0f, -2 * onebythree, 3.0f); + glEnd(); + + // domefacesId[5] => 180º (back) + glBindTexture(GL_TEXTURE_2D, domefacesId[5]); + glBegin(GL_QUADS); + glTexCoord2f(uv_ratio,uv_ratio); + glVertex3f( onebythree, 2 * onebythree, 3.0f); + glTexCoord2f(0.0,uv_ratio); + glVertex3f(-onebythree, 2 * onebythree, 3.0f); + glTexCoord2f(0.0,0.0); + glVertex3f(-onebythree, 0.0f, 3.0f); + glTexCoord2f(uv_ratio,0.0); + glVertex3f(onebythree, 0.0f, 3.0f); + glEnd(); + + glDisable(GL_TEXTURE_2D); + glEnable(GL_DEPTH_TEST); +} + +void KX_Dome::DrawDomeFisheye(void) +{ + int i; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + // Making the viewport always square + + int can_width = m_viewport.GetRight(); + int can_height = m_viewport.GetTop(); + + float ortho_width, ortho_height; + + if(m_mode == DOME_FISHEYE) { + if (warp.usemesh) + glOrtho((-1.0), 1.0, (-1.0), 1.0, -20.0, 10.0); //stretch the image to reduce resolution lost + + else { + if (can_width < can_height){ + ortho_width = 1.0; + ortho_height = (float)can_height/can_width; + }else{ + ortho_width = (float)can_width/can_height; + ortho_height = 1.0; + } + + glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0); + } + } + else if(m_mode == DOME_TRUNCATED_FRONT) + { + ortho_width = 1.0; + ortho_height = 2 * ((float)can_height/can_width) - 1.0 ; + + glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_width, -20.0, 10.0); + } + else { //m_mode == DOME_TRUNCATED_REAR + ortho_width = 1.0; + ortho_height = 2 * ((float)can_height/can_width) - 1.0 ; + + glOrtho((-ortho_width), ortho_width, (-ortho_width), ortho_height, -20.0, 10.0); + } + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(0.0,-1.0,0.0, 0.0,0.0,0.0, 0.0,0.0,1.0); + + if(m_drawingmode == RAS_IRasterizer::KX_WIREFRAME) + glPolygonMode(GL_FRONT, GL_LINE); + else + glPolygonMode(GL_FRONT, GL_FILL); + + glShadeModel(GL_SMOOTH); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + + glEnable(GL_TEXTURE_2D); + glColor3f(1.0,1.0,1.0); + + if (dlistSupported){ + for(i=0;i<m_numfaces;i++){ + glBindTexture(GL_TEXTURE_2D, domefacesId[i]); + glCallList(dlistId+i); + } + } + else { // DisplayLists not supported + // top triangle + glBindTexture(GL_TEXTURE_2D, domefacesId[0]); + GLDrawTriangles(cubetop, nfacestop); + + // bottom triangle + glBindTexture(GL_TEXTURE_2D, domefacesId[1]); + GLDrawTriangles(cubebottom, nfacesbottom); + + // left triangle + glBindTexture(GL_TEXTURE_2D, domefacesId[2]); + GLDrawTriangles(cubeleft, nfacesleft); + + // right triangle + glBindTexture(GL_TEXTURE_2D, domefacesId[3]); + GLDrawTriangles(cuberight, nfacesright); + + if (m_angle > 180){ + // front triangle + glBindTexture(GL_TEXTURE_2D, domefacesId[4]); + GLDrawTriangles(cubefront, nfacesfront); + } + } + glDisable(GL_TEXTURE_2D); + glEnable(GL_DEPTH_TEST); +} + +void KX_Dome::DrawPanorama(void) +{ + int i; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + // Making the viewport always square + + int can_width = m_viewport.GetRight(); + int can_height = m_viewport.GetTop(); + + float ortho_height = 1.0; + float ortho_width = 1.0; + + if (warp.usemesh) + glOrtho((-1.0), 1.0, (-0.5), 0.5, -20.0, 10.0); //stretch the image to reduce resolution lost + + else { + //using all the screen + if ((can_width / 2) <= (can_height)){ + ortho_width = 1.0; + ortho_height = (float)can_height/can_width; + }else{ + ortho_width = (float)can_width/can_height * 0.5; + ortho_height = 0.5; + } + + glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0); + } + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(0.0,-1.0,0.0, 0.0,0.0,0.0, 0.0,0.0,1.0); + + if(m_drawingmode == RAS_IRasterizer::KX_WIREFRAME) + glPolygonMode(GL_FRONT, GL_LINE); + else + glPolygonMode(GL_FRONT, GL_FILL); + + glShadeModel(GL_SMOOTH); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + + glEnable(GL_TEXTURE_2D); + glColor3f(1.0,1.0,1.0); + + if (dlistSupported){ + for(i=0;i<m_numfaces;i++){ + glBindTexture(GL_TEXTURE_2D, domefacesId[i]); + glCallList(dlistId+i); + } + } + else { + // domefacesId[4] => (top) + glBindTexture(GL_TEXTURE_2D, domefacesId[0]); + GLDrawTriangles(cubetop, nfacestop); + + // domefacesId[5] => (bottom) + glBindTexture(GL_TEXTURE_2D, domefacesId[1]); + GLDrawTriangles(cubebottom, nfacesbottom); + + // domefacesId[1] => -45º (left) + glBindTexture(GL_TEXTURE_2D, domefacesId[2]); + GLDrawTriangles(cubeleft, nfacesleft); + + // domefacesId[2] => 45º (right) + glBindTexture(GL_TEXTURE_2D, domefacesId[3]); + GLDrawTriangles(cuberight, nfacesright); + + // domefacesId[0] => -135º (leftback) + glBindTexture(GL_TEXTURE_2D, domefacesId[4]); + GLDrawTriangles(cubeleftback, nfacesleftback); + + // domefacesId[3] => 135º (rightback) + glBindTexture(GL_TEXTURE_2D, domefacesId[5]); + GLDrawTriangles(cuberightback, nfacesrightback); + } + glDisable(GL_TEXTURE_2D); + glEnable(GL_DEPTH_TEST); +} + +void KX_Dome::DrawDomeWarped(void) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + // Making the viewport always square + int can_width = m_viewport.GetRight(); + int can_height = m_viewport.GetTop(); + + double screen_ratio = can_width/ (double) can_height; + + glOrtho(-screen_ratio,screen_ratio,-1.0,1.0,-20.0,10.0); + + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(0.0, 0.0, 1.0, 0.0,0.0,0.0, 0.0,1.0,0.0); + + if(m_drawingmode == RAS_IRasterizer::KX_WIREFRAME) + glPolygonMode(GL_FRONT, GL_LINE); + else + glPolygonMode(GL_FRONT, GL_FILL); + + glShadeModel(GL_SMOOTH); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + + glEnable(GL_TEXTURE_2D); + glColor3f(1.0,1.0,1.0); + + if (dlistSupported){ + glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]); + glCallList(dlistId + m_numfaces); + } + else{ + glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]); + GLDrawWarpQuads(); + } + glDisable(GL_TEXTURE_2D); + glEnable(GL_DEPTH_TEST); +} + +void KX_Dome::BindImages(int i) +{ + glBindTexture(GL_TEXTURE_2D, domefacesId[i]); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_viewport.GetLeft(), m_viewport.GetBottom(), m_buffersize, m_buffersize); +} + +void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i) +{ + if (!cam) + return; + + m_canvas->SetViewPort(0,0,m_buffersize-1,m_buffersize-1); + +// m_rasterizer->SetAmbient(); + m_rasterizer->DisplayFog(); + + CalculateFrustum(cam); //calculates m_projmat + cam->SetProjectionMatrix(m_projmat); + m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix()); +// Dome_RotateCamera(cam,i); + + MT_Matrix3x3 camori = cam->GetSGNode()->GetLocalOrientation(); + + cam->NodeSetLocalOrientation(camori*m_locRot[i]); + cam->NodeUpdateGS(0.f); + + MT_Transform camtrans(cam->GetWorldToCamera()); + MT_Matrix4x4 viewmat(camtrans); + m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), 1.0); + cam->SetModelviewMatrix(viewmat); + + scene->CalculateVisibleMeshes(m_rasterizer,cam); + scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools); + + // restore the original orientation + cam->NodeSetLocalOrientation(camori); + cam->NodeUpdateGS(0.f); +} + diff --git a/source/gameengine/Ketsji/KX_Dome.h b/source/gameengine/Ketsji/KX_Dome.h new file mode 100644 index 00000000000..9ff33fe2852 --- /dev/null +++ b/source/gameengine/Ketsji/KX_Dome.h @@ -0,0 +1,197 @@ +/* $Id$ +----------------------------------------------------------------------------- + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. + +Contributor(s): Dalai Felinto + +This source uses some of the ideas and code from Paul Bourke. +Developed as part of a Research and Development project for SAT - La Soci�t� des arts technologiques. +----------------------------------------------------------------------------- +*/ + +#if !defined KX_DOME_H +#define KX_DOME_H + +#include "KX_Scene.h" +#include "KX_Camera.h" +#include "DNA_screen_types.h" +#include "RAS_ICanvas.h" +#include "RAS_IRasterizer.h" +#include "RAS_IRenderTools.h" +#include "KX_KetsjiEngine.h" + +#include "GL/glew.h" +#include <vector> + +#include "MEM_guardedalloc.h" +#include "BKE_text.h" + +//Dome modes: limit hardcoded in buttons_scene.c +#define DOME_FISHEYE 1 +#define DOME_TRUNCATED_FRONT 2 +#define DOME_TRUNCATED_REAR 3 +#define DOME_ENVMAP 4 +#define DOME_PANORAM_SPH 5 +#define DOME_NUM_MODES 6 + + +/// class for render 3d scene +class KX_Dome +{ +public: + /// constructor + KX_Dome ( + RAS_ICanvas* m_canvas, + /// rasterizer + RAS_IRasterizer* m_rasterizer, + /// render tools + RAS_IRenderTools* m_rendertools, + /// engine + KX_KetsjiEngine* m_engine, + + short res, + short mode, + short angle, + float resbuf, + short tilt, + struct Text* warptext + ); + + /// destructor + virtual ~KX_Dome (void); + + //openGL checks: + bool dlistSupported; + bool fboSupported; + + //openGL names: + GLuint domefacesId[7]; // ID of the images -- room for 7 images, using only 4 for 180� x 360� dome, 6 for panoramic and +1 for warp mesh + GLuint dlistId; // ID of the Display Lists of the images (used as an offset) + + typedef struct { + double u[3], v[3]; + MT_Vector3 verts[3]; //three verts + } DomeFace; + + //mesh warp functions + typedef struct { + double x, y, u, v, i; + } WarpMeshNode; + + struct { + bool usemesh; + int mode; + int n_width, n_height; //nodes width and height + int imagesize; + int bufferwidth, bufferheight; + GLuint fboId; + vector <vector <WarpMeshNode> > nodes; + } warp; + + bool ParseWarpMesh(STR_String text); + + vector <DomeFace> cubetop, cubebottom, cuberight, cubeleft, cubefront, cubeback; //for fisheye + vector <DomeFace> cubeleftback, cuberightback; //for panorama + + int nfacestop, nfacesbottom, nfacesleft, nfacesright, nfacesfront, nfacesback; + int nfacesleftback, nfacesrightback; + + int GetNumberRenders(){return m_numfaces;}; + + void RenderDome(void); + void RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i); + void BindImages(int i); + + void SetViewPort(GLuint viewport[4]); + void CalculateFrustum(KX_Camera* cam); + void RotateCamera(KX_Camera* cam, int i); + + //Mesh creation Functions + void CreateMeshDome180(void); + void CreateMeshDome250(void); + void CreateMeshPanorama(void); + + void SplitFace(vector <DomeFace>& face, int *nfaces); + + void FlattenDome(MT_Vector3 verts[3]); + void FlattenPanorama(MT_Vector3 verts[3]); + + //Draw functions + void GLDrawTriangles(vector <DomeFace>& face, int nfaces); + void GLDrawWarpQuads(void); + void Draw(void); + void DrawDomeFisheye(void); + void DrawEnvMap(void); + void DrawPanorama(void); + void DrawDomeWarped(void); + + //setting up openGL + void CreateGLImages(void); + void ClearGLImages(void);//called on resize + bool CreateDL(void); //create Display Lists + void ClearDL(void); //remove Display Lists + bool CreateFBO(void);//create FBO (for warp mesh) + void ClearFBO(void); //remove FBO + + void CalculateCameraOrientation(); + void CalculateImageSize(); //set m_imagesize + + int canvaswidth; + int canvasheight; + +protected: + int m_drawingmode; + + int m_imagesize; + int m_buffersize; // canvas small dimension + int m_numfaces; // 4 to 6 depending on the kind of dome image + int m_numimages; //numfaces +1 if we have warp mesh + + short m_resolution; //resolution to tesselate the mesh + short m_mode; // the mode (truncated, warped, panoramic,...) + short m_angle; //the angle of the fisheye + float m_radangle; //the angle of the fisheye in radians + float m_resbuffer; //the resolution of the buffer + short m_tilt; //the dome tilt (camera rotation on horizontal axis) + + RAS_Rect m_viewport; + + MT_Matrix4x4 m_projmat; + + MT_Matrix3x3 m_locRot [6];// the rotation matrix + + /// rendered scene + KX_Scene * m_scene; + + /// canvas + RAS_ICanvas* m_canvas; + /// rasterizer + RAS_IRasterizer* m_rasterizer; + /// render tools + RAS_IRenderTools* m_rendertools; + /// engine + KX_KetsjiEngine* m_engine; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_Dome"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif + diff --git a/source/gameengine/Ketsji/KX_EmptyObject.h b/source/gameengine/Ketsji/KX_EmptyObject.h index 62aa7fcd017..fa405e20076 100644 --- a/source/gameengine/Ketsji/KX_EmptyObject.h +++ b/source/gameengine/Ketsji/KX_EmptyObject.h @@ -37,7 +37,13 @@ public: KX_GameObject(sgReplicationInfo,callbacks) {}; virtual ~KX_EmptyObject(); - + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_EmptyObject"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_EMPTYOBJECT diff --git a/source/gameengine/Ketsji/KX_GameActuator.cpp b/source/gameengine/Ketsji/KX_GameActuator.cpp index 76459e46731..42dc4d8fd24 100644 --- a/source/gameengine/Ketsji/KX_GameActuator.cpp +++ b/source/gameengine/Ketsji/KX_GameActuator.cpp @@ -49,9 +49,8 @@ KX_GameActuator::KX_GameActuator(SCA_IObject *gameobj, const STR_String& filename, const STR_String& loadinganimationname, KX_Scene* scene, - KX_KetsjiEngine* ketsjiengine, - PyTypeObject* T) - : SCA_IActuator(gameobj, T) + KX_KetsjiEngine* ketsjiengine) + : SCA_IActuator(gameobj) { m_mode = mode; m_filename = filename; @@ -73,8 +72,6 @@ CValue* KX_GameActuator::GetReplica() { KX_GameActuator* replica = new KX_GameActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; } @@ -132,7 +129,7 @@ bool KX_GameActuator::Update() { char mashal_path[512]; char *marshal_buffer = NULL; - int marshal_length; + unsigned int marshal_length; FILE *fp = NULL; pathGamePythonConfig(mashal_path); @@ -151,6 +148,8 @@ bool KX_GameActuator::Update() } else { printf("Warning: could not create marshal buffer\n"); } + if (marshal_buffer) + delete [] marshal_buffer; } break; } @@ -208,77 +207,34 @@ bool KX_GameActuator::Update() /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_GameActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_GameActuator", - sizeof(KX_GameActuator), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 + PyVarObject_HEAD_INIT(NULL, 0) + "KX_GameActuator", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_IActuator::Type, + 0,0,0,0,0,0, + py_base_new }; - - -PyParentObject KX_GameActuator::Parents[] = -{ - &KX_GameActuator::Type, - &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL -}; - - - PyMethodDef KX_GameActuator::Methods[] = { - {"getFile", (PyCFunction) KX_GameActuator::sPyGetFile, METH_VARARGS, (PY_METHODCHAR)GetFile_doc}, - {"setFile", (PyCFunction) KX_GameActuator::sPySetFile, METH_VARARGS, (PY_METHODCHAR)SetFile_doc}, {NULL,NULL} //Sentinel }; -/* getFile */ -const char KX_GameActuator::GetFile_doc[] = -"getFile()\n" -"get the name of the file to start.\n"; -PyObject* KX_GameActuator::PyGetFile(PyObject* self, PyObject* args, PyObject* kwds) -{ - return PyString_FromString(m_filename); -} - -/* setFile */ -const char KX_GameActuator::SetFile_doc[] = -"setFile(name)\n" -"set the name of the file to start.\n"; -PyObject* KX_GameActuator::PySetFile(PyObject* self, PyObject* args, PyObject* kwds) -{ - char* new_file; - - if (!PyArg_ParseTuple(args, "s", &new_file)) - { - return NULL; - } - - m_filename = STR_String(new_file); - - Py_Return; - -} - - - -PyObject* KX_GameActuator::_getattr(const STR_String& attr) -{ - _getattr_up(SCA_IActuator); -} - - +PyAttributeDef KX_GameActuator::Attributes[] = { + KX_PYATTRIBUTE_STRING_RW("fileName",0,100,false,KX_GameActuator,m_filename), + KX_PYATTRIBUTE_INT_RW("mode", KX_GAME_NODEF+1, KX_GAME_MAX-1, true, KX_GameActuator, m_mode), + { NULL } //Sentinel +}; diff --git a/source/gameengine/Ketsji/KX_GameActuator.h b/source/gameengine/Ketsji/KX_GameActuator.h index bb3448995dc..37d09a5a9fb 100644 --- a/source/gameengine/Ketsji/KX_GameActuator.h +++ b/source/gameengine/Ketsji/KX_GameActuator.h @@ -65,8 +65,7 @@ protected: const STR_String& filename, const STR_String& loadinganimationname, KX_Scene* scene, - KX_KetsjiEngine* ketsjiEngine, - PyTypeObject* T=&Type); + KX_KetsjiEngine* ketsjiEngine); virtual ~KX_GameActuator(); virtual CValue* GetReplica(); @@ -76,10 +75,6 @@ protected: /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - KX_PYMETHOD_DOC(KX_GameActuator,GetFile); - KX_PYMETHOD_DOC(KX_GameActuator,SetFile); }; /* end of class KX_GameActuator */ diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 739c122a5ef..8193aa8c37b 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -49,12 +49,15 @@ typedef unsigned long uint_ptr; #include "RAS_IPolygonMaterial.h" #include "KX_BlenderMaterial.h" #include "KX_GameObject.h" +#include "KX_Camera.h" // only for their ::Type +#include "KX_Light.h" // only for their ::Type #include "RAS_MeshObject.h" #include "KX_MeshProxy.h" #include "KX_PolyProxy.h" #include <stdio.h> // printf #include "SG_Controller.h" #include "KX_IPhysicsController.h" +#include "PHY_IGraphicController.h" #include "SG_Node.h" #include "SG_Controller.h" #include "KX_ClientObjectInfo.h" @@ -62,8 +65,12 @@ typedef unsigned long uint_ptr; #include "KX_RayCast.h" #include "KX_PythonInit.h" #include "KX_PyMath.h" +#include "KX_PythonSeq.h" +#include "KX_ConvertPhysicsObject.h" #include "SCA_IActuator.h" #include "SCA_ISensor.h" +#include "SCA_IController.h" +#include "NG_NetworkScene.h" //Needed for sendMessage() #include "PyObjectPlus.h" /* python stuff */ @@ -72,12 +79,16 @@ typedef unsigned long uint_ptr; #include "KX_SG_NodeRelationships.h" +static MT_Point3 dummy_point= MT_Point3(0.0, 0.0, 0.0); +static MT_Vector3 dummy_scaling = MT_Vector3(1.0, 1.0, 1.0); +static MT_Matrix3x3 dummy_orientation = MT_Matrix3x3( 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + KX_GameObject::KX_GameObject( void* sgReplicationInfo, - SG_Callbacks callbacks, - PyTypeObject* T -) : - SCA_IObject(T), + SG_Callbacks callbacks) + : SCA_IObject(), m_bDyna(false), m_layer(0), m_pBlenderObject(NULL), @@ -87,11 +98,13 @@ KX_GameObject::KX_GameObject( m_bIsNegativeScaling(false), m_bVisible(true), m_bCulled(true), + m_bOccluder(false), m_pPhysicsController1(NULL), - m_pPhysicsEnvironment(NULL), + m_pGraphicController(NULL), m_xray(false), m_pHitObject(NULL), - m_isDeformable(false) + m_isDeformable(false), + m_attr_dict(NULL) { m_ignore_activity_culling = false; m_pClient_info = new KX_ClientObjectInfo(this, KX_ClientObjectInfo::ACTOR); @@ -129,9 +142,23 @@ KX_GameObject::~KX_GameObject() } m_pSGNode->SetSGClientObject(NULL); } + if (m_pGraphicController) + { + delete m_pGraphicController; + } + + if (m_attr_dict) { + PyDict_Clear(m_attr_dict); /* incase of circular refs or other weired cases */ + Py_DECREF(m_attr_dict); + } } - +KX_GameObject* KX_GameObject::GetClientObject(KX_ClientObjectInfo* info) +{ + if (!info) + return NULL; + return info->m_gameobject; +} CValue* KX_GameObject:: Calc(VALUE_OPERATOR op, CValue *val) { @@ -154,45 +181,30 @@ const STR_String & KX_GameObject::GetText() -float KX_GameObject::GetNumber() +double KX_GameObject::GetNumber() { return 0; } -STR_String KX_GameObject::GetName() +STR_String& KX_GameObject::GetName() { return m_name; } -void KX_GameObject::SetName(STR_String name) +void KX_GameObject::SetName(const char *name) { m_name = name; }; // Set the name of the value - - -void KX_GameObject::ReplicaSetName(STR_String name) -{ -} - - - - - - KX_IPhysicsController* KX_GameObject::GetPhysicsController() { return m_pPhysicsController1; } - - - - KX_GameObject* KX_GameObject::GetParent() { KX_GameObject* result = NULL; @@ -212,7 +224,7 @@ KX_GameObject* KX_GameObject::GetParent() } -void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj) +void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj, bool addToCompound, bool ghost) { // check on valid node in case a python controller holds a reference to a deleted object if (obj && GetSGNode() && obj->GetSGNode() && GetSGNode()->GetSGParent() != obj->GetSGNode()) @@ -233,7 +245,7 @@ void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj) if (m_pPhysicsController1) { - m_pPhysicsController1->SuspendDynamics(true); + m_pPhysicsController1->SuspendDynamics(ghost); } // Set us to our new scale, position, and orientation scale2[0] = 1.0/scale2[0]; @@ -246,12 +258,27 @@ void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj) NodeSetLocalScale(scale1); NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2])); NodeSetLocalOrientation(invori*NodeGetWorldOrientation()); - NodeUpdateGS(0.f,true); + NodeUpdateGS(0.f); // object will now be a child, it must be removed from the parent list CListValue* rootlist = scene->GetRootParentList(); if (rootlist->RemoveValue(this)) // the object was in parent list, decrement ref count as it's now removed Release(); + // if the new parent is a compound object, add this object shape to the compound shape. + // step 0: verify this object has physical controller + if (m_pPhysicsController1 && addToCompound) + { + // step 1: find the top parent (not necessarily obj) + KX_GameObject* rootobj = (KX_GameObject*)obj->GetSGNode()->GetRootSGParent()->GetSGClientObject(); + // step 2: verify it has a physical controller and compound shape + if (rootobj != NULL && + rootobj->m_pPhysicsController1 != NULL && + rootobj->m_pPhysicsController1->IsCompound()) + { + rootobj->m_pPhysicsController1->AddCompoundChild(m_pPhysicsController1); + } + } + // graphically, the object hasn't change place, no need to update m_pGraphicController } } @@ -260,6 +287,8 @@ void KX_GameObject::RemoveParent(KX_Scene *scene) // check on valid node in case a python controller holds a reference to a deleted object if (GetSGNode() && GetSGNode()->GetSGParent()) { + // get the root object to remove us from compound object if needed + KX_GameObject* rootobj = (KX_GameObject*)GetSGNode()->GetRootSGParent()->GetSGClientObject(); // Set us to the right spot GetSGNode()->SetLocalScale(GetSGNode()->GetWorldScaling()); GetSGNode()->SetLocalOrientation(GetSGNode()->GetWorldOrientation()); @@ -267,7 +296,7 @@ void KX_GameObject::RemoveParent(KX_Scene *scene) // Remove us from our parent GetSGNode()->DisconnectFromParent(); - NodeUpdateGS(0.f,true); + NodeUpdateGS(0.f); // the object is now a root object, add it to the parentlist CListValue* rootlist = scene->GetRootParentList(); if (!rootlist->SearchValue(this)) @@ -275,29 +304,83 @@ void KX_GameObject::RemoveParent(KX_Scene *scene) rootlist->Add(AddRef()); if (m_pPhysicsController1) { + // in case this controller was added as a child shape to the parent + if (rootobj != NULL && + rootobj->m_pPhysicsController1 != NULL && + rootobj->m_pPhysicsController1->IsCompound()) + { + rootobj->m_pPhysicsController1->RemoveCompoundChild(m_pPhysicsController1); + } m_pPhysicsController1->RestoreDynamics(); + if (m_pPhysicsController1->IsDyna() && rootobj->m_pPhysicsController1) + { + // dynamic object should remember the velocity they had while being parented + MT_Point3 childPoint = GetSGNode()->GetWorldPosition(); + MT_Point3 rootPoint = rootobj->GetSGNode()->GetWorldPosition(); + MT_Point3 relPoint; + relPoint = (childPoint-rootPoint); + MT_Vector3 linVel = rootobj->m_pPhysicsController1->GetVelocity(relPoint); + MT_Vector3 angVel = rootobj->m_pPhysicsController1->GetAngularVelocity(); + m_pPhysicsController1->SetLinearVelocity(linVel, false); + m_pPhysicsController1->SetAngularVelocity(angVel, false); + } } + // graphically, the object hasn't change place, no need to update m_pGraphicController } } -void KX_GameObject::ProcessReplica(KX_GameObject* replica) +void KX_GameObject::ProcessReplica() +{ + SCA_IObject::ProcessReplica(); + + m_pPhysicsController1 = NULL; + m_pGraphicController = NULL; + m_pSGNode = NULL; + m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info); + m_pClient_info->m_gameobject = this; + m_state = 0; + if(m_attr_dict) + m_attr_dict= PyDict_Copy(m_attr_dict); + +} + +static void setGraphicController_recursive(SG_Node* node) { - replica->m_pPhysicsController1 = NULL; - replica->m_pSGNode = NULL; - replica->m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info); - replica->m_pClient_info->m_gameobject = replica; - replica->m_state = 0; + NodeList& children = node->GetSGChildren(); + + for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) + { + SG_Node* childnode = (*childit); + KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); + if (clientgameobj != NULL) // This is a GameObject + clientgameobj->ActivateGraphicController(false); + + // if the childobj is NULL then this may be an inverse parent link + // so a non recursive search should still look down this node. + setGraphicController_recursive(childnode); + } } +void KX_GameObject::ActivateGraphicController(bool recurse) +{ + if (m_pGraphicController) + { + m_pGraphicController->Activate(m_bVisible); + } + if (recurse) + { + setGraphicController_recursive(GetSGNode()); + } +} + CValue* KX_GameObject::GetReplica() { KX_GameObject* replica = new KX_GameObject(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); - ProcessReplica(replica); + replica->ProcessReplica(); return replica; } @@ -322,11 +405,14 @@ void KX_GameObject::ApplyTorque(const MT_Vector3& torque,bool local) void KX_GameObject::ApplyMovement(const MT_Vector3& dloc,bool local) { - if (m_pPhysicsController1) // (IsDynamic()) + if (GetSGNode()) { - m_pPhysicsController1->RelativeTranslate(dloc,local); + if (m_pPhysicsController1) // (IsDynamic()) + { + m_pPhysicsController1->RelativeTranslate(dloc,local); + } + GetSGNode()->RelativeTranslate(dloc,GetSGNode()->GetSGParent(),local); } - GetSGNode()->RelativeTranslate(dloc,GetSGNode()->GetSGParent(),local); } @@ -334,11 +420,13 @@ void KX_GameObject::ApplyMovement(const MT_Vector3& dloc,bool local) void KX_GameObject::ApplyRotation(const MT_Vector3& drot,bool local) { MT_Matrix3x3 rotmat(drot); + + if (GetSGNode()) { + GetSGNode()->RelativeRotate(rotmat,local); - GetSGNode()->RelativeRotate(rotmat,local); - - if (m_pPhysicsController1) { // (IsDynamic()) - m_pPhysicsController1->RelativeRotate(rotmat,local); + if (m_pPhysicsController1) { // (IsDynamic()) + m_pPhysicsController1->RelativeRotate(rotmat,local); + } } } @@ -351,24 +439,36 @@ double* KX_GameObject::GetOpenGLMatrix() { // todo: optimize and only update if necessary double* fl = m_OpenGL_4x4Matrix.getPointer(); - MT_Transform trans; + if (GetSGNode()) { + MT_Transform trans; - trans.setOrigin(GetSGNode()->GetWorldPosition()); - trans.setBasis(GetSGNode()->GetWorldOrientation()); + trans.setOrigin(GetSGNode()->GetWorldPosition()); + trans.setBasis(GetSGNode()->GetWorldOrientation()); - MT_Vector3 scaling = GetSGNode()->GetWorldScaling(); - m_bIsNegativeScaling = ((scaling[0] < 0.0) ^ (scaling[1] < 0.0) ^ (scaling[2] < 0.0)) ? true : false; - trans.scale(scaling[0], scaling[1], scaling[2]); - trans.getValue(fl); - + MT_Vector3 scaling = GetSGNode()->GetWorldScaling(); + m_bIsNegativeScaling = ((scaling[0] < 0.0) ^ (scaling[1] < 0.0) ^ (scaling[2] < 0.0)) ? true : false; + trans.scale(scaling[0], scaling[1], scaling[2]); + trans.getValue(fl); + GetSGNode()->ClearDirty(); + } return fl; } void KX_GameObject::AddMeshUser() { for (size_t i=0;i<m_meshes.size();i++) - m_meshes[i]->AddMeshUser(this); - + { + m_meshes[i]->AddMeshUser(this, &m_meshSlots, GetDeformer()); + } + // set the part of the mesh slot that never change + double* fl = GetOpenGLMatrixPtr()->getPointer(); + + SG_QList::iterator<RAS_MeshSlot> mit(m_meshSlots); +// RAS_MeshSlot* ms; + for(mit.begin(); !mit.end(); ++mit) + { + (*mit)->m_OpenGLMatrix = fl; + } UpdateBuckets(false); } @@ -391,13 +491,32 @@ static void UpdateBuckets_recursive(SG_Node* node) void KX_GameObject::UpdateBuckets( bool recursive ) { - double* fl = GetOpenGLMatrix(); + if (GetSGNode()) { + RAS_MeshSlot *ms; - for (size_t i=0;i<m_meshes.size();i++) - m_meshes[i]->UpdateBuckets(this, fl, m_bUseObjectColor, m_objectColor, m_bVisible, m_bCulled); + if (GetSGNode()->IsDirty()) + GetOpenGLMatrix(); + + SG_QList::iterator<RAS_MeshSlot> mit(m_meshSlots); + for(mit.begin(); !mit.end(); ++mit) + { + ms = *mit; + ms->m_bObjectColor = m_bUseObjectColor; + ms->m_RGBAcolor = m_objectColor; + ms->m_bVisible = m_bVisible; + ms->m_bCulled = m_bCulled || !m_bVisible; + if (!ms->m_bCulled) + ms->m_bucket->ActivateMesh(ms); + + /* split if necessary */ +#ifdef USE_SPLIT + ms->Split(); +#endif + } - if (recursive) { - UpdateBuckets_recursive(m_pSGNode); + if (recursive) { + UpdateBuckets_recursive(GetSGNode()); + } } } @@ -411,27 +530,37 @@ void KX_GameObject::RemoveMeshes() m_meshes.clear(); } - - -void KX_GameObject::UpdateNonDynas() +void KX_GameObject::UpdateTransform() { - if (m_pPhysicsController1) - { + // HACK: saves function call for dynamic object, they are handled differently + if (m_pPhysicsController1 && !m_pPhysicsController1->IsDyna()) + // Note that for Bullet, this does not even update the transform of static object + // but merely sets there collision flag to "kinematic" because the synchronization is + // done during physics simulation m_pPhysicsController1->SetSumoTransform(true); - } -} + if (m_pGraphicController) + // update the culling tree + m_pGraphicController->SetGraphicTransform(); +} +void KX_GameObject::UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene) +{ + ((KX_GameObject*)gameobj)->UpdateTransform(); +} -void KX_GameObject::UpdateTransform() +void KX_GameObject::SynchronizeTransform() { + // only used for sensor object, do full synchronization as bullet doesn't do it if (m_pPhysicsController1) - m_pPhysicsController1->SetSumoTransform(false); + m_pPhysicsController1->SetTransform(); + if (m_pGraphicController) + m_pGraphicController->SetGraphicTransform(); } -void KX_GameObject::UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene) +void KX_GameObject::SynchronizeTransformFunc(SG_IObject* node, void* gameobj, void* scene) { - ((KX_GameObject*)gameobj)->UpdateTransform(); + ((KX_GameObject*)gameobj)->SynchronizeTransform(); } @@ -498,7 +627,7 @@ KX_GameObject::UpdateMaterialData( { KX_BlenderMaterial *m = static_cast<KX_BlenderMaterial*>(poly); - if (matname_hash == NULL) + if (matname_hash == 0) { m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha); // if mesh has only one material attached to it then use original hack with no need to edit vertices (better performance) @@ -552,28 +681,45 @@ KX_GameObject::SetVisible( bool recursive ) { - m_bVisible = v; - if (recursive) - setVisible_recursive(m_pSGNode, v); + if (GetSGNode()) { + m_bVisible = v; + if (m_pGraphicController) + m_pGraphicController->Activate(m_bVisible); + if (recursive) + setVisible_recursive(GetSGNode(), v); + } } -bool -KX_GameObject::GetCulled( - void - ) +static void setOccluder_recursive(SG_Node* node, bool v) { - return m_bCulled; + NodeList& children = node->GetSGChildren(); + + for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) + { + SG_Node* childnode = (*childit); + KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); + if (clientgameobj != NULL) // This is a GameObject + clientgameobj->SetOccluder(v, false); + + // if the childobj is NULL then this may be an inverse parent link + // so a non recursive search should still look down this node. + setOccluder_recursive(childnode, v); + } } void -KX_GameObject::SetCulled( - bool c +KX_GameObject::SetOccluder( + bool v, + bool recursive ) { - m_bCulled = c; + if (GetSGNode()) { + m_bOccluder = v; + if (recursive) + setOccluder_recursive(GetSGNode(), v); + } } - void KX_GameObject::SetLayer( int l @@ -615,6 +761,7 @@ void KX_GameObject::setAngularVelocity(const MT_Vector3& ang_vel,bool local) m_pPhysicsController1->SetAngularVelocity(ang_vel,local); } + void KX_GameObject::ResolveCombinedVelocities( const MT_Vector3 & lin_vel, const MT_Vector3 & ang_vel, @@ -666,9 +813,9 @@ void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac) switch (axis) { case 0: //x axis - ori = MT_Vector3(orimat[0][2], orimat[1][2], orimat[2][2]); //pivot axis + ori.setValue(orimat[0][2], orimat[1][2], orimat[2][2]); //pivot axis if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON) //is the vector paralell to the pivot? - ori = MT_Vector3(orimat[0][1], orimat[1][1], orimat[2][1]); //change the pivot! + ori.setValue(orimat[0][1], orimat[1][1], orimat[2][1]); //change the pivot! if (fac == 1.0) { x = vect; } else { @@ -681,9 +828,9 @@ void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac) z = x.cross(y); break; case 1: //y axis - ori = MT_Vector3(orimat[0][0], orimat[1][0], orimat[2][0]); + ori.setValue(orimat[0][0], orimat[1][0], orimat[2][0]); if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON) - ori = MT_Vector3(orimat[0][2], orimat[1][2], orimat[2][2]); + ori.setValue(orimat[0][2], orimat[1][2], orimat[2][2]); if (fac == 1.0) { y = vect; } else { @@ -696,9 +843,9 @@ void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac) x = y.cross(z); break; case 2: //z axis - ori = MT_Vector3(orimat[0][1], orimat[1][1], orimat[2][1]); + ori.setValue(orimat[0][1], orimat[1][1], orimat[2][1]); if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON) - ori = MT_Vector3(orimat[0][0], orimat[1][0], orimat[2][0]); + ori.setValue(orimat[0][0], orimat[1][0], orimat[2][0]); if (fac == 1.0) { z = vect; } else { @@ -717,9 +864,9 @@ void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac) x.normalize(); //normalize the vectors y.normalize(); z.normalize(); - orimat = MT_Matrix3x3( x[0],y[0],z[0], - x[1],y[1],z[1], - x[2],y[2],z[2]); + orimat.setValue( x[0],y[0],z[0], + x[1],y[1],z[1], + x[2],y[2],z[2]); if (GetSGNode()->GetSGParent() != NULL) { // the object is a child, adapt its local orientation so that @@ -740,6 +887,16 @@ MT_Scalar KX_GameObject::GetMass() return 0.0; } +MT_Vector3 KX_GameObject::GetLocalInertia() +{ + MT_Vector3 local_inertia(0.0,0.0,0.0); + if (m_pPhysicsController1) + { + local_inertia = m_pPhysicsController1->GetLocalInertia(); + } + return local_inertia; +} + MT_Vector3 KX_GameObject::GetLinearVelocity(bool local) { MT_Vector3 velocity(0.0,0.0,0.0), locvel; @@ -805,6 +962,7 @@ void KX_GameObject::NodeSetLocalPosition(const MT_Point3& trans) } GetSGNode()->SetLocalPosition(trans); + } @@ -823,7 +981,17 @@ void KX_GameObject::NodeSetLocalOrientation(const MT_Matrix3x3& rot) GetSGNode()->SetLocalOrientation(rot); } +void KX_GameObject::NodeSetGlobalOrientation(const MT_Matrix3x3& rot) +{ + // check on valid node in case a python controller holds a reference to a deleted object + if (!GetSGNode()) + return; + if (GetSGNode()->GetSGParent()) + GetSGNode()->SetLocalOrientation(GetSGNode()->GetSGParent()->GetWorldOrientation().inverse()*rot); + else + GetSGNode()->SetLocalOrientation(rot); +} void KX_GameObject::NodeSetLocalScale(const MT_Vector3& scale) { @@ -859,7 +1027,9 @@ void KX_GameObject::NodeSetRelativeScale(const MT_Vector3& scale) void KX_GameObject::NodeSetWorldPosition(const MT_Point3& trans) { - SG_Node* parent = m_pSGNode->GetSGParent(); + if (!GetSGNode()) + return; + SG_Node* parent = GetSGNode()->GetSGParent(); if (parent != NULL) { // Make sure the objects have some scale @@ -884,7 +1054,7 @@ void KX_GameObject::NodeSetWorldPosition(const MT_Point3& trans) } -void KX_GameObject::NodeUpdateGS(double time,bool bInitiator) +void KX_GameObject::NodeUpdateGS(double time) { if (GetSGNode()) GetSGNode()->UpdateWorldData(time); @@ -894,42 +1064,57 @@ void KX_GameObject::NodeUpdateGS(double time,bool bInitiator) const MT_Matrix3x3& KX_GameObject::NodeGetWorldOrientation() const { - static MT_Matrix3x3 defaultOrientation = MT_Matrix3x3( 1.0, 0.0, 0.0, - 0.0, 1.0, 0.0, - 0.0, 0.0, 1.0); - // check on valid node in case a python controller holds a reference to a deleted object if (!GetSGNode()) - return defaultOrientation; + return dummy_orientation; return GetSGNode()->GetWorldOrientation(); } - +const MT_Matrix3x3& KX_GameObject::NodeGetLocalOrientation() const +{ + // check on valid node in case a python controller holds a reference to a deleted object + if (!GetSGNode()) + return dummy_orientation; + return GetSGNode()->GetLocalOrientation(); +} const MT_Vector3& KX_GameObject::NodeGetWorldScaling() const { - static MT_Vector3 defaultScaling = MT_Vector3(1.0, 1.0, 1.0); - // check on valid node in case a python controller holds a reference to a deleted object if (!GetSGNode()) - return defaultScaling; + return dummy_scaling; return GetSGNode()->GetWorldScaling(); } +const MT_Vector3& KX_GameObject::NodeGetLocalScaling() const +{ + // check on valid node in case a python controller holds a reference to a deleted object + if (!GetSGNode()) + return dummy_scaling; + return GetSGNode()->GetLocalScale(); +} const MT_Point3& KX_GameObject::NodeGetWorldPosition() const { - static MT_Point3 defaultPosition = MT_Point3(0.0, 0.0, 0.0); - // check on valid node in case a python controller holds a reference to a deleted object - if (!GetSGNode()) - return defaultPosition; + if (GetSGNode()) + return GetSGNode()->GetWorldPosition(); + else + return dummy_point; +} - return GetSGNode()->GetWorldPosition(); +const MT_Point3& KX_GameObject::NodeGetLocalPosition() const +{ + // check on valid node in case a python controller holds a reference to a deleted object + if (GetSGNode()) + return GetSGNode()->GetLocalPosition(); + else + return dummy_point; } + /* Suspend/ resume: for the dynamic behaviour, there is a simple * method. For the residual motion, there is not. I wonder what the * correct solution is for Sumo. Remove from the motion-update tree? @@ -941,7 +1126,8 @@ void KX_GameObject::Resume(void) { if (m_suspended) { SCA_IObject::Resume(); - GetPhysicsController()->RestoreDynamics(); + if(GetPhysicsController()) + GetPhysicsController()->RestoreDynamics(); m_suspended = false; } @@ -952,36 +1138,239 @@ void KX_GameObject::Suspend() if ((!m_ignore_activity_culling) && (!m_suspended)) { SCA_IObject::Suspend(); - GetPhysicsController()->SuspendDynamics(); + if(GetPhysicsController()) + GetPhysicsController()->SuspendDynamics(); m_suspended = true; } } +static void walk_children(SG_Node* node, CListValue* list, bool recursive) +{ + if (!node) + return; + NodeList& children = node->GetSGChildren(); + for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) + { + SG_Node* childnode = (*childit); + CValue* childobj = (CValue*)childnode->GetSGClientObject(); + if (childobj != NULL) // This is a GameObject + { + // add to the list + list->Add(childobj->AddRef()); + } + + // if the childobj is NULL then this may be an inverse parent link + // so a non recursive search should still look down this node. + if (recursive || childobj==NULL) { + walk_children(childnode, list, recursive); + } + } +} + +CListValue* KX_GameObject::GetChildren() +{ + CListValue* list = new CListValue(); + walk_children(GetSGNode(), list, 0); /* GetSGNode() is always valid or it would have raised an exception before this */ + return list; +} +CListValue* KX_GameObject::GetChildrenRecursive() +{ + CListValue* list = new CListValue(); + walk_children(GetSGNode(), list, 1); + return list; +} + +#ifdef USE_MATHUTILS + +/* These require an SGNode */ +#define MATHUTILS_VEC_CB_POS_LOCAL 1 +#define MATHUTILS_VEC_CB_POS_GLOBAL 2 +#define MATHUTILS_VEC_CB_SCALE_LOCAL 3 +#define MATHUTILS_VEC_CB_SCALE_GLOBAL 4 +#define MATHUTILS_VEC_CB_INERTIA_LOCAL 5 + +static int mathutils_kxgameob_vector_cb_index= -1; /* index for our callbacks */ + +static int mathutils_kxgameob_generic_check(PyObject *self_v) +{ + KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); + if(self==NULL) + return 0; + + return 1; +} + +static int mathutils_kxgameob_vector_get(PyObject *self_v, int subtype, float *vec_from) +{ + KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); + if(self==NULL) + return 0; + + switch(subtype) { + case MATHUTILS_VEC_CB_POS_LOCAL: + self->NodeGetLocalPosition().getValue(vec_from); + break; + case MATHUTILS_VEC_CB_POS_GLOBAL: + self->NodeGetWorldPosition().getValue(vec_from); + break; + case MATHUTILS_VEC_CB_SCALE_LOCAL: + self->NodeGetLocalScaling().getValue(vec_from); + break; + case MATHUTILS_VEC_CB_SCALE_GLOBAL: + self->NodeGetWorldScaling().getValue(vec_from); + break; + case MATHUTILS_VEC_CB_INERTIA_LOCAL: + if(!self->GetPhysicsController()) return 0; + self->GetPhysicsController()->GetLocalInertia().getValue(vec_from); + break; + } + + return 1; +} + +static int mathutils_kxgameob_vector_set(PyObject *self_v, int subtype, float *vec_to) +{ + KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); + if(self==NULL) + return 0; + + switch(subtype) { + case MATHUTILS_VEC_CB_POS_LOCAL: + self->NodeSetLocalPosition(MT_Point3(vec_to)); + self->NodeUpdateGS(0.f); + break; + case MATHUTILS_VEC_CB_POS_GLOBAL: + self->NodeSetWorldPosition(MT_Point3(vec_to)); + self->NodeUpdateGS(0.f); + break; + case MATHUTILS_VEC_CB_SCALE_LOCAL: + self->NodeSetLocalScale(MT_Point3(vec_to)); + self->NodeUpdateGS(0.f); + break; + case MATHUTILS_VEC_CB_SCALE_GLOBAL: + break; + case MATHUTILS_VEC_CB_INERTIA_LOCAL: + /* read only */ + break; + } + + return 1; +} + +static int mathutils_kxgameob_vector_get_index(PyObject *self_v, int subtype, float *vec_from, int index) +{ + float f[4]; + /* lazy, avoid repeteing the case statement */ + if(!mathutils_kxgameob_vector_get(self_v, subtype, f)) + return 0; + + vec_from[index]= f[index]; + return 1; +} + +static int mathutils_kxgameob_vector_set_index(PyObject *self_v, int subtype, float *vec_to, int index) +{ + float f= vec_to[index]; + + /* lazy, avoid repeteing the case statement */ + if(!mathutils_kxgameob_vector_get(self_v, subtype, vec_to)) + return 0; + + vec_to[index]= f; + mathutils_kxgameob_vector_set(self_v, subtype, vec_to); + + return 1; +} + +Mathutils_Callback mathutils_kxgameob_vector_cb = { + mathutils_kxgameob_generic_check, + mathutils_kxgameob_vector_get, + mathutils_kxgameob_vector_set, + mathutils_kxgameob_vector_get_index, + mathutils_kxgameob_vector_set_index +}; + +/* Matrix */ +#define MATHUTILS_MAT_CB_ORI_LOCAL 1 +#define MATHUTILS_MAT_CB_ORI_GLOBAL 2 + +static int mathutils_kxgameob_matrix_cb_index= -1; /* index for our callbacks */ + +static int mathutils_kxgameob_matrix_get(PyObject *self_v, int subtype, float *mat_from) +{ + KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); + if(self==NULL) + return 0; + + switch(subtype) { + case MATHUTILS_MAT_CB_ORI_LOCAL: + self->NodeGetLocalOrientation().getValue3x3(mat_from); + break; + case MATHUTILS_MAT_CB_ORI_GLOBAL: + self->NodeGetWorldOrientation().getValue3x3(mat_from); + break; + } + + return 1; +} -/* ------- python stuff ---------------------------------------------------*/ +static int mathutils_kxgameob_matrix_set(PyObject *self_v, int subtype, float *mat_to) +{ + KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); + if(self==NULL) + return 0; + + MT_Matrix3x3 mat3x3; + switch(subtype) { + case MATHUTILS_MAT_CB_ORI_LOCAL: + mat3x3.setValue3x3(mat_to); + self->NodeSetLocalOrientation(mat3x3); + self->NodeUpdateGS(0.f); + break; + case MATHUTILS_MAT_CB_ORI_GLOBAL: + mat3x3.setValue3x3(mat_to); + self->NodeSetLocalOrientation(mat3x3); + self->NodeUpdateGS(0.f); + break; + } + + return 1; +} +Mathutils_Callback mathutils_kxgameob_matrix_cb = { + mathutils_kxgameob_generic_check, + mathutils_kxgameob_matrix_get, + mathutils_kxgameob_matrix_set, + NULL, + NULL +}; +void KX_GameObject_Mathutils_Callback_Init(void) +{ + // register mathutils callbacks, ok to run more then once. + mathutils_kxgameob_vector_cb_index= Mathutils_RegisterCallback(&mathutils_kxgameob_vector_cb); + mathutils_kxgameob_matrix_cb_index= Mathutils_RegisterCallback(&mathutils_kxgameob_matrix_cb); +} + +#endif // USE_MATHUTILS + +/* ------- python stuff ---------------------------------------------------*/ + PyMethodDef KX_GameObject::Methods[] = { - {"getPosition", (PyCFunction) KX_GameObject::sPyGetPosition, METH_NOARGS}, - {"setPosition", (PyCFunction) KX_GameObject::sPySetPosition, METH_O}, - {"setWorldPosition", (PyCFunction) KX_GameObject::sPySetWorldPosition, METH_O}, + {"applyForce", (PyCFunction) KX_GameObject::sPyApplyForce, METH_VARARGS}, + {"applyTorque", (PyCFunction) KX_GameObject::sPyApplyTorque, METH_VARARGS}, + {"applyRotation", (PyCFunction) KX_GameObject::sPyApplyRotation, METH_VARARGS}, + {"applyMovement", (PyCFunction) KX_GameObject::sPyApplyMovement, METH_VARARGS}, {"getLinearVelocity", (PyCFunction) KX_GameObject::sPyGetLinearVelocity, METH_VARARGS}, {"setLinearVelocity", (PyCFunction) KX_GameObject::sPySetLinearVelocity, METH_VARARGS}, {"getAngularVelocity", (PyCFunction) KX_GameObject::sPyGetAngularVelocity, METH_VARARGS}, {"setAngularVelocity", (PyCFunction) KX_GameObject::sPySetAngularVelocity, METH_VARARGS}, {"getVelocity", (PyCFunction) KX_GameObject::sPyGetVelocity, METH_VARARGS}, - {"getMass", (PyCFunction) KX_GameObject::sPyGetMass, METH_NOARGS}, {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_NOARGS}, - {"getOrientation", (PyCFunction) KX_GameObject::sPyGetOrientation, METH_NOARGS}, - {"setOrientation", (PyCFunction) KX_GameObject::sPySetOrientation, METH_O}, - {"getVisible",(PyCFunction) KX_GameObject::sPyGetVisible, METH_NOARGS}, - {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS}, - {"getState",(PyCFunction) KX_GameObject::sPyGetState, METH_NOARGS}, - {"setState",(PyCFunction) KX_GameObject::sPySetState, METH_O}, {"alignAxisToVect",(PyCFunction) KX_GameObject::sPyAlignAxisToVect, METH_VARARGS}, {"getAxisVect",(PyCFunction) KX_GameObject::sPyGetAxisVect, METH_O}, {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics,METH_NOARGS}, @@ -990,23 +1379,61 @@ PyMethodDef KX_GameObject::Methods[] = { {"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_NOARGS}, {"applyImpulse", (PyCFunction) KX_GameObject::sPyApplyImpulse, METH_VARARGS}, {"setCollisionMargin", (PyCFunction) KX_GameObject::sPySetCollisionMargin, METH_O}, - {"getParent", (PyCFunction)KX_GameObject::sPyGetParent,METH_NOARGS}, - {"setParent", (PyCFunction)KX_GameObject::sPySetParent,METH_O}, + {"setParent", (PyCFunction)KX_GameObject::sPySetParent,METH_VARARGS}, + {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS}, + {"setOcclusion",(PyCFunction) KX_GameObject::sPySetOcclusion, METH_VARARGS}, {"removeParent", (PyCFunction)KX_GameObject::sPyRemoveParent,METH_NOARGS}, - {"getChildren", (PyCFunction)KX_GameObject::sPyGetChildren,METH_NOARGS}, - {"getChildrenRecursive", (PyCFunction)KX_GameObject::sPyGetChildrenRecursive,METH_NOARGS}, - {"getMesh", (PyCFunction)KX_GameObject::sPyGetMesh,METH_VARARGS}, + + {"getPhysicsId", (PyCFunction)KX_GameObject::sPyGetPhysicsId,METH_NOARGS}, {"getPropertyNames", (PyCFunction)KX_GameObject::sPyGetPropertyNames,METH_NOARGS}, - {"replaceMesh",(PyCFunction) KX_GameObject::sPyReplaceMesh, METH_O}, + {"replaceMesh",(PyCFunction) KX_GameObject::sPyReplaceMesh, METH_VARARGS}, {"endObject",(PyCFunction) KX_GameObject::sPyEndObject, METH_NOARGS}, + {"reinstancePhysicsMesh", (PyCFunction)KX_GameObject::sPyReinstancePhysicsMesh,METH_VARARGS}, + KX_PYMETHODTABLE(KX_GameObject, rayCastTo), KX_PYMETHODTABLE(KX_GameObject, rayCast), - KX_PYMETHODTABLE(KX_GameObject, getDistanceTo), - KX_PYMETHODTABLE(KX_GameObject, getVectTo), + KX_PYMETHODTABLE_O(KX_GameObject, getDistanceTo), + KX_PYMETHODTABLE_O(KX_GameObject, getVectTo), + KX_PYMETHODTABLE(KX_GameObject, sendMessage), + + // dict style access for props + {"get",(PyCFunction) KX_GameObject::sPyget, METH_VARARGS}, + {NULL,NULL} //Sentinel }; +PyAttributeDef KX_GameObject::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("name", KX_GameObject, pyattr_get_name), + KX_PYATTRIBUTE_RO_FUNCTION("parent", KX_GameObject, pyattr_get_parent), + KX_PYATTRIBUTE_RW_FUNCTION("mass", KX_GameObject, pyattr_get_mass, pyattr_set_mass), + KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMin", KX_GameObject, pyattr_get_lin_vel_min, pyattr_set_lin_vel_min), + KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMax", KX_GameObject, pyattr_get_lin_vel_max, pyattr_set_lin_vel_max), + KX_PYATTRIBUTE_RW_FUNCTION("visible", KX_GameObject, pyattr_get_visible, pyattr_set_visible), + KX_PYATTRIBUTE_BOOL_RW ("occlusion", KX_GameObject, m_bOccluder), + KX_PYATTRIBUTE_RW_FUNCTION("position", KX_GameObject, pyattr_get_worldPosition, pyattr_set_localPosition), + KX_PYATTRIBUTE_RO_FUNCTION("localInertia", KX_GameObject, pyattr_get_localInertia), + KX_PYATTRIBUTE_RW_FUNCTION("orientation",KX_GameObject,pyattr_get_worldOrientation,pyattr_set_localOrientation), + KX_PYATTRIBUTE_RW_FUNCTION("scaling", KX_GameObject, pyattr_get_worldScaling, pyattr_set_localScaling), + KX_PYATTRIBUTE_RW_FUNCTION("timeOffset",KX_GameObject, pyattr_get_timeOffset,pyattr_set_timeOffset), + KX_PYATTRIBUTE_RW_FUNCTION("state", KX_GameObject, pyattr_get_state, pyattr_set_state), + KX_PYATTRIBUTE_RO_FUNCTION("meshes", KX_GameObject, pyattr_get_meshes), + KX_PYATTRIBUTE_RW_FUNCTION("localOrientation",KX_GameObject,pyattr_get_localOrientation,pyattr_set_localOrientation), + KX_PYATTRIBUTE_RW_FUNCTION("worldOrientation",KX_GameObject,pyattr_get_worldOrientation,pyattr_set_worldOrientation), + KX_PYATTRIBUTE_RW_FUNCTION("localPosition", KX_GameObject, pyattr_get_localPosition, pyattr_set_localPosition), + KX_PYATTRIBUTE_RW_FUNCTION("worldPosition", KX_GameObject, pyattr_get_worldPosition, pyattr_set_worldPosition), + KX_PYATTRIBUTE_RW_FUNCTION("localScale", KX_GameObject, pyattr_get_localScaling, pyattr_set_localScaling), + KX_PYATTRIBUTE_RO_FUNCTION("worldScale", KX_GameObject, pyattr_get_worldScaling), + KX_PYATTRIBUTE_RO_FUNCTION("children", KX_GameObject, pyattr_get_children), + KX_PYATTRIBUTE_RO_FUNCTION("childrenRecursive", KX_GameObject, pyattr_get_children_recursive), + KX_PYATTRIBUTE_RO_FUNCTION("attrDict", KX_GameObject, pyattr_get_attrDict), + + /* Experemental, dont rely on these yet */ + KX_PYATTRIBUTE_RO_FUNCTION("sensors", KX_GameObject, pyattr_get_sensors), + KX_PYATTRIBUTE_RO_FUNCTION("controllers", KX_GameObject, pyattr_get_controllers), + KX_PYATTRIBUTE_RO_FUNCTION("actuators", KX_GameObject, pyattr_get_actuators), + {NULL} //Sentinel +}; /* @@ -1025,248 +1452,660 @@ bool KX_GameObject::ConvertPythonVectorArgs(PyObject* args, } */ -PyObject* KX_GameObject::PyReplaceMesh(PyObject* self, PyObject* value) +PyObject* KX_GameObject::PyReplaceMesh(PyObject* args) { - KX_Scene *scene = PHY_GetActiveScene(); - char* meshname; - void* mesh_pt; - - meshname = PyString_AsString(value); - if (meshname==NULL) { - PyErr_SetString(PyExc_ValueError, "Expected a mesh name"); + KX_Scene *scene = KX_GetActiveScene(); + + PyObject *value; + int use_gfx= 1, use_phys= 0; + RAS_MeshObject *new_mesh; + + if (!PyArg_ParseTuple(args,"O|ii:replaceMesh", &value, &use_gfx, &use_phys)) return NULL; - } - mesh_pt = SCA_ILogicBrick::m_sCurrentLogicManager->GetMeshByName(STR_String(meshname)); - if (mesh_pt==NULL) { - PyErr_SetString(PyExc_ValueError, "The mesh name given does not exist"); + if (!ConvertPythonToMesh(value, &new_mesh, false, "gameOb.replaceMesh(value): KX_GameObject")) return NULL; - } - scene->ReplaceMesh(this, (class RAS_MeshObject*)mesh_pt); + scene->ReplaceMesh(this, new_mesh, (bool)use_gfx, (bool)use_phys); Py_RETURN_NONE; } -PyObject* KX_GameObject::PyEndObject(PyObject* self) +PyObject* KX_GameObject::PyEndObject() { - - KX_Scene *scene = PHY_GetActiveScene(); + KX_Scene *scene = KX_GetActiveScene(); + scene->DelayedRemoveObject(this); Py_RETURN_NONE; } +PyObject* KX_GameObject::PyReinstancePhysicsMesh(PyObject* args) +{ + KX_GameObject *gameobj= NULL; + RAS_MeshObject *mesh= NULL; + + PyObject *gameobj_py= NULL; + PyObject *mesh_py= NULL; + + if ( !PyArg_ParseTuple(args,"|OO:reinstancePhysicsMesh",&gameobj_py, &mesh_py) || + (gameobj_py && !ConvertPythonToGameObject(gameobj_py, &gameobj, true, "gameOb.reinstancePhysicsMesh(obj, mesh): KX_GameObject")) || + (mesh_py && !ConvertPythonToMesh(mesh_py, &mesh, true, "gameOb.reinstancePhysicsMesh(obj, mesh): KX_GameObject")) + ) { + return NULL; + } + + /* gameobj and mesh can be NULL */ + if(KX_ReInstanceBulletShapeFromMesh(this, gameobj, mesh)) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + +static PyObject *Map_GetItem(PyObject *self_v, PyObject *item) +{ + KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); + const char *attr_str= _PyUnicode_AsString(item); + CValue* resultattr; + PyObject* pyconvert; + + if (self==NULL) { + PyErr_SetString(PyExc_SystemError, "val = gameOb[key]: KX_GameObject, "BGE_PROXY_ERROR_MSG); + return NULL; + } + + /* first see if the attributes a string and try get the cvalue attribute */ + if(attr_str && (resultattr=self->GetProperty(attr_str))) { + pyconvert = resultattr->ConvertValueToPython(); + return pyconvert ? pyconvert:resultattr->GetProxy(); + } + /* no CValue attribute, try get the python only m_attr_dict attribute */ + else if (self->m_attr_dict && (pyconvert=PyDict_GetItem(self->m_attr_dict, item))) { + + if (attr_str) + PyErr_Clear(); + Py_INCREF(pyconvert); + return pyconvert; + } + else { + if(attr_str) PyErr_Format(PyExc_KeyError, "value = gameOb[key]: KX_GameObject, key \"%s\" does not exist", attr_str); + else PyErr_SetString(PyExc_KeyError, "value = gameOb[key]: KX_GameObject, key does not exist"); + return NULL; + } + +} + + +static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) +{ + KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); + const char *attr_str= _PyUnicode_AsString(key); + if(attr_str==NULL) + PyErr_Clear(); + + if (self==NULL) { + PyErr_SetString(PyExc_SystemError, "gameOb[key] = value: KX_GameObject, "BGE_PROXY_ERROR_MSG); + return -1; + } + + if (val==NULL) { /* del ob["key"] */ + int del= 0; + + /* try remove both just incase */ + if(attr_str) + del |= (self->RemoveProperty(attr_str)==true) ? 1:0; + + if(self->m_attr_dict) + del |= (PyDict_DelItem(self->m_attr_dict, key)==0) ? 1:0; + + if (del==0) { + if(attr_str) PyErr_Format(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key \"%s\" could not be set", attr_str); + else PyErr_SetString(PyExc_KeyError, "del gameOb[key]: KX_GameObject, key could not be deleted"); + return -1; + } + else if (self->m_attr_dict) { + PyErr_Clear(); /* PyDict_DelItem sets an error when it fails */ + } + } + else { /* ob["key"] = value */ + int set= 0; + + /* as CValue */ + if(attr_str && PyObject_TypeCheck(val, &PyObjectPlus::Type)==0) /* dont allow GameObjects for eg to be assigned to CValue props */ + { + CValue* vallie = self->ConvertPythonToValue(val, ""); /* error unused */ + + if(vallie) + { + CValue* oldprop = self->GetProperty(attr_str); + + if (oldprop) + oldprop->SetValue(vallie); + else + self->SetProperty(attr_str, vallie); + + vallie->Release(); + set= 1; + + /* try remove dict value to avoid double ups */ + if (self->m_attr_dict){ + if (PyDict_DelItem(self->m_attr_dict, key) != 0) + PyErr_Clear(); + } + } + else { + PyErr_Clear(); + } + } + + if(set==0) + { + if (self->m_attr_dict==NULL) /* lazy init */ + self->m_attr_dict= PyDict_New(); + + + if(PyDict_SetItem(self->m_attr_dict, key, val)==0) + { + if(attr_str) + self->RemoveProperty(attr_str); /* overwrite the CValue if it exists */ + set= 1; + } + else { + if(attr_str) PyErr_Format(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key \"%s\" not be added to internal dictionary", attr_str); + else PyErr_SetString(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key not be added to internal dictionary"); + } + } + + if(set==0) + return -1; /* pythons error value */ + + } + + return 0; /* success */ +} -PyObject* KX_GameObject::PyGetPosition(PyObject* self) +static int Seq_Contains(PyObject *self_v, PyObject *value) { - return PyObjectFrom(NodeGetWorldPosition()); + KX_GameObject* self= static_cast<KX_GameObject*>BGE_PROXY_REF(self_v); + + if (self==NULL) { + PyErr_SetString(PyExc_SystemError, "val in gameOb: KX_GameObject, "BGE_PROXY_ERROR_MSG); + return -1; + } + + if(PyUnicode_Check(value) && self->GetProperty(_PyUnicode_AsString(value))) + return 1; + + if (self->m_attr_dict && PyDict_GetItem(self->m_attr_dict, value)) + return 1; + + return 0; } +PyMappingMethods KX_GameObject::Mapping = { + (lenfunc)NULL , /*inquiry mp_length */ + (binaryfunc)Map_GetItem, /*binaryfunc mp_subscript */ + (objobjargproc)Map_SetItem, /*objobjargproc mp_ass_subscript */ +}; + +PySequenceMethods KX_GameObject::Sequence = { + NULL, /* Cant set the len otherwise it can evaluate as false */ + NULL, /* sq_concat */ + NULL, /* sq_repeat */ + NULL, /* sq_item */ + NULL, /* sq_slice */ + NULL, /* sq_ass_item */ + NULL, /* sq_ass_slice */ + (objobjproc)Seq_Contains, /* sq_contains */ +}; PyTypeObject KX_GameObject::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_GameObject", - sizeof(KX_GameObject), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 + PyVarObject_HEAD_INIT(NULL, 0) + "KX_GameObject", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, + &Sequence, + &Mapping, + 0,0,0, + NULL, + NULL, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_IObject::Type, + 0,0,0,0,0,0, + py_base_new }; +PyObject* KX_GameObject::pyattr_get_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + return PyUnicode_FromString(self->GetName().ReadPtr()); +} +PyObject* KX_GameObject::pyattr_get_parent(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + KX_GameObject* parent = self->GetParent(); + if (parent) { + parent->Release(); /* self->GetParent() AddRef's */ + return parent->GetProxy(); + } + Py_RETURN_NONE; +} -PyParentObject KX_GameObject::Parents[] = { - &KX_GameObject::Type, - &SCA_IObject::Type, - &CValue::Type, - NULL -}; +PyObject* KX_GameObject::pyattr_get_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + KX_IPhysicsController *spc = self->GetPhysicsController(); + return PyFloat_FromDouble(spc ? spc->GetMass() : 0.0f); +} +int KX_GameObject::pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + KX_IPhysicsController *spc = self->GetPhysicsController(); + MT_Scalar val = PyFloat_AsDouble(value); + if (val < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "gameOb.mass = float: KX_GameObject, expected a float zero or above"); + return PY_SET_ATTR_FAIL; + } + if (spc) + spc->SetMass(val); + return PY_SET_ATTR_SUCCESS; +} -PyObject* KX_GameObject::_getattr(const STR_String& attr) +PyObject* KX_GameObject::pyattr_get_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - if (m_pPhysicsController1) - { - if (attr == "mass") - return PyFloat_FromDouble(GetPhysicsController()->GetMass()); + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + KX_IPhysicsController *spc = self->GetPhysicsController(); + return PyFloat_FromDouble(spc ? spc->GetLinVelocityMax() : 0.0f); +} + +int KX_GameObject::pyattr_set_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + KX_IPhysicsController *spc = self->GetPhysicsController(); + MT_Scalar val = PyFloat_AsDouble(value); + if (val < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "gameOb.linVelocityMin = float: KX_GameObject, expected a float zero or above"); + return PY_SET_ATTR_FAIL; } - if (attr == "parent") - { - KX_GameObject* parent = GetParent(); - if (parent) - { - parent->AddRef(); - return parent; - } - Py_RETURN_NONE; + if (spc) + spc->SetLinVelocityMin(val); + + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_GameObject::pyattr_get_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + KX_IPhysicsController *spc = self->GetPhysicsController(); + return PyFloat_FromDouble(spc ? spc->GetLinVelocityMax() : 0.0f); +} + +int KX_GameObject::pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + KX_IPhysicsController *spc = self->GetPhysicsController(); + MT_Scalar val = PyFloat_AsDouble(value); + if (val < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "gameOb.linVelocityMax = float: KX_GameObject, expected a float zero or above"); + return PY_SET_ATTR_FAIL; } - if (attr == "visible") - return PyInt_FromLong(m_bVisible); + if (spc) + spc->SetLinVelocityMax(val); + + return PY_SET_ATTR_SUCCESS; +} + + +PyObject* KX_GameObject::pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + return PyBool_FromLong(self->GetVisible()); +} + +int KX_GameObject::pyattr_set_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + int param = PyObject_IsTrue( value ); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "gameOb.visible = bool: KX_GameObject, expected True or False"); + return PY_SET_ATTR_FAIL; + } + + self->SetVisible(param, false); + self->UpdateBuckets(false); + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_GameObject::pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ +#ifdef USE_MATHUTILS + return newVectorObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_GLOBAL); +#else + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + return PyObjectFrom(self->NodeGetWorldPosition()); +#endif +} + +int KX_GameObject::pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + MT_Point3 pos; + if (!PyVecTo(value, pos)) + return PY_SET_ATTR_FAIL; - if (attr == "position") - return PyObjectFrom(NodeGetWorldPosition()); + self->NodeSetWorldPosition(pos); + self->NodeUpdateGS(0.f); + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_GameObject::pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ +#ifdef USE_MATHUTILS + return newVectorObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_LOCAL); +#else + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + return PyObjectFrom(self->NodeGetLocalPosition()); +#endif +} + +int KX_GameObject::pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + MT_Point3 pos; + if (!PyVecTo(value, pos)) + return PY_SET_ATTR_FAIL; - if (attr == "orientation") - return PyObjectFrom(NodeGetWorldOrientation()); + self->NodeSetLocalPosition(pos); + self->NodeUpdateGS(0.f); + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ +#ifdef USE_MATHUTILS + return newVectorObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_INERTIA_LOCAL); +#else + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + if (self->GetPhysicsController()) + return PyObjectFrom(self->GetPhysicsController()->GetLocalInertia()); + return Py_BuildValue("fff", 0.0f, 0.0f, 0.0f); +#endif +} + +PyObject* KX_GameObject::pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ +#ifdef USE_MATHUTILS + return newMatrixObject_cb(BGE_PROXY_FROM_REF(self_v), 3, 3, mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_GLOBAL); +#else + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + return PyObjectFrom(self->NodeGetWorldOrientation()); +#endif +} + +int KX_GameObject::pyattr_set_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); - if (attr == "scaling") - return PyObjectFrom(NodeGetWorldScaling()); - - if (attr == "name") - return PyString_FromString(m_name.ReadPtr()); - if (attr == "timeOffset") { - if (m_pSGNode->GetSGParent()->IsSlowParent()) { - return PyFloat_FromDouble(static_cast<KX_SlowParentRelation *>(m_pSGNode->GetSGParent()->GetParentRelation())->GetTimeOffset()); - } else { - return PyFloat_FromDouble(0.0); - } - } + /* if value is not a sequence PyOrientationTo makes an error */ + MT_Matrix3x3 rot; + if (!PyOrientationTo(value, rot, "gameOb.worldOrientation = sequence: KX_GameObject, ")) + return PY_SET_ATTR_FAIL; + + self->NodeSetGlobalOrientation(rot); + self->NodeUpdateGS(0.f); + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_GameObject::pyattr_get_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ +#ifdef USE_MATHUTILS + return newMatrixObject_cb(BGE_PROXY_FROM_REF(self_v), 3, 3, mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_LOCAL); +#else + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + return PyObjectFrom(self->NodeGetLocalOrientation()); +#endif +} + +int KX_GameObject::pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); - _getattr_up(SCA_IObject); + /* if value is not a sequence PyOrientationTo makes an error */ + MT_Matrix3x3 rot; + if (!PyOrientationTo(value, rot, "gameOb.localOrientation = sequence: KX_GameObject, ")) + return PY_SET_ATTR_FAIL; + + self->NodeSetLocalOrientation(rot); + self->NodeUpdateGS(0.f); + return PY_SET_ATTR_SUCCESS; } -int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr method +PyObject* KX_GameObject::pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - if (attr == "mass") { - PyErr_SetString(PyExc_AttributeError, "attribute \"mass\" is read only"); - return 1; +#ifdef USE_MATHUTILS + return newVectorObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_GLOBAL); +#else + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + return PyObjectFrom(self->NodeGetWorldScaling()); +#endif +} + +PyObject* KX_GameObject::pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ +#ifdef USE_MATHUTILS + return newVectorObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_LOCAL); +#else + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + return PyObjectFrom(self->NodeGetLocalScaling()); +#endif +} + +int KX_GameObject::pyattr_set_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + MT_Vector3 scale; + if (!PyVecTo(value, scale)) + return PY_SET_ATTR_FAIL; + + self->NodeSetLocalScale(scale); + self->NodeUpdateGS(0.f); + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_GameObject::pyattr_get_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + SG_Node* sg_parent; + if (self->GetSGNode() && (sg_parent = self->GetSGNode()->GetSGParent()) != NULL && sg_parent->IsSlowParent()) { + return PyFloat_FromDouble(static_cast<KX_SlowParentRelation *>(sg_parent->GetParentRelation())->GetTimeOffset()); + } else { + return PyFloat_FromDouble(0.0); } +} + +int KX_GameObject::pyattr_set_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + if (self->GetSGNode()) { + MT_Scalar val = PyFloat_AsDouble(value); + SG_Node* sg_parent= self->GetSGNode()->GetSGParent(); + if (val < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "gameOb.timeOffset = float: KX_GameObject, expected a float zero or above"); + return PY_SET_ATTR_FAIL; + } + if (sg_parent && sg_parent->IsSlowParent()) + static_cast<KX_SlowParentRelation *>(sg_parent->GetParentRelation())->SetTimeOffset(val); + } + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_GameObject::pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + int state = 0; + state |= self->GetState(); + return PyLong_FromSsize_t(state); +} + +int KX_GameObject::pyattr_set_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + int state_i = PyLong_AsSsize_t(value); + unsigned int state = 0; - if (attr == "parent") { - PyErr_SetString(PyExc_AttributeError, "attribute \"mass\" is read only\nUse setParent()"); - return 1; + if (state_i == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "gameOb.state = int: KX_GameObject, expected an int bit field"); + return PY_SET_ATTR_FAIL; } - - if (PyInt_Check(value)) - { - int val = PyInt_AsLong(value); - if (attr == "visible") - { - SetVisible(val != 0, false); - UpdateBuckets(false); - return 0; - } + + state |= state_i; + if ((state & ((1<<30)-1)) == 0) { + PyErr_SetString(PyExc_AttributeError, "gameOb.state = int: KX_GameObject, state bitfield was not between 0 and 30 (1<<0 and 1<<29)"); + return PY_SET_ATTR_FAIL; } + self->SetState(state); + return PY_SET_ATTR_SUCCESS; +} - if (PyFloat_Check(value)) +PyObject* KX_GameObject::pyattr_get_meshes(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + PyObject *meshes= PyList_New(self->m_meshes.size()); + int i; + + for(i=0; i < (int)self->m_meshes.size(); i++) { - MT_Scalar val = PyFloat_AsDouble(value); - if (attr == "timeOffset") { - if (m_pSGNode->GetSGParent() && m_pSGNode->GetSGParent()->IsSlowParent()) { - static_cast<KX_SlowParentRelation *>(m_pSGNode->GetSGParent()->GetParentRelation())->SetTimeOffset(val); - return 0; - } else { - return 0; - } - } + KX_MeshProxy* meshproxy = new KX_MeshProxy(self->m_meshes[i]); + PyList_SET_ITEM(meshes, i, meshproxy->NewProxy(true)); } - if (PySequence_Check(value)) - { - if (attr == "orientation") - { - MT_Matrix3x3 rot; - if (PyObject_IsMT_Matrix(value, 3)) - { - if (PyMatTo(value, rot)) - { - NodeSetLocalOrientation(rot); - NodeUpdateGS(0.f,true); - return 0; - } - return 1; - } - - if (PySequence_Size(value) == 4) - { - MT_Quaternion qrot; - if (PyVecTo(value, qrot)) - { - rot.setRotation(qrot); - NodeSetLocalOrientation(rot); - NodeUpdateGS(0.f,true); - return 0; - } - return 1; - } - - if (PySequence_Size(value) == 3) - { - MT_Vector3 erot; - if (PyVecTo(value, erot)) - { - rot.setEuler(erot); - NodeSetLocalOrientation(rot); - NodeUpdateGS(0.f,true); - return 0; - } - return 1; - } - PyErr_SetString(PyExc_AttributeError, "could not set the orientation from a 3x3 matrix, quaternion or euler sequence"); - return 1; - } - - if (attr == "position") - { - MT_Point3 pos; - if (PyVecTo(value, pos)) - { - NodeSetLocalPosition(pos); - NodeUpdateGS(0.f,true); - return 0; - } - return 1; + return meshes; +} + +/* experemental! */ +PyObject* KX_GameObject::pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_SENSORS); +} + +PyObject* KX_GameObject::pyattr_get_controllers(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CONTROLLERS); +} + +PyObject* KX_GameObject::pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_ACTUATORS); +} + +PyObject* KX_GameObject::pyattr_get_children(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + return self->GetChildren()->NewProxy(true); +} + +PyObject* KX_GameObject::pyattr_get_children_recursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + return self->GetChildrenRecursive()->NewProxy(true); +} + +PyObject* KX_GameObject::pyattr_get_attrDict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self= static_cast<KX_GameObject*>(self_v); + + if(self->m_attr_dict==NULL) + self->m_attr_dict= PyDict_New(); + + Py_INCREF(self->m_attr_dict); + return self->m_attr_dict; +} + +PyObject* KX_GameObject::PyApplyForce(PyObject* args) +{ + int local = 0; + PyObject* pyvect; + + if (PyArg_ParseTuple(args, "O|i:applyForce", &pyvect, &local)) { + MT_Vector3 force; + if (PyVecTo(pyvect, force)) { + ApplyForce(force, (local!=0)); + Py_RETURN_NONE; } - - if (attr == "scaling") - { - MT_Vector3 scale; - if (PyVecTo(value, scale)) - { - NodeSetLocalScale(scale); - NodeUpdateGS(0.f,true); - return 0; - } - return 1; + } + return NULL; +} + +PyObject* KX_GameObject::PyApplyTorque(PyObject* args) +{ + int local = 0; + PyObject* pyvect; + + if (PyArg_ParseTuple(args, "O|i:applyTorque", &pyvect, &local)) { + MT_Vector3 torque; + if (PyVecTo(pyvect, torque)) { + ApplyTorque(torque, (local!=0)); + Py_RETURN_NONE; } } - - if (PyString_Check(value)) - { - if (attr == "name") - { - m_name = PyString_AsString(value); - return 0; + return NULL; +} + +PyObject* KX_GameObject::PyApplyRotation(PyObject* args) +{ + int local = 0; + PyObject* pyvect; + + if (PyArg_ParseTuple(args, "O|i:applyRotation", &pyvect, &local)) { + MT_Vector3 rotation; + if (PyVecTo(pyvect, rotation)) { + ApplyRotation(rotation, (local!=0)); + Py_RETURN_NONE; } } - - /* Need to have parent settable here too */ - - return SCA_IObject::_setattr(attr, value); + return NULL; } +PyObject* KX_GameObject::PyApplyMovement(PyObject* args) +{ + int local = 0; + PyObject* pyvect; -PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self, PyObject* args) + if (PyArg_ParseTuple(args, "O|i:applyMovement", &pyvect, &local)) { + MT_Vector3 movement; + if (PyVecTo(pyvect, movement)) { + ApplyMovement(movement, (local!=0)); + Py_RETURN_NONE; + } + } + return NULL; +} + +PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* args) { // only can get the velocity if we have a physics object connected to us... int local = 0; - if (PyArg_ParseTuple(args,"|i",&local)) + if (PyArg_ParseTuple(args,"|i:getLinearVelocity",&local)) { return PyObjectFrom(GetLinearVelocity((local!=0))); } @@ -1276,12 +2115,12 @@ PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self, PyObject* args) } } -PyObject* KX_GameObject::PySetLinearVelocity(PyObject* self, PyObject* args) +PyObject* KX_GameObject::PySetLinearVelocity(PyObject* args) { int local = 0; PyObject* pyvect; - if (PyArg_ParseTuple(args,"O|i",&pyvect,&local)) { + if (PyArg_ParseTuple(args,"O|i:setLinearVelocity",&pyvect,&local)) { MT_Vector3 velocity; if (PyVecTo(pyvect, velocity)) { setLinearVelocity(velocity, (local!=0)); @@ -1291,11 +2130,11 @@ PyObject* KX_GameObject::PySetLinearVelocity(PyObject* self, PyObject* args) return NULL; } -PyObject* KX_GameObject::PyGetAngularVelocity(PyObject* self, PyObject* args) +PyObject* KX_GameObject::PyGetAngularVelocity(PyObject* args) { // only can get the velocity if we have a physics object connected to us... int local = 0; - if (PyArg_ParseTuple(args,"|i",&local)) + if (PyArg_ParseTuple(args,"|i:getAngularVelocity",&local)) { return PyObjectFrom(GetAngularVelocity((local!=0))); } @@ -1305,12 +2144,12 @@ PyObject* KX_GameObject::PyGetAngularVelocity(PyObject* self, PyObject* args) } } -PyObject* KX_GameObject::PySetAngularVelocity(PyObject* self, PyObject* args) +PyObject* KX_GameObject::PySetAngularVelocity(PyObject* args) { int local = 0; PyObject* pyvect; - if (PyArg_ParseTuple(args,"O|i",&pyvect,&local)) { + if (PyArg_ParseTuple(args,"O|i:setAngularVelocity",&pyvect,&local)) { MT_Vector3 velocity; if (PyVecTo(pyvect, velocity)) { setAngularVelocity(velocity, (local!=0)); @@ -1320,10 +2159,10 @@ PyObject* KX_GameObject::PySetAngularVelocity(PyObject* self, PyObject* args) return NULL; } -PyObject* KX_GameObject::PySetVisible(PyObject* self, PyObject* args) +PyObject* KX_GameObject::PySetVisible(PyObject* args) { int visible, recursive = 0; - if (!PyArg_ParseTuple(args,"i|i",&visible, &recursive)) + if (!PyArg_ParseTuple(args,"i|i:setVisible",&visible, &recursive)) return NULL; SetVisible(visible ? true:false, recursive ? true:false); @@ -1332,193 +2171,97 @@ PyObject* KX_GameObject::PySetVisible(PyObject* self, PyObject* args) } -PyObject* KX_GameObject::PyGetVisible(PyObject* self) +PyObject* KX_GameObject::PySetOcclusion(PyObject* args) { - return PyInt_FromLong(m_bVisible); -} - -PyObject* KX_GameObject::PyGetState(PyObject* self) -{ - int state = 0; - state |= GetState(); - return PyInt_FromLong(state); -} - -PyObject* KX_GameObject::PySetState(PyObject* self, PyObject* value) -{ - int state_i = PyInt_AsLong(value); - unsigned int state = 0; - - if (state_i == -1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "expected an int bit field"); + int occlusion, recursive = 0; + if (!PyArg_ParseTuple(args,"i|i:setOcclusion",&occlusion, &recursive)) return NULL; - } - - state |= state_i; - if ((state & ((1<<30)-1)) == 0) { - PyErr_SetString(PyExc_AttributeError, "The state bitfield was not between 0 and 30 (1<<0 and 1<<29)"); - return NULL; - } - SetState(state); + SetOccluder(occlusion ? true:false, recursive ? true:false); Py_RETURN_NONE; } - - -PyObject* KX_GameObject::PyGetVelocity(PyObject* self, PyObject* args) +PyObject* KX_GameObject::PyGetVelocity(PyObject* args) { // only can get the velocity if we have a physics object connected to us... - MT_Vector3 velocity(0.0,0.0,0.0); MT_Point3 point(0.0,0.0,0.0); - - PyObject* pypos = NULL; - if (PyArg_ParseTuple(args, "|O", &pypos)) - { - if (pypos) - PyVecTo(pypos, point); - } - else { + + if (!PyArg_ParseTuple(args, "|O:getVelocity", &pypos) || (pypos && !PyVecTo(pypos, point))) return NULL; - } if (m_pPhysicsController1) { - velocity = m_pPhysicsController1->GetVelocity(point); + return PyObjectFrom(m_pPhysicsController1->GetVelocity(point)); + } + else { + return PyObjectFrom(MT_Vector3(0.0,0.0,0.0)); } - - return PyObjectFrom(velocity); -} - - - -PyObject* KX_GameObject::PyGetMass(PyObject* self) -{ - return PyFloat_FromDouble(GetPhysicsController()->GetMass()); } - - -PyObject* KX_GameObject::PyGetReactionForce(PyObject* self) +PyObject* KX_GameObject::PyGetReactionForce() { // only can get the velocity if we have a physics object connected to us... - return PyObjectFrom(GetPhysicsController()->getReactionForce()); + + // XXX - Currently not working with bullet intergration, see KX_BulletPhysicsController.cpp's getReactionForce + /* + if (GetPhysicsController()) + return PyObjectFrom(GetPhysicsController()->getReactionForce()); + return PyObjectFrom(dummy_point); + */ + + return Py_BuildValue("fff", 0.0f, 0.0f, 0.0f); + } -PyObject* KX_GameObject::PyEnableRigidBody(PyObject* self) +PyObject* KX_GameObject::PyEnableRigidBody() { - GetPhysicsController()->setRigidBody(true); + if(GetPhysicsController()) + GetPhysicsController()->setRigidBody(true); Py_RETURN_NONE; } -PyObject* KX_GameObject::PyDisableRigidBody(PyObject* self) +PyObject* KX_GameObject::PyDisableRigidBody() { - GetPhysicsController()->setRigidBody(false); + if(GetPhysicsController()) + GetPhysicsController()->setRigidBody(false); Py_RETURN_NONE; } - -PyObject* KX_GameObject::PyGetParent(PyObject* self) +PyObject* KX_GameObject::PySetParent(PyObject* args) { - KX_GameObject* parent = this->GetParent(); - if (parent) - { - parent->AddRef(); - return parent; + KX_Scene *scene = KX_GetActiveScene(); + PyObject* pyobj; + KX_GameObject *obj; + int addToCompound=1, ghost=1; + + if (!PyArg_ParseTuple(args,"O|ii:setParent", &pyobj, &addToCompound, &ghost)) { + return NULL; // Python sets a simple error } - Py_RETURN_NONE; -} - -PyObject* KX_GameObject::PySetParent(PyObject* self, PyObject* value) -{ - if (!PyObject_TypeCheck(value, &KX_GameObject::Type)) { - PyErr_SetString(PyExc_TypeError, "expected a KX_GameObject type"); + if (!ConvertPythonToGameObject(pyobj, &obj, true, "gameOb.setParent(obj): KX_GameObject")) return NULL; - } - - // The object we want to set as parent - CValue *m_ob = (CValue*)value; - KX_GameObject *obj = ((KX_GameObject*)m_ob); - KX_Scene *scene = PHY_GetActiveScene(); - - this->SetParent(scene, obj); - - Py_RETURN_NONE; -} - -PyObject* KX_GameObject::PyRemoveParent(PyObject* self) -{ - KX_Scene *scene = PHY_GetActiveScene(); - this->RemoveParent(scene); + if (obj) + this->SetParent(scene, obj, addToCompound, ghost); Py_RETURN_NONE; } - -static void walk_children(SG_Node* node, CListValue* list, bool recursive) +PyObject* KX_GameObject::PyRemoveParent() { - NodeList& children = node->GetSGChildren(); - - for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) - { - SG_Node* childnode = (*childit); - CValue* childobj = (CValue*)childnode->GetSGClientObject(); - if (childobj != NULL) // This is a GameObject - { - // add to the list - list->Add(childobj->AddRef()); - } - - // if the childobj is NULL then this may be an inverse parent link - // so a non recursive search should still look down this node. - if (recursive || childobj==NULL) { - walk_children(childnode, list, recursive); - } - } -} - -PyObject* KX_GameObject::PyGetChildren(PyObject* self) -{ - CListValue* list = new CListValue(); - walk_children(m_pSGNode, list, 0); - return list; -} - -PyObject* KX_GameObject::PyGetChildrenRecursive(PyObject* self) -{ - CListValue* list = new CListValue(); - walk_children(m_pSGNode, list, 1); - return list; -} - -PyObject* KX_GameObject::PyGetMesh(PyObject* self, PyObject* args) -{ - int mesh = 0; - - if (!PyArg_ParseTuple(args, "|i", &mesh)) - return NULL; // python sets a simple error - - if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0) - { - KX_MeshProxy* meshproxy = new KX_MeshProxy(m_meshes[mesh]); - return meshproxy; - } + KX_Scene *scene = KX_GetActiveScene(); + this->RemoveParent(scene); Py_RETURN_NONE; } - - - -PyObject* KX_GameObject::PySetCollisionMargin(PyObject* self, PyObject* value) +PyObject* KX_GameObject::PySetCollisionMargin(PyObject* value) { float collisionMargin = PyFloat_AsDouble(value); @@ -1538,7 +2281,7 @@ PyObject* KX_GameObject::PySetCollisionMargin(PyObject* self, PyObject* value) -PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, PyObject* args) +PyObject* KX_GameObject::PyApplyImpulse(PyObject* args) { PyObject* pyattach; PyObject* pyimpulse; @@ -1548,7 +2291,7 @@ PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, PyObject* args) return NULL; } - if (PyArg_ParseTuple(args, "OO", &pyattach, &pyimpulse)) + if (PyArg_ParseTuple(args, "OO:applyImpulse", &pyattach, &pyimpulse)) { MT_Point3 attach; MT_Vector3 impulse; @@ -1565,7 +2308,7 @@ PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, PyObject* args) -PyObject* KX_GameObject::PySuspendDynamics(PyObject* self) +PyObject* KX_GameObject::PySuspendDynamics() { SuspendDynamics(); Py_RETURN_NONE; @@ -1573,49 +2316,20 @@ PyObject* KX_GameObject::PySuspendDynamics(PyObject* self) -PyObject* KX_GameObject::PyRestoreDynamics(PyObject* self) +PyObject* KX_GameObject::PyRestoreDynamics() { RestoreDynamics(); Py_RETURN_NONE; } - -PyObject* KX_GameObject::PyGetOrientation(PyObject* self) //keywords -{ - return PyObjectFrom(NodeGetWorldOrientation()); -} - - - -PyObject* KX_GameObject::PySetOrientation(PyObject* self, PyObject* value) -{ - MT_Matrix3x3 matrix; - if (PyObject_IsMT_Matrix(value, 3) && PyMatTo(value, matrix)) - { - NodeSetLocalOrientation(matrix); - NodeUpdateGS(0.f,true); - Py_RETURN_NONE; - } - - MT_Quaternion quat; - if (PyVecTo(value, quat)) - { - matrix.setRotation(quat); - NodeSetLocalOrientation(matrix); - NodeUpdateGS(0.f,true); - Py_RETURN_NONE; - } - return NULL; -} - -PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* self, PyObject* args) +PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* args) { PyObject* pyvect; int axis = 2; //z axis is the default float fac = 1.0; - if (PyArg_ParseTuple(args,"O|if",&pyvect,&axis, &fac)) + if (PyArg_ParseTuple(args,"O|if:alignAxisToVect",&pyvect,&axis, &fac)) { MT_Vector3 vect; if (PyVecTo(pyvect, vect)) @@ -1624,14 +2338,14 @@ PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* self, PyObject* args) if (fac> 1.0) fac= 1.0; AlignAxisToVect(vect,axis,fac); - NodeUpdateGS(0.f,true); + NodeUpdateGS(0.f); Py_RETURN_NONE; } } return NULL; } -PyObject* KX_GameObject::PyGetAxisVect(PyObject* self, PyObject* value) +PyObject* KX_GameObject::PyGetAxisVect(PyObject* value) { MT_Vector3 vect; if (PyVecTo(value, vect)) @@ -1641,33 +2355,8 @@ PyObject* KX_GameObject::PyGetAxisVect(PyObject* self, PyObject* value) return NULL; } -PyObject* KX_GameObject::PySetPosition(PyObject* self, PyObject* value) -{ - MT_Point3 pos; - if (PyVecTo(value, pos)) - { - NodeSetLocalPosition(pos); - NodeUpdateGS(0.f,true); - Py_RETURN_NONE; - } - - return NULL; -} - -PyObject* KX_GameObject::PySetWorldPosition(PyObject* self, PyObject* value) -{ - MT_Point3 pos; - if (PyVecTo(value, pos)) - { - NodeSetWorldPosition(pos); - NodeUpdateGS(0.f,true); - Py_RETURN_NONE; - } - - return NULL; -} -PyObject* KX_GameObject::PyGetPhysicsId(PyObject* self) +PyObject* KX_GameObject::PyGetPhysicsId() { KX_IPhysicsController* ctrl = GetPhysicsController(); uint_ptr physid=0; @@ -1675,27 +2364,36 @@ PyObject* KX_GameObject::PyGetPhysicsId(PyObject* self) { physid= (uint_ptr)ctrl->GetUserData(); } - return PyInt_FromLong((long)physid); + return PyLong_FromSsize_t((long)physid); } -PyObject* KX_GameObject::PyGetPropertyNames(PyObject* self) +PyObject* KX_GameObject::PyGetPropertyNames() { - return ConvertKeysToPython(); + PyObject *list= ConvertKeysToPython(); + + if(m_attr_dict) { + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next(m_attr_dict, &pos, &key, &value)) { + PyList_Append(list, key); + } + } + return list; } -KX_PYMETHODDEF_DOC(KX_GameObject, getDistanceTo, +KX_PYMETHODDEF_DOC_O(KX_GameObject, getDistanceTo, "getDistanceTo(other): get distance to another point/KX_GameObject") { MT_Point3 b; - if (PyVecArgTo(args, b)) + if (PyVecTo(value, b)) { return PyFloat_FromDouble(NodeGetWorldPosition().distance(b)); } PyErr_Clear(); - PyObject *pyother; KX_GameObject *other; - if (PyArg_ParseTuple(args, "O", &pyother) && ConvertPythonToGameObject(pyother, &other, false)) + if (ConvertPythonToGameObject(value, &other, false, "gameOb.getDistanceTo(value): KX_GameObject")) { return PyFloat_FromDouble(NodeGetWorldPosition().distance(other->NodeGetWorldPosition())); } @@ -1703,7 +2401,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, getDistanceTo, return NULL; } -KX_PYMETHODDEF_DOC(KX_GameObject, getVectTo, +KX_PYMETHODDEF_DOC_O(KX_GameObject, getVectTo, "getVectTo(other): get vector and the distance to another point/KX_GameObject\n" "Returns a 3-tuple with (distance,worldVector,localVector)\n") { @@ -1712,19 +2410,18 @@ KX_PYMETHODDEF_DOC(KX_GameObject, getVectTo, MT_Scalar distance; PyObject *returnValue; - PyObject *pyother; - if (!PyVecArgTo(args, toPoint)) + if (!PyVecTo(value, toPoint)) { PyErr_Clear(); KX_GameObject *other; - if (PyArg_ParseTuple(args, "O", &pyother) && ConvertPythonToGameObject(pyother, &other, false)) + if (ConvertPythonToGameObject(value, &other, false, "")) /* error will be overwritten */ { toPoint = other->NodeGetWorldPosition(); } else { - PyErr_SetString(PyExc_TypeError, "Expected a 3D Vector or GameObject type"); + PyErr_SetString(PyExc_TypeError, "gameOb.getVectTo(other): KX_GameObject, expected a 3D Vector or KX_GameObject type"); return NULL; } } @@ -1804,7 +2501,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, float dist = 0.0f; char *propName = NULL; - if (!PyArg_ParseTuple(args,"O|fs", &pyarg, &dist, &propName)) { + if (!PyArg_ParseTuple(args,"O|fs:rayCastTo", &pyarg, &dist, &propName)) { return NULL; // python sets simple error } @@ -1813,24 +2510,21 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, KX_GameObject *other; PyErr_Clear(); - if (ConvertPythonToGameObject(pyarg, &other, false)) + if (ConvertPythonToGameObject(pyarg, &other, false, "")) /* error will be overwritten */ { toPoint = other->NodeGetWorldPosition(); } else { - PyErr_SetString(PyExc_TypeError, "the first argument to rayCastTo must be a vector or a KX_GameObject"); + PyErr_SetString(PyExc_TypeError, "gameOb.rayCastTo(other,dist,prop): KX_GameObject, the first argument to rayCastTo must be a vector or a KX_GameObject"); return NULL; } } MT_Point3 fromPoint = NodeGetWorldPosition(); + if (dist != 0.0f) - { - MT_Vector3 toDir = toPoint-fromPoint; - toDir.normalize(); - toPoint = fromPoint + (dist) * toDir; - } - - PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment(); + toPoint = fromPoint + dist * (toPoint-fromPoint).safe_normalized(); + + PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment(); KX_IPhysicsController *spc = GetPhysicsController(); KX_GameObject *parent = GetParent(); if (!spc && parent) @@ -1847,13 +2541,39 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, KX_RayCast::RayTest(pe, fromPoint, toPoint, callback); if (m_pHitObject) - { - m_pHitObject->AddRef(); - return m_pHitObject; - } + return m_pHitObject->GetProxy(); + Py_RETURN_NONE; } +/* faster then Py_BuildValue since some scripts call raycast a lot */ +static PyObject *none_tuple_3() +{ + PyObject *ret= PyTuple_New(3); + PyTuple_SET_ITEM(ret, 0, Py_None); + PyTuple_SET_ITEM(ret, 1, Py_None); + PyTuple_SET_ITEM(ret, 2, Py_None); + + Py_INCREF(Py_None); + Py_INCREF(Py_None); + Py_INCREF(Py_None); + return ret; +} +static PyObject *none_tuple_4() +{ + PyObject *ret= PyTuple_New(4); + PyTuple_SET_ITEM(ret, 0, Py_None); + PyTuple_SET_ITEM(ret, 1, Py_None); + PyTuple_SET_ITEM(ret, 2, Py_None); + PyTuple_SET_ITEM(ret, 3, Py_None); + + Py_INCREF(Py_None); + Py_INCREF(Py_None); + Py_INCREF(Py_None); + Py_INCREF(Py_None); + return ret; +} + KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, "rayCast(to,from,dist,prop,face,xray,poly): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) of contact point with object within dist that matches prop.\n" " If no hit, return (None,None,None) or (None,None,None,None).\n" @@ -1883,7 +2603,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, KX_GameObject *other; int face=0, xray=0, poly=0; - if (!PyArg_ParseTuple(args,"O|Ofsiii", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly)) { + if (!PyArg_ParseTuple(args,"O|Ofsiii:rayCast", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly)) { return NULL; // Python sets a simple error } @@ -1891,7 +2611,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, { PyErr_Clear(); - if (ConvertPythonToGameObject(pyto, &other, false)) + if (ConvertPythonToGameObject(pyto, &other, false, "")) /* error will be overwritten */ { toPoint = other->NodeGetWorldPosition(); } else @@ -1908,12 +2628,12 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, { PyErr_Clear(); - if (ConvertPythonToGameObject(pyfrom, &other, false)) + if (ConvertPythonToGameObject(pyfrom, &other, false, "")) /* error will be overwritten */ { fromPoint = other->NodeGetWorldPosition(); } else { - PyErr_SetString(PyExc_TypeError, "the second optional argument to rayCast must be a vector or a KX_GameObject"); + PyErr_SetString(PyExc_TypeError, "gameOb.rayCast(to,from,dist,prop,face,xray,poly): KX_GameObject, the second optional argument to rayCast must be a vector or a KX_GameObject"); return NULL; } } @@ -1921,15 +2641,17 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, if (dist != 0.0f) { MT_Vector3 toDir = toPoint-fromPoint; if (MT_fuzzyZero(toDir.length2())) { - return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + //return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + return none_tuple_3(); } toDir.normalize(); toPoint = fromPoint + (dist) * toDir; } else if (MT_fuzzyZero((toPoint-fromPoint).length2())) { - return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + //return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + return none_tuple_3(); } - PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment(); + PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment(); KX_IPhysicsController *spc = GetPhysicsController(); KX_GameObject *parent = GetParent(); if (!spc && parent) @@ -1951,7 +2673,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, { PyObject* returnValue = (poly) ? PyTuple_New(4) : PyTuple_New(3); if (returnValue) { // unlikely this would ever fail, if it does python sets an error - PyTuple_SET_ITEM(returnValue, 0, m_pHitObject->AddRef()); + PyTuple_SET_ITEM(returnValue, 0, m_pHitObject->GetProxy()); PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(callback.m_hitPoint)); PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(callback.m_hitNormal)); if (poly) @@ -1959,9 +2681,9 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, if (callback.m_hitMesh) { // if this field is set, then we can trust that m_hitPolygon is a valid polygon - RAS_Polygon* poly = callback.m_hitMesh->GetPolygon(callback.m_hitPolygon); - KX_PolyProxy* polyproxy = new KX_PolyProxy(callback.m_hitMesh, poly); - PyTuple_SET_ITEM(returnValue, 3, polyproxy); + RAS_Polygon* polygon = callback.m_hitMesh->GetPolygon(callback.m_hitPolygon); + KX_PolyProxy* polyproxy = new KX_PolyProxy(callback.m_hitMesh, polygon); + PyTuple_SET_ITEM(returnValue, 3, polyproxy->NewProxy(true)); } else { @@ -1974,9 +2696,65 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, } // no hit if (poly) - return Py_BuildValue("OOOO", Py_None, Py_None, Py_None, Py_None); + //return Py_BuildValue("OOOO", Py_None, Py_None, Py_None, Py_None); + return none_tuple_4(); else - return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + //return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + return none_tuple_3(); +} + +KX_PYMETHODDEF_DOC_VARARGS(KX_GameObject, sendMessage, + "sendMessage(subject, [body, to])\n" +"sends a message in same manner as a message actuator" +"subject = Subject of the message (string)" +"body = Message body (string)" +"to = Name of object to send the message to") +{ + KX_Scene *scene = KX_GetActiveScene(); + char* subject; + char* body = (char *)""; + char* to = (char *)""; + const STR_String& from = GetName(); + + if (!PyArg_ParseTuple(args, "s|ss:sendMessage", &subject, &body, &to)) + return NULL; + + scene->GetNetworkScene()->SendMessage(to, from, subject, body); + Py_RETURN_NONE; +} + +/* dict style access */ + + +/* Matches python dict.get(key, [default]) */ +PyObject* KX_GameObject::Pyget(PyObject *args) +{ + PyObject *key; + PyObject* def = Py_None; + PyObject* ret; + + if (!PyArg_ParseTuple(args, "O|O:get", &key, &def)) + return NULL; + + + if(PyUnicode_Check(key)) { + CValue *item = GetProperty(_PyUnicode_AsString(key)); + if (item) { + ret = item->ConvertValueToPython(); + if(ret) + return ret; + else + return item->GetProxy(); + } + } + + if (m_attr_dict && (ret=PyDict_GetItem(m_attr_dict, key))) { + Py_INCREF(ret); + return ret; + } + + Py_INCREF(def); + return def; } /* --------------------------------------------------------------------- @@ -2001,10 +2779,11 @@ void KX_GameObject::Relink(GEN_Map<GEN_HashedPtr, void*> *map_parameter) } } -bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok) + +bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok, const char *error_prefix) { if (value==NULL) { - PyErr_SetString(PyExc_TypeError, "Error in ConvertPythonToGameObject, python pointer NULL, should never happen"); + PyErr_Format(PyExc_TypeError, "%s, python pointer NULL, should never happen", error_prefix); *object = NULL; return false; } @@ -2015,34 +2794,43 @@ bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py if (py_none_ok) { return true; } else { - PyErr_SetString(PyExc_TypeError, "Expected KX_GameObject or a string for a name of a KX_GameObject, None is invalid"); + PyErr_Format(PyExc_TypeError, "%s, expected KX_GameObject or a KX_GameObject name, None is invalid", error_prefix); return false; } - return (py_none_ok ? true : false); } - if (PyString_Check(value)) { - *object = (KX_GameObject *)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String( PyString_AsString(value) )); + if (PyUnicode_Check(value)) { + *object = (KX_GameObject*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String( _PyUnicode_AsString(value) )); if (*object) { return true; } else { - PyErr_SetString(PyExc_ValueError, "Requested name did not match any KX_GameObject"); + PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_GameObject in this scene", error_prefix, _PyUnicode_AsString(value)); return false; } } - if (PyObject_TypeCheck(value, &KX_GameObject::Type)) { - *object = static_cast<KX_GameObject*>(value); + if ( PyObject_TypeCheck(value, &KX_GameObject::Type) || + PyObject_TypeCheck(value, &KX_LightObject::Type) || + PyObject_TypeCheck(value, &KX_Camera::Type) ) + { + *object = static_cast<KX_GameObject*>BGE_PROXY_REF(value); + + /* sets the error */ + if (*object==NULL) { + PyErr_Format(PyExc_SystemError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix); + return false; + } + return true; } *object = NULL; if (py_none_ok) { - PyErr_SetString(PyExc_TypeError, "Expect a KX_GameObject, a string or None"); + PyErr_Format(PyExc_TypeError, "%s, expect a KX_GameObject, a string or None", error_prefix); } else { - PyErr_SetString(PyExc_TypeError, "Expect a KX_GameObject or a string"); + PyErr_Format(PyExc_TypeError, "%s, expect a KX_GameObject or a string", error_prefix); } return false; diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 20b15787d27..845cead1cdb 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -51,15 +51,22 @@ #include "SCA_LogicManager.h" /* for ConvertPythonToGameObject to search object names */ #define KX_OB_DYNAMIC 1 - //Forward declarations. struct KX_ClientObjectInfo; class KX_RayCast; class RAS_MeshObject; class KX_IPhysicsController; +class PHY_IGraphicController; class PHY_IPhysicsEnvironment; struct Object; +/* utility conversion function */ +bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok, const char *error_prefix); + +#ifdef USE_MATHUTILS +void KX_GameObject_Mathutils_Callback_Init(void); +#endif + /** * KX_GameObject is the main class for dynamic objects. */ @@ -74,6 +81,7 @@ protected: STR_String m_text; int m_layer; std::vector<RAS_MeshObject*> m_meshes; + SG_QList m_meshSlots; // head of mesh slots of this struct Object* m_pBlenderObject; struct Object* m_pBlenderGroupObject; @@ -86,10 +94,10 @@ protected: // culled = while rendering, depending on camera bool m_bVisible; bool m_bCulled; + bool m_bOccluder; KX_IPhysicsController* m_pPhysicsController1; - // used for ray casting - PHY_IPhysicsEnvironment* m_pPhysicsEnvironment; + PHY_IGraphicController* m_pGraphicController; STR_String m_testPropName; bool m_xray; KX_GameObject* m_pHitObject; @@ -101,6 +109,28 @@ protected: public: bool m_isDeformable; + /** + * Helper function for modules that can't include KX_ClientObjectInfo.h + */ + static KX_GameObject* GetClientObject(KX_ClientObjectInfo* info); + + // Python attributes that wont convert into CValue + // + // there are 2 places attributes can be stored, in the CValue, + // where attributes are converted into BGE's CValue types + // these can be used with property actuators + // + // For the python API, For types that cannot be converted into CValues (lists, dicts, GameObjects) + // these will be put into "m_attr_dict", logic bricks cannot access them. + // + // rules for setting attributes. + // + // * there should NEVER be a CValue and a m_attr_dict attribute with matching names. get/sets make sure of this. + // * if CValue conversion fails, use a PyObject in "m_attr_dict" + // * when assigning a value, first see if it can be a CValue, if it can remove the "m_attr_dict" and set the CValue + // + PyObject* m_attr_dict; + virtual void /* This function should be virtual - derived classed override it */ Relink( GEN_Map<GEN_HashedPtr, void*> *map @@ -143,7 +173,7 @@ public: /** * Sets the parent of this object to a game object */ - void SetParent(KX_Scene *scene, KX_GameObject *obj); + void SetParent(KX_Scene *scene, KX_GameObject *obj, bool addToCompound=true, bool ghost=true); /** * Removes the parent of this object to a game object @@ -157,19 +187,13 @@ public: KX_GameObject( void* sgReplicationInfo, - SG_Callbacks callbacks, - PyTypeObject* T=&Type + SG_Callbacks callbacks ); virtual ~KX_GameObject( ); - CValue* - AddRef() { - /* temporarily to find memleaks */ return CValue::AddRef(); - } - /** * @section Stuff which is here due to poor design. * Inherited from CValue and needs an implementation. @@ -206,7 +230,7 @@ public: /** * Inherited from CValue -- does nothing! */ - float + double GetNumber( ); @@ -218,7 +242,7 @@ public: /** * Inherited from CValue -- returns the name of this object. */ - STR_String + STR_String& GetName( ); @@ -227,15 +251,7 @@ public: */ void SetName( - STR_String name - ); - - /** - * Inherited from CValue -- does nothing. - */ - void - ReplicaSetName( - STR_String name + const char *name ); /** @@ -252,9 +268,7 @@ public: * data owned by this class is deep copied. Called internally */ virtual void - ProcessReplica( - KX_GameObject* replica - ); + ProcessReplica(); /** * Return the linear velocity of the game object. @@ -279,6 +293,12 @@ public: MT_Scalar GetMass(); + /** + * Return the local inertia vector of the object + */ + MT_Vector3 + GetLocalInertia(); + /** * Return the angular velocity of the game object. */ @@ -315,20 +335,6 @@ public: bool ang_vel_local ); - - /** - * @return a pointer to the physics environment in use during the game, for rayCasting - */ - PHY_IPhysicsEnvironment* GetPhysicsEnvironment() - { - return m_pPhysicsEnvironment; - } - - void SetPhysicsEnvironment(PHY_IPhysicsEnvironment* physicsEnvironment) - { - m_pPhysicsEnvironment = physicsEnvironment; - } - /** * @return a pointer to the physics controller owned by this class. */ @@ -351,12 +357,30 @@ public: } /** + * @return a pointer to the graphic controller owner by this class + */ + PHY_IGraphicController* GetGraphicController() + { + return m_pGraphicController; + } + + void SetGraphicController(PHY_IGraphicController* graphiccontroller) + { + m_pGraphicController = graphiccontroller; + } + /* + * @add/remove the graphic controller to the physic system + */ + void ActivateGraphicController(bool recurse); + + /** * @section Coordinate system manipulation functions */ void NodeSetLocalPosition(const MT_Point3& trans ); void NodeSetLocalOrientation(const MT_Matrix3x3& rot ); + void NodeSetGlobalOrientation(const MT_Matrix3x3& rot ); void NodeSetLocalScale( const MT_Vector3& scale ); @@ -367,25 +391,16 @@ public: void NodeUpdateGS( - double time, - bool bInitiator + double time ); - const - MT_Matrix3x3& - NodeGetWorldOrientation( - ) const; - - const - MT_Vector3& - NodeGetWorldScaling( - ) const; - - const - MT_Point3& - NodeGetWorldPosition( - ) const; + const MT_Matrix3x3& NodeGetWorldOrientation( ) const; + const MT_Vector3& NodeGetWorldScaling( ) const; + const MT_Point3& NodeGetWorldPosition( ) const; + const MT_Matrix3x3& NodeGetLocalOrientation( ) const; + const MT_Vector3& NodeGetLocalScaling( ) const; + const MT_Point3& NodeGetLocalPosition( ) const; /** * @section scene graph node accessor functions. @@ -525,11 +540,11 @@ public: static void UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene); /** - * Only update the transform if it's a non-dynamic object + * only used for sensor objects */ - void - UpdateNonDynas( - ); + void SynchronizeTransform(); + + static void SynchronizeTransformFunc(SG_IObject* node, void* gameobj, void* scene); /** * Function to set IPO option at start of IPO @@ -665,20 +680,37 @@ public: /** * Was this object culled? */ - bool + inline bool GetCulled( void - ); + ) { return m_bCulled; } /** * Set culled flag of this object */ - void + inline void SetCulled( bool c - ); + ) { m_bCulled = c; } + + /** + * Is this object an occluder? + */ + inline bool + GetOccluder( + void + ) { return m_bOccluder; } /** + * Set occluder flag of this object + */ + void + SetOccluder( + bool v, + bool recursive + ); + + /** * Change the layer of the object (when it is added in another layer * than the original layer) */ @@ -752,37 +784,35 @@ public: } KX_ClientObjectInfo* getClientInfo() { return m_pClient_info; } + + CListValue* GetChildren(); + CListValue* GetChildrenRecursive(); + /** * @section Python interface functions. */ + virtual PyObject* py_repr(void) + { + return PyUnicode_FromString(GetName().ReadPtr()); + } - virtual - PyObject* - _getattr( - const STR_String& attr - ); - - virtual - int - _setattr( - const STR_String& attr, - PyObject *value - ); // _setattr method - - KX_PYMETHOD_NOARGS(KX_GameObject,GetPosition); - KX_PYMETHOD_O(KX_GameObject,SetPosition); KX_PYMETHOD_O(KX_GameObject,SetWorldPosition); + KX_PYMETHOD_VARARGS(KX_GameObject, ApplyForce); + KX_PYMETHOD_VARARGS(KX_GameObject, ApplyTorque); + KX_PYMETHOD_VARARGS(KX_GameObject, ApplyRotation); + KX_PYMETHOD_VARARGS(KX_GameObject, ApplyMovement); KX_PYMETHOD_VARARGS(KX_GameObject,GetLinearVelocity); KX_PYMETHOD_VARARGS(KX_GameObject,SetLinearVelocity); KX_PYMETHOD_VARARGS(KX_GameObject,GetAngularVelocity); KX_PYMETHOD_VARARGS(KX_GameObject,SetAngularVelocity); KX_PYMETHOD_VARARGS(KX_GameObject,GetVelocity); - KX_PYMETHOD_NOARGS(KX_GameObject,GetMass); + KX_PYMETHOD_NOARGS(KX_GameObject,GetReactionForce); - KX_PYMETHOD_NOARGS(KX_GameObject,GetOrientation); - KX_PYMETHOD_O(KX_GameObject,SetOrientation); + + KX_PYMETHOD_NOARGS(KX_GameObject,GetVisible); KX_PYMETHOD_VARARGS(KX_GameObject,SetVisible); + KX_PYMETHOD_VARARGS(KX_GameObject,SetOcclusion); KX_PYMETHOD_NOARGS(KX_GameObject,GetState); KX_PYMETHOD_O(KX_GameObject,SetState); KX_PYMETHOD_VARARGS(KX_GameObject,AlignAxisToVect); @@ -794,19 +824,67 @@ public: KX_PYMETHOD_VARARGS(KX_GameObject,ApplyImpulse); KX_PYMETHOD_O(KX_GameObject,SetCollisionMargin); KX_PYMETHOD_NOARGS(KX_GameObject,GetParent); - KX_PYMETHOD_O(KX_GameObject,SetParent); + KX_PYMETHOD_VARARGS(KX_GameObject,SetParent); KX_PYMETHOD_NOARGS(KX_GameObject,RemoveParent); - KX_PYMETHOD_NOARGS(KX_GameObject,GetChildren); + KX_PYMETHOD_NOARGS(KX_GameObject,GetChildren); KX_PYMETHOD_NOARGS(KX_GameObject,GetChildrenRecursive); KX_PYMETHOD_VARARGS(KX_GameObject,GetMesh); KX_PYMETHOD_NOARGS(KX_GameObject,GetPhysicsId); KX_PYMETHOD_NOARGS(KX_GameObject,GetPropertyNames); - KX_PYMETHOD_O(KX_GameObject,ReplaceMesh); + KX_PYMETHOD_VARARGS(KX_GameObject,ReplaceMesh); KX_PYMETHOD_NOARGS(KX_GameObject,EndObject); KX_PYMETHOD_DOC(KX_GameObject,rayCastTo); KX_PYMETHOD_DOC(KX_GameObject,rayCast); - KX_PYMETHOD_DOC(KX_GameObject,getDistanceTo); - KX_PYMETHOD_DOC(KX_GameObject,getVectTo); + KX_PYMETHOD_DOC_O(KX_GameObject,getDistanceTo); + KX_PYMETHOD_DOC_O(KX_GameObject,getVectTo); + KX_PYMETHOD_DOC_VARARGS(KX_GameObject, sendMessage); + KX_PYMETHOD_VARARGS(KX_GameObject, ReinstancePhysicsMesh); + + /* Dict access */ + KX_PYMETHOD_VARARGS(KX_GameObject,get); + + /* attributes */ + static PyObject* pyattr_get_name(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_parent(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + + static PyObject* pyattr_get_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_meshes(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_children(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_children_recursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_attrDict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + + /* Experemental! */ + static PyObject* pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_controllers(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + + /* getitem/setitem */ + static PyMappingMethods Mapping; + static PySequenceMethods Sequence; private : @@ -825,8 +903,7 @@ private : }; -/* utility conversion function */ -bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok); + #endif //__KX_GAMEOBJECT diff --git a/source/gameengine/Ketsji/KX_IInterpolator.h b/source/gameengine/Ketsji/KX_IInterpolator.h index 8c899a4db0b..52b9b3be5af 100644 --- a/source/gameengine/Ketsji/KX_IInterpolator.h +++ b/source/gameengine/Ketsji/KX_IInterpolator.h @@ -31,11 +31,22 @@ #include <vector> +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class KX_IInterpolator { public: virtual ~KX_IInterpolator() {} virtual void Execute(float currentTime) const = 0; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_IInterpolator"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; typedef std::vector<KX_IInterpolator *> T_InterpolatorList; diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.cpp b/source/gameengine/Ketsji/KX_IPO_SGController.cpp index 67d54cf0b0b..bd7e09d1dda 100644 --- a/source/gameengine/Ketsji/KX_IPO_SGController.cpp +++ b/source/gameengine/Ketsji/KX_IPO_SGController.cpp @@ -58,8 +58,8 @@ KX_IpoSGController::KX_IpoSGController() m_ipo_add(false), m_ipo_local(false), m_modified(true), - m_ipo_start_initialized(false), m_ipotime(1.0), + m_ipo_start_initialized(false), m_ipo_start_euler(0.0,0.0,0.0), m_ipo_euler_initialized(false) { @@ -194,7 +194,8 @@ bool KX_IpoSGController::Update(double currentTime) else newPosition = m_ipo_start_point + newPosition; } - ob->SetLocalPosition(newPosition); + if (m_game_object) + m_game_object->NodeSetLocalPosition(newPosition); } } //modifies orientation? @@ -233,7 +234,8 @@ bool KX_IpoSGController::Update(double currentTime) rotation = m_ipo_start_orient * rotation; else rotation = rotation * m_ipo_start_orient; - ob->SetLocalOrientation(rotation); + if (m_game_object) + m_game_object->NodeSetLocalOrientation(rotation); } } else if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z]) { if (m_ipo_euler_initialized) { @@ -265,7 +267,8 @@ bool KX_IpoSGController::Update(double currentTime) else if (m_ipo_channels_active[OB_DROT_Z]) { roll += m_ipo_xform.GetDeltaEulerAngles()[2]; } - ob->SetLocalOrientation(MT_Vector3(yaw, pitch, roll)); + if (m_game_object) + m_game_object->NodeSetLocalOrientation(MT_Vector3(yaw, pitch, roll)); } } else if (m_ipo_start_initialized) { // only DROT, treat as Add @@ -286,7 +289,8 @@ bool KX_IpoSGController::Update(double currentTime) // dRot are always local MT_Matrix3x3 rotation(MT_Vector3(yaw, pitch, roll)); rotation = m_ipo_start_orient * rotation; - ob->SetLocalOrientation(rotation); + if (m_game_object) + m_game_object->NodeSetLocalOrientation(rotation); } } //modifies scale? @@ -322,8 +326,8 @@ bool KX_IpoSGController::Update(double currentTime) if (m_ipo_add) { newScale = m_ipo_start_scale * newScale; } - - ob->SetLocalScale(newScale); + if (m_game_object) + m_game_object->NodeSetLocalScale(newScale); } m_modified=false; @@ -342,6 +346,7 @@ SG_Controller* KX_IpoSGController::GetReplica(class SG_Node* destnode) KX_IpoSGController* iporeplica = new KX_IpoSGController(*this); // clear object that ipo acts on in the replica. iporeplica->ClearObject(); + iporeplica->SetGameObject((KX_GameObject*)destnode->GetSGClientObject()); // dirty hack, ask Gino for a better solution in the ipo implementation // hacken en zagen, in what we call datahiding, not written for replication :( diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.h b/source/gameengine/Ketsji/KX_IPO_SGController.h index 031b74294ce..68a74c3a364 100644 --- a/source/gameengine/Ketsji/KX_IPO_SGController.h +++ b/source/gameengine/Ketsji/KX_IPO_SGController.h @@ -116,6 +116,12 @@ public: m_ipotime = time; m_modified = true; } + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_IpoSGController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__IPO_SGCONTROLLER_H diff --git a/source/gameengine/Ketsji/KX_IPhysicsController.cpp b/source/gameengine/Ketsji/KX_IPhysicsController.cpp index 5cd66efd965..673acabd774 100644 --- a/source/gameengine/Ketsji/KX_IPhysicsController.cpp +++ b/source/gameengine/Ketsji/KX_IPhysicsController.cpp @@ -35,9 +35,11 @@ #include "PHY_DynamicTypes.h" -KX_IPhysicsController::KX_IPhysicsController(bool dyna,void* userdata) +KX_IPhysicsController::KX_IPhysicsController(bool dyna, bool sensor, bool compound, void* userdata) : m_bDyna(dyna), + m_bSensor(sensor), + m_bCompound(compound), m_suspendDynamics(false), m_userdata(userdata) { diff --git a/source/gameengine/Ketsji/KX_IPhysicsController.h b/source/gameengine/Ketsji/KX_IPhysicsController.h index 4ea283e9f98..f9dcf81bca5 100644 --- a/source/gameengine/Ketsji/KX_IPhysicsController.h +++ b/source/gameengine/Ketsji/KX_IPhysicsController.h @@ -32,6 +32,7 @@ #include "SG_Controller.h" #include "MT_Vector3.h" #include "MT_Point3.h" +#include "MT_Transform.h" #include "MT_Matrix3x3.h" struct KX_ClientObjectInfo; @@ -48,10 +49,12 @@ class KX_IPhysicsController : public SG_Controller { protected: bool m_bDyna; + bool m_bSensor; + bool m_bCompound; bool m_suspendDynamics; void* m_userdata; public: - KX_IPhysicsController(bool dyna,void* userdata); + KX_IPhysicsController(bool dyna,bool sensor,bool compound, void* userdata); virtual ~KX_IPhysicsController(); @@ -72,12 +75,23 @@ public: virtual void getOrientation(MT_Quaternion& orn)=0; virtual void setOrientation(const MT_Matrix3x3& orn)=0; + virtual void SetTransform()=0; //virtual void setOrientation(const MT_Quaternion& orn)=0; virtual void setPosition(const MT_Point3& pos)=0; virtual void setScaling(const MT_Vector3& scaling)=0; virtual MT_Scalar GetMass()=0; + virtual void SetMass(MT_Scalar newmass)=0; + + virtual float GetLinVelocityMin()=0; + virtual void SetLinVelocityMin(float newmass)=0; + virtual float GetLinVelocityMax()=0; + virtual void SetLinVelocityMax(float newmass)=0; + + virtual MT_Vector3 GetLocalInertia()=0; virtual MT_Vector3 getReactionForce()=0; virtual void setRigidBody(bool rigid)=0; + virtual void AddCompoundChild(KX_IPhysicsController* child) = 0; + virtual void RemoveCompoundChild(KX_IPhysicsController* child) = 0; virtual void SuspendDynamics(bool ghost=false)=0; virtual void RestoreDynamics()=0; @@ -88,10 +102,22 @@ public: m_bDyna = isDynamic; } + void SetSensor(bool isSensor) { + m_bSensor = isSensor; + } + bool IsDyna(void) { return m_bDyna; } + bool IsSensor(void) { + return m_bSensor; + } + + bool IsCompound(void) { + return m_bCompound; + } + virtual MT_Scalar GetRadius()=0; virtual void SetSumoTransform(bool nondynaonly)=0; // todo: remove next line ! @@ -100,6 +126,13 @@ public: // call from scene graph to update virtual bool Update(double time)=0; void* GetUserData() { return m_userdata;} + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_IPhysicsController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_IPHYSICSCONTROLLER_H diff --git a/source/gameengine/Ketsji/KX_IScalarInterpolator.h b/source/gameengine/Ketsji/KX_IScalarInterpolator.h index 6ba685885e9..ec6183b88a1 100644 --- a/source/gameengine/Ketsji/KX_IScalarInterpolator.h +++ b/source/gameengine/Ketsji/KX_IScalarInterpolator.h @@ -29,11 +29,22 @@ #ifndef KX_ISCALARINTERPOLATOR_H #define KX_ISCALARINTERPOLATOR_H +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class KX_IScalarInterpolator { public: virtual ~KX_IScalarInterpolator() {} virtual float GetValue(float currentTime) const = 0; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_IScalarInterpolator"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Ketsji/KX_ISceneConverter.h b/source/gameengine/Ketsji/KX_ISceneConverter.h index 3709fa8c784..f098b0bebf5 100644 --- a/source/gameengine/Ketsji/KX_ISceneConverter.h +++ b/source/gameengine/Ketsji/KX_ISceneConverter.h @@ -32,6 +32,10 @@ #include "STR_String.h" #include "KX_Python.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + struct Scene; class KX_ISceneConverter @@ -47,10 +51,9 @@ public: destinationscene: pass an empty scene, everything goes into this dictobj: python dictionary (for pythoncontrollers) */ - virtual void ConvertScene(const STR_String& scenename, + virtual void ConvertScene( class KX_Scene* destinationscene, PyObject* dictobj, - class SCA_IInputDevice* keyinputdev, class RAS_IRenderTools* rendertools, class RAS_ICanvas* canvas)=0; @@ -81,6 +84,13 @@ public: virtual bool GetGLSLMaterials()=0; virtual struct Scene* GetBlenderSceneForName(const STR_String& name)=0; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_ISceneConverter"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_ISCENECONVERTER_H diff --git a/source/gameengine/Ketsji/KX_ISystem.h b/source/gameengine/Ketsji/KX_ISystem.h index 204e116e822..deee91f62e8 100644 --- a/source/gameengine/Ketsji/KX_ISystem.h +++ b/source/gameengine/Ketsji/KX_ISystem.h @@ -37,6 +37,10 @@ using namespace std; #include "STR_String.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + /** * System Abstraction, needed only for getting some timing stuff from the host. */ @@ -47,6 +51,13 @@ public: virtual ~KX_ISystem() {}; virtual double GetTimeInSeconds()=0; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_ISystem"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Ketsji/KX_IpoActuator.cpp b/source/gameengine/Ketsji/KX_IpoActuator.cpp index f5e17118ffb..b71907be961 100644 --- a/source/gameengine/Ketsji/KX_IpoActuator.cpp +++ b/source/gameengine/Ketsji/KX_IpoActuator.cpp @@ -49,13 +49,13 @@ /* Type strings */ /* ------------------------------------------------------------------------- */ -STR_String KX_IpoActuator::S_KX_ACT_IPO_PLAY_STRING = "Play"; -STR_String KX_IpoActuator::S_KX_ACT_IPO_PINGPONG_STRING = "PingPong"; -STR_String KX_IpoActuator::S_KX_ACT_IPO_FLIPPER_STRING = "Flipper"; -STR_String KX_IpoActuator::S_KX_ACT_IPO_LOOPSTOP_STRING = "LoopStop"; -STR_String KX_IpoActuator::S_KX_ACT_IPO_LOOPEND_STRING = "LoopEnd"; -STR_String KX_IpoActuator::S_KX_ACT_IPO_KEY2KEY_STRING = "Key2key"; -STR_String KX_IpoActuator::S_KX_ACT_IPO_FROM_PROP_STRING = "FromProp"; +const char *KX_IpoActuator::S_KX_ACT_IPO_PLAY_STRING = "Play"; +const char *KX_IpoActuator::S_KX_ACT_IPO_PINGPONG_STRING = "PingPong"; +const char *KX_IpoActuator::S_KX_ACT_IPO_FLIPPER_STRING = "Flipper"; +const char *KX_IpoActuator::S_KX_ACT_IPO_LOOPSTOP_STRING = "LoopStop"; +const char *KX_IpoActuator::S_KX_ACT_IPO_LOOPEND_STRING = "LoopEnd"; +const char *KX_IpoActuator::S_KX_ACT_IPO_KEY2KEY_STRING = "Key2key"; +const char *KX_IpoActuator::S_KX_ACT_IPO_FROM_PROP_STRING = "FromProp"; /* ------------------------------------------------------------------------- */ /* Native functions */ @@ -70,9 +70,8 @@ KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj, int acttype, bool ipo_as_force, bool ipo_add, - bool ipo_local, - PyTypeObject* T) - : SCA_IActuator(gameobj,T), + bool ipo_local) + : SCA_IActuator(gameobj), m_bNegativeEvent(false), m_startframe (starttime), m_endframe(endtime), @@ -84,7 +83,7 @@ KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj, m_ipo_as_force(ipo_as_force), m_ipo_add(ipo_add), m_ipo_local(ipo_local), - m_type((IpoActType)acttype) + m_type(acttype) { m_starttime = -2.0*fabs(m_endframe - m_startframe) - 1.0; m_bIpoPlaying = false; @@ -164,14 +163,14 @@ bool KX_IpoActuator::Update(double curtime, bool frame) // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! bool bNegativeEvent = false; - int numevents = 0; + bool numevents = false; bool bIpoStart = false; curtime -= KX_KetsjiEngine::GetSuspendedDelta(); if (frame) { - numevents = m_events.size(); + numevents = m_posevent || m_negevent; bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); } @@ -190,7 +189,7 @@ bool KX_IpoActuator::Update(double curtime, bool frame) } } - switch (m_type) + switch ((IpoActType)m_type) { case KX_ACT_IPO_PLAY: @@ -273,7 +272,7 @@ bool KX_IpoActuator::Update(double curtime, bool frame) { result = false; m_bNegativeEvent = false; - numevents = 0; + numevents = false; } if (!m_bIpoPlaying) { @@ -383,22 +382,22 @@ bool KX_IpoActuator::Update(double curtime, bool frame) return result; } -KX_IpoActuator::IpoActType KX_IpoActuator::string2mode(char* modename) { +int KX_IpoActuator::string2mode(char* modename) { IpoActType res = KX_ACT_IPO_NODEF; - if (modename == S_KX_ACT_IPO_PLAY_STRING) { + if (strcmp(modename, S_KX_ACT_IPO_PLAY_STRING)==0) { res = KX_ACT_IPO_PLAY; - } else if (modename == S_KX_ACT_IPO_PINGPONG_STRING) { + } else if (strcmp(modename, S_KX_ACT_IPO_PINGPONG_STRING)==0) { res = KX_ACT_IPO_PINGPONG; - } else if (modename == S_KX_ACT_IPO_FLIPPER_STRING) { + } else if (strcmp(modename, S_KX_ACT_IPO_FLIPPER_STRING)==0) { res = KX_ACT_IPO_FLIPPER; - } else if (modename == S_KX_ACT_IPO_LOOPSTOP_STRING) { + } else if (strcmp(modename, S_KX_ACT_IPO_LOOPSTOP_STRING)==0) { res = KX_ACT_IPO_LOOPSTOP; - } else if (modename == S_KX_ACT_IPO_LOOPEND_STRING) { + } else if (strcmp(modename, S_KX_ACT_IPO_LOOPEND_STRING)==0) { res = KX_ACT_IPO_LOOPEND; - } else if (modename == S_KX_ACT_IPO_KEY2KEY_STRING) { + } else if (strcmp(modename, S_KX_ACT_IPO_KEY2KEY_STRING)==0) { res = KX_ACT_IPO_KEY2KEY; - } else if (modename == S_KX_ACT_IPO_FROM_PROP_STRING) { + } else if (strcmp(modename, S_KX_ACT_IPO_FROM_PROP_STRING)==0) { res = KX_ACT_IPO_FROM_PROP; } @@ -413,282 +412,43 @@ KX_IpoActuator::IpoActType KX_IpoActuator::string2mode(char* modename) { /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_IpoActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_IpoActuator", - sizeof(KX_IpoActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_IpoActuator::Parents[] = { - &KX_IpoActuator::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_IpoActuator::Methods[] = { - {"set", (PyCFunction) KX_IpoActuator::sPySet, METH_VARARGS, (PY_METHODCHAR)Set_doc}, - {"setProperty", (PyCFunction) KX_IpoActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, - {"setStart", (PyCFunction) KX_IpoActuator::sPySetStart, METH_VARARGS, (PY_METHODCHAR)SetStart_doc}, - {"getStart", (PyCFunction) KX_IpoActuator::sPyGetStart, METH_NOARGS, (PY_METHODCHAR)GetStart_doc}, - {"setEnd", (PyCFunction) KX_IpoActuator::sPySetEnd, METH_VARARGS, (PY_METHODCHAR)SetEnd_doc}, - {"getEnd", (PyCFunction) KX_IpoActuator::sPyGetEnd, METH_NOARGS, (PY_METHODCHAR)GetEnd_doc}, - {"setIpoAsForce", (PyCFunction) KX_IpoActuator::sPySetIpoAsForce, METH_VARARGS, (PY_METHODCHAR)SetIpoAsForce_doc}, - {"getIpoAsForce", (PyCFunction) KX_IpoActuator::sPyGetIpoAsForce, METH_NOARGS, (PY_METHODCHAR)GetIpoAsForce_doc}, - {"setIpoAdd", (PyCFunction) KX_IpoActuator::sPySetIpoAdd, METH_VARARGS, (PY_METHODCHAR)SetIpoAdd_doc}, - {"getIpoAdd", (PyCFunction) KX_IpoActuator::sPyGetIpoAdd, METH_NOARGS, (PY_METHODCHAR)GetIpoAdd_doc}, - {"setType", (PyCFunction) KX_IpoActuator::sPySetType, METH_VARARGS, (PY_METHODCHAR)SetType_doc}, - {"getType", (PyCFunction) KX_IpoActuator::sPyGetType, METH_NOARGS, (PY_METHODCHAR)GetType_doc}, - {"setForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPySetForceIpoActsLocal, METH_VARARGS, (PY_METHODCHAR)SetForceIpoActsLocal_doc}, - {"getForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPyGetForceIpoActsLocal, METH_NOARGS, (PY_METHODCHAR)GetForceIpoActsLocal_doc}, {NULL,NULL} //Sentinel }; -PyObject* KX_IpoActuator::_getattr(const STR_String& attr) { - _getattr_up(SCA_IActuator); -} - - - -/* set --------------------------------------------------------------------- */ -const char KX_IpoActuator::Set_doc[] = -"set(type, startframe, endframe, mode?)\n" -"\t - type: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n" -"\t - startframe: first frame to use (int)\n" -"\t - endframe : last frame to use (int)\n" -"\t - mode? : special mode (0=normal, 1=interpret location as force, 2=additive)" -"\tSet the properties of the actuator.\n"; -PyObject* KX_IpoActuator::PySet(PyObject* self, - PyObject* args, - PyObject* kwds) { - /* sets modes PLAY, PINGPONG, FLIPPER, LOOPSTOP, LOOPEND */ - /* arg 1 = mode string, arg 2 = startframe, arg3 = stopframe, */ - /* arg4 = force toggle */ - char* mode; - int forceToggle; - IpoActType modenum; - int startFrame, stopFrame; - if(!PyArg_ParseTuple(args, "siii", &mode, &startFrame, - &stopFrame, &forceToggle)) { - return NULL; - } - modenum = string2mode(mode); - - switch (modenum) { - case KX_ACT_IPO_PLAY: - case KX_ACT_IPO_PINGPONG: - case KX_ACT_IPO_FLIPPER: - case KX_ACT_IPO_LOOPSTOP: - case KX_ACT_IPO_LOOPEND: - m_type = modenum; - m_startframe = startFrame; - m_endframe = stopFrame; - m_ipo_as_force = forceToggle == 1; - m_ipo_add = forceToggle == 2; - break; - default: - ; /* error */ - } - - Py_Return; -} - -/* set property ----------------------------------------------------------- */ -const char KX_IpoActuator::SetProperty_doc[] = -"setProperty(propname)\n" -"\t - propname: name of the property (string)\n" -"\tSet the property to be used in FromProp mode.\n"; -PyObject* KX_IpoActuator::PySetProperty(PyObject* self, - PyObject* args, - PyObject* kwds) { - /* mode is implicit here, but not supported yet... */ - /* args: property */ - char *propertyName; - if(!PyArg_ParseTuple(args, "s", &propertyName)) { - return NULL; - } - - m_propname = propertyName; - - Py_Return; -} - -/* 4. setStart: */ -const char KX_IpoActuator::SetStart_doc[] = -"setStart(frame)\n" -"\t - frame: first frame to use (int)\n" -"\tSet the frame from which the ipo starts playing.\n"; -PyObject* KX_IpoActuator::PySetStart(PyObject* self, - PyObject* args, - PyObject* kwds) { - float startArg; - if(!PyArg_ParseTuple(args, "f", &startArg)) { - return NULL; - } - - m_startframe = startArg; - - Py_Return; -} -/* 5. getStart: */ -const char KX_IpoActuator::GetStart_doc[] = -"getStart()\n" -"\tReturns the frame from which the ipo starts playing.\n"; -PyObject* KX_IpoActuator::PyGetStart(PyObject* self) { - return PyFloat_FromDouble(m_startframe); -} - -/* 6. setEnd: */ -const char KX_IpoActuator::SetEnd_doc[] = -"setEnd(frame)\n" -"\t - frame: last frame to use (int)\n" -"\tSet the frame at which the ipo stops playing.\n"; -PyObject* KX_IpoActuator::PySetEnd(PyObject* self, - PyObject* args, - PyObject* kwds) { - float endArg; - if(!PyArg_ParseTuple(args, "f", &endArg)) { - return NULL; - } - - m_endframe = endArg; - - Py_Return; -} -/* 7. getEnd: */ -const char KX_IpoActuator::GetEnd_doc[] = -"getEnd()\n" -"\tReturns the frame at which the ipo stops playing.\n"; -PyObject* KX_IpoActuator::PyGetEnd(PyObject* self) { - return PyFloat_FromDouble(m_endframe); -} - -/* 6. setIpoAsForce: */ -const char KX_IpoActuator::SetIpoAsForce_doc[] = -"setIpoAsForce(force?)\n" -"\t - force? : interpret this ipo as a force? (KX_TRUE, KX_FALSE)\n" -"\tSet whether to interpret the ipo as a force rather than a displacement.\n"; -PyObject* KX_IpoActuator::PySetIpoAsForce(PyObject* self, - PyObject* args, - PyObject* kwds) { - int boolArg; - - if (!PyArg_ParseTuple(args, "i", &boolArg)) { - return NULL; - } - - m_ipo_as_force = PyArgToBool(boolArg); - if (m_ipo_as_force) - m_ipo_add = false; - - Py_Return; -} -/* 7. getIpoAsForce: */ -const char KX_IpoActuator::GetIpoAsForce_doc[] = -"getIpoAsForce()\n" -"\tReturns whether to interpret the ipo as a force rather than a displacement.\n"; -PyObject* KX_IpoActuator::PyGetIpoAsForce(PyObject* self) { - return BoolToPyArg(m_ipo_as_force); -} - -/* 6. setIpoAsForce: */ -const char KX_IpoActuator::SetIpoAdd_doc[] = -"setIpoAdd(add?)\n" -"\t - add? : add flag (KX_TRUE, KX_FALSE)\n" -"\tSet whether to interpret the ipo as additive rather than absolute.\n"; -PyObject* KX_IpoActuator::PySetIpoAdd(PyObject* self, - PyObject* args, - PyObject* kwds) { - int boolArg; - - if (!PyArg_ParseTuple(args, "i", &boolArg)) { - return NULL; - } - - m_ipo_add = PyArgToBool(boolArg); - if (m_ipo_add) - m_ipo_as_force = false; - - Py_Return; -} -/* 7. getIpoAsForce: */ -const char KX_IpoActuator::GetIpoAdd_doc[] = -"getIpoAsAdd()\n" -"\tReturns whether to interpret the ipo as additive rather than absolute.\n"; -PyObject* KX_IpoActuator::PyGetIpoAdd(PyObject* self) { - return BoolToPyArg(m_ipo_add); -} - -/* 8. setType: */ -const char KX_IpoActuator::SetType_doc[] = -"setType(mode)\n" -"\t - mode: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n" -"\tSet the operation mode of the actuator.\n"; -PyObject* KX_IpoActuator::PySetType(PyObject* self, - PyObject* args, - PyObject* kwds) { - int typeArg; +PyAttributeDef KX_IpoActuator::Attributes[] = { + KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, 300000, KX_IpoActuator, m_startframe), + KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, 300000, KX_IpoActuator, m_endframe), + KX_PYATTRIBUTE_STRING_RW("propName", 0, 64, false, KX_IpoActuator, m_propname), + KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 64, false, KX_IpoActuator, m_framepropname), + KX_PYATTRIBUTE_INT_RW("mode", KX_ACT_IPO_NODEF+1, KX_ACT_IPO_MAX-1, true, KX_IpoActuator, m_type), + KX_PYATTRIBUTE_BOOL_RW("useIpoAsForce", KX_IpoActuator, m_ipo_as_force), + KX_PYATTRIBUTE_BOOL_RW("useIpoAdd", KX_IpoActuator, m_ipo_add), + KX_PYATTRIBUTE_BOOL_RW("useIpoLocal", KX_IpoActuator, m_ipo_local), + KX_PYATTRIBUTE_BOOL_RW("useChildren", KX_IpoActuator, m_recurse), - if (!PyArg_ParseTuple(args, "i", &typeArg)) { - return NULL; - } - - if ( (typeArg > KX_ACT_IPO_NODEF) - && (typeArg < KX_ACT_IPO_KEY2KEY) ) { - m_type = (IpoActType) typeArg; - } - - Py_Return; -} -/* 9. getType: */ -const char KX_IpoActuator::GetType_doc[] = -"getType()\n" -"\tReturns the operation mode of the actuator.\n"; -PyObject* KX_IpoActuator::PyGetType(PyObject* self) { - return PyInt_FromLong(m_type); -} - -/* 10. setForceIpoActsLocal: */ -const char KX_IpoActuator::SetForceIpoActsLocal_doc[] = -"setForceIpoActsLocal(local?)\n" -"\t - local? : Apply the ipo-as-force in the object's local\n" -"\t coordinates? (KX_TRUE, KX_FALSE)\n" -"\tSet whether to apply the force in the object's local\n" -"\tcoordinates rather than the world global coordinates.\n"; -PyObject* KX_IpoActuator::PySetForceIpoActsLocal(PyObject* self, - PyObject* args, - PyObject* kwds) { - int boolArg; - - if (!PyArg_ParseTuple(args, "i", &boolArg)) { - return NULL; - } - - m_ipo_local = PyArgToBool(boolArg); - - Py_Return; -} -/* 11. getForceIpoActsLocal: */ -const char KX_IpoActuator::GetForceIpoActsLocal_doc[] = -"getForceIpoActsLocal()\n" -"\tReturn whether to apply the force in the object's local\n" -"\tcoordinates rather than the world global coordinates.\n"; -PyObject* KX_IpoActuator::PyGetForceIpoActsLocal(PyObject* self) { - return BoolToPyArg(m_ipo_local); -} - + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/Ketsji/KX_IpoActuator.h b/source/gameengine/Ketsji/KX_IpoActuator.h index 8e5baed0530..72fe812f98e 100644 --- a/source/gameengine/Ketsji/KX_IpoActuator.h +++ b/source/gameengine/Ketsji/KX_IpoActuator.h @@ -100,17 +100,17 @@ public: KX_ACT_IPO_MAX }; - static STR_String S_KX_ACT_IPO_PLAY_STRING; - static STR_String S_KX_ACT_IPO_PINGPONG_STRING; - static STR_String S_KX_ACT_IPO_FLIPPER_STRING; - static STR_String S_KX_ACT_IPO_LOOPSTOP_STRING; - static STR_String S_KX_ACT_IPO_LOOPEND_STRING; - static STR_String S_KX_ACT_IPO_KEY2KEY_STRING; - static STR_String S_KX_ACT_IPO_FROM_PROP_STRING; - - IpoActType string2mode(char* modename); + static const char *S_KX_ACT_IPO_PLAY_STRING; + static const char *S_KX_ACT_IPO_PINGPONG_STRING; + static const char *S_KX_ACT_IPO_FLIPPER_STRING; + static const char *S_KX_ACT_IPO_LOOPSTOP_STRING; + static const char *S_KX_ACT_IPO_LOOPEND_STRING; + static const char *S_KX_ACT_IPO_KEY2KEY_STRING; + static const char *S_KX_ACT_IPO_FROM_PROP_STRING; + + int string2mode(char* modename); - IpoActType m_type; + int m_type; KX_IpoActuator(SCA_IObject* gameobj, const STR_String& propname, @@ -121,15 +121,12 @@ public: int acttype, bool ipo_as_force, bool ipo_add, - bool ipo_local, - PyTypeObject* T=&Type); + bool ipo_local); virtual ~KX_IpoActuator() {}; virtual CValue* GetReplica() { KX_IpoActuator* replica = new KX_IpoActuator(*this);//m_float,GetName()); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; }; @@ -140,24 +137,6 @@ public: /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - //KX_PYMETHOD_DOC - KX_PYMETHOD_DOC(KX_IpoActuator,Set); - KX_PYMETHOD_DOC(KX_IpoActuator,SetProperty); -/* KX_PYMETHOD_DOC(KX_IpoActuator,SetKey2Key); */ - KX_PYMETHOD_DOC(KX_IpoActuator,SetStart); - KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetStart); - KX_PYMETHOD_DOC(KX_IpoActuator,SetEnd); - KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetEnd); - KX_PYMETHOD_DOC(KX_IpoActuator,SetIpoAsForce); - KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetIpoAsForce); - KX_PYMETHOD_DOC(KX_IpoActuator,SetIpoAdd); - KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetIpoAdd); - KX_PYMETHOD_DOC(KX_IpoActuator,SetType); - KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetType); - KX_PYMETHOD_DOC(KX_IpoActuator,SetForceIpoActsLocal); - KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetForceIpoActsLocal); }; diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index b1ab8e3e7de..4117e493322 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -55,14 +55,13 @@ #include "KX_Scene.h" #include "MT_CmMatrix4x4.h" #include "KX_Camera.h" +#include "KX_Dome.h" #include "KX_Light.h" #include "KX_PythonInit.h" #include "KX_PyConstraintBinding.h" #include "PHY_IPhysicsEnvironment.h" -#include "SumoPhysicsEnvironment.h" -#include "SND_Scene.h" -#include "SND_IAudioDevice.h" +#include "AUD_C-API.h" #include "NG_NetworkScene.h" #include "NG_NetworkDeviceInterface.h" @@ -73,6 +72,8 @@ #include "RAS_FramingManager.h" #include "stdio.h" +#include "DNA_world_types.h" +#include "DNA_scene_types.h" // If define: little test for Nzc: guarded drawing. If the canvas is // not valid, skip rendering this frame. @@ -93,6 +94,8 @@ const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = { }; double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE; +int KX_KetsjiEngine::m_maxLogicFrame = 5; +int KX_KetsjiEngine::m_maxPhysicsFrame = 5; double KX_KetsjiEngine::m_anim_framerate = 25.0; double KX_KetsjiEngine::m_suspendedtime = 0.0; double KX_KetsjiEngine::m_suspendeddelta = 0.0; @@ -109,7 +112,6 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_rendertools(NULL), m_sceneconverter(NULL), m_networkdevice(NULL), - m_audiodevice(NULL), m_pythondictionary(NULL), m_keyboarddevice(NULL), m_mousedevice(NULL), @@ -158,7 +160,9 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_overrideFrameColor(false), m_overrideFrameColorR(0.0), m_overrideFrameColorG(0.0), - m_overrideFrameColorB(0.0) + m_overrideFrameColorB(0.0), + + m_usedome(false) { // Initialize the time logger m_logger = new KX_TimeCategoryLogger (25); @@ -176,6 +180,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) KX_KetsjiEngine::~KX_KetsjiEngine() { delete m_logger; + if(m_usedome) + delete m_dome; } @@ -203,15 +209,6 @@ void KX_KetsjiEngine::SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice) } - -void KX_KetsjiEngine::SetAudioDevice(SND_IAudioDevice* audiodevice) -{ - MT_assert(audiodevice); - m_audiodevice = audiodevice; -} - - - void KX_KetsjiEngine::SetCanvas(RAS_ICanvas* canvas) { MT_assert(canvas); @@ -253,7 +250,123 @@ void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter* sceneconverter) m_sceneconverter = sceneconverter; } +void KX_KetsjiEngine::InitDome(short res, short mode, short angle, float resbuf, short tilt, struct Text* text) +{ + m_dome = new KX_Dome(m_canvas, m_rasterizer, m_rendertools,this, res, mode, angle, resbuf, tilt, text); + m_usedome = true; +} + +void KX_KetsjiEngine::RenderDome() +{ + GLuint viewport[4]={0}; + glGetIntegerv(GL_VIEWPORT,(GLint *)viewport); + + m_dome->SetViewPort(viewport); + + KX_Scene* firstscene = *m_scenes.begin(); + const RAS_FrameSettings &framesettings = firstscene->GetFramingType(); + + m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); + + // hiding mouse cursor each frame + // (came back when going out of focus and then back in again) + if (m_hideCursor) + m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); + + // clear the entire game screen with the border color + // only once per frame + + m_canvas->BeginDraw(); + + // BeginFrame() sets the actual drawing area. You can use a part of the window + if (!BeginFrame()) + return; + + KX_SceneList::iterator sceneit; + + int n_renders=m_dome->GetNumberRenders();// usually 4 or 6 + for (int i=0;i<n_renders;i++){ + m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER); + for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) + // for each scene, call the proceed functions + { + KX_Scene* scene = *sceneit; + KX_Camera* cam = scene->GetActiveCamera(); + + m_rendertools->BeginFrame(m_rasterizer); + // pass the scene's worldsettings to the rasterizer + SetWorldSettings(scene->GetWorldInfo()); + + // shadow buffers + if (i == 0){ + RenderShadowBuffers(scene); + } + // Avoid drawing the scene with the active camera twice when it's viewport is enabled + if(cam && !cam->GetViewport()) + { + if (scene->IsClearingZBuffer()) + m_rasterizer->ClearDepthBuffer(); + + m_rendertools->SetAuxilaryClientInfo(scene); + + // do the rendering + m_dome->RenderDomeFrame(scene,cam, i); + } + + list<class KX_Camera*>* cameras = scene->GetCameras(); + + // Draw the scene once for each camera with an enabled viewport + list<KX_Camera*>::iterator it = cameras->begin(); + while(it != cameras->end()) + { + if((*it)->GetViewport()) + { + if (scene->IsClearingZBuffer()) + m_rasterizer->ClearDepthBuffer(); + + m_rendertools->SetAuxilaryClientInfo(scene); + + // do the rendering + m_dome->RenderDomeFrame(scene, (*it),i); + } + + it++; + } + } + m_dome->BindImages(i); + } + + m_canvas->EndFrame();//XXX do we really need that? + + m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight()); + + if (m_overrideFrameColor) //XXX why do we want + { + // Do not use the framing bar color set in the Blender scenes + m_canvas->ClearColor( + m_overrideFrameColorR, + m_overrideFrameColorG, + m_overrideFrameColorB, + 1.0 + ); + } + else + { + // Use the framing bar color set in the Blender scenes + m_canvas->ClearColor( + framesettings.BarRed(), + framesettings.BarGreen(), + framesettings.BarBlue(), + 1.0 + ); + } + m_dome->Draw(); + + // run the 2dfilters and motion blur once for all the scenes + PostRenderFrame(); + EndFrame(); +} /** * Ketsji Init(), Initializes datastructures and converts data from @@ -268,7 +381,20 @@ void KX_KetsjiEngine::StartEngine(bool clearIpo) m_firstframe = true; m_bInitialized = true; - m_ticrate = DEFAULT_LOGIC_TIC_RATE; + // there is always one scene enabled at startup + Scene* scene = m_scenes[0]->GetBlenderScene(); + if (scene) + { + m_ticrate = scene->gm.ticrate ? scene->gm.ticrate : DEFAULT_LOGIC_TIC_RATE; + m_maxLogicFrame = scene->gm.maxlogicstep ? scene->gm.maxlogicstep : 5; + m_maxPhysicsFrame = scene->gm.maxphystep ? scene->gm.maxlogicstep : 5; + } + else + { + m_ticrate = DEFAULT_LOGIC_TIC_RATE; + m_maxLogicFrame = 5; + m_maxPhysicsFrame = 5; + } if (m_game2ipo) { @@ -381,7 +507,8 @@ void KX_KetsjiEngine::EndFrame() bool KX_KetsjiEngine::NextFrame() { - + double timestep = 1.0/m_ticrate; + double framestep = timestep; // static hidden::Clock sClock; m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(),true); @@ -390,7 +517,7 @@ m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(),true); //sClock.reset(); if (m_bFixedTime) - m_clockTime += 1./m_ticrate; + m_clockTime += timestep; else { @@ -409,7 +536,7 @@ else // Compute the number of logic frames to do each update (fixed tic bricks) - int frames =int(deltatime*m_ticrate); + int frames =int(deltatime*m_ticrate+1e-6); // if (frames>1) // printf("****************************************"); // printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames); @@ -418,24 +545,29 @@ else // PIL_sleep_ms(1); KX_SceneList::iterator sceneit; - int frameOut = 5; - if (frames>frameOut) + if (frames>m_maxPhysicsFrame) { // printf("framedOut: %d\n",frames); - m_frameTime+=(frames-frameOut)*(1.0/m_ticrate); - frames = frameOut; + m_frameTime+=(frames-m_maxPhysicsFrame)*timestep; + frames = m_maxPhysicsFrame; } bool doRender = frames>0; + if (frames > m_maxLogicFrame) + { + framestep = (frames*timestep)/m_maxLogicFrame; + frames = m_maxLogicFrame; + } + while (frames) { - m_frameTime += 1.0/m_ticrate; + m_frameTime += framestep; for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit) // for each scene, call the proceed functions @@ -462,52 +594,62 @@ else m_logger->StartLog(tc_network, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_NETWORK); scene->GetNetworkScene()->proceed(m_frameTime); - m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); - scene->UpdateParents(m_frameTime); + //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); + //SG_SetActiveStage(SG_STAGE_NETWORK_UPDATE); + //scene->UpdateParents(m_frameTime); m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_PHYSICS1); // set Python hooks for each scene PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); - PHY_SetActiveScene(scene); + KX_SetActiveScene(scene); scene->GetPhysicsEnvironment()->endFrame(); // Update scenegraph after physics step. This maps physics calculations // into node positions. - m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); - scene->UpdateParents(m_frameTime); + //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); + //SG_SetActiveStage(SG_STAGE_PHYSICS1_UPDATE); + //scene->UpdateParents(m_frameTime); // Process sensors, and controllers m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_CONTROLLER); scene->LogicBeginFrame(m_frameTime); // Scenegraph needs to be updated again, because Logic Controllers // can affect the local matrices. m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_CONTROLLER_UPDATE); scene->UpdateParents(m_frameTime); // Process actuators // Do some cleanup work for this logic frame m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_ACTUATOR); scene->LogicUpdateFrame(m_frameTime, true); scene->LogicEndFrame(); // Actuators can affect the scenegraph m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE); scene->UpdateParents(m_frameTime); m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_PHYSICS2); scene->GetPhysicsEnvironment()->beginFrame(); // Perform physics calculations on the scene. This can involve // many iterations of the physics solver. - scene->GetPhysicsEnvironment()->proceedDeltaTime(m_frameTime,1.0/m_ticrate);//m_deltatimerealDeltaTime); + scene->GetPhysicsEnvironment()->proceedDeltaTime(m_frameTime,timestep,framestep);//m_deltatimerealDeltaTime); m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_PHYSICS2_UPDATE); scene->UpdateParents(m_frameTime); @@ -537,10 +679,7 @@ else if (m_networkdevice) m_networkdevice->NextFrame(); - - if (m_audiodevice) - m_audiodevice->NextFrame(); - + // scene management ProcessScheduledScenes(); @@ -568,18 +707,20 @@ else // set Python hooks for each scene PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); - PHY_SetActiveScene(scene); + KX_SetActiveScene(scene); m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_PHYSICS1); scene->UpdateParents(m_clockTime); // Perform physics calculations on the scene. This can involve // many iterations of the physics solver. m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); - scene->GetPhysicsEnvironment()->proceedDeltaTime(m_clockTime,0.f); + scene->GetPhysicsEnvironment()->proceedDeltaTime(m_clockTime,timestep,timestep); // Update scenegraph after physics step. This maps physics calculations // into node positions. m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_PHYSICS2); scene->UpdateParents(m_clockTime); // Do some cleanup work for this logic frame @@ -588,6 +729,7 @@ else // Actuators can affect the scenegraph m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_ACTUATOR); scene->UpdateParents(m_clockTime); scene->setSuspendedTime(0.0); @@ -615,10 +757,15 @@ else void KX_KetsjiEngine::Render() { + if(m_usedome){ + RenderDome(); + return; + } KX_Scene* firstscene = *m_scenes.begin(); const RAS_FrameSettings &framesettings = firstscene->GetFramingType(); m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_RENDER); // hiding mouse cursor each frame // (came back when going out of focus and then back in again) @@ -669,6 +816,9 @@ void KX_KetsjiEngine::Render() // pass the scene's worldsettings to the rasterizer SetWorldSettings(scene->GetWorldInfo()); + // this is now done incrementatlly in KX_Scene::CalculateVisibleMeshes + //scene->UpdateMeshTransformations(); + // shadow buffers RenderShadowBuffers(scene); @@ -713,7 +863,7 @@ void KX_KetsjiEngine::Render() if (!BeginFrame()) return; - KX_SceneList::iterator sceneit; + for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) // for each scene, call the proceed functions { @@ -732,6 +882,26 @@ void KX_KetsjiEngine::Render() // do the rendering //RenderFrame(scene); RenderFrame(scene, cam); + + list<class KX_Camera*>* cameras = scene->GetCameras(); + + // Draw the scene once for each camera with an enabled viewport + list<KX_Camera*>::iterator it = cameras->begin(); + while(it != cameras->end()) + { + if((*it)->GetViewport()) + { + if (scene->IsClearingZBuffer()) + m_rasterizer->ClearDepthBuffer(); + + m_rendertools->SetAuxilaryClientInfo(scene); + + // do the rendering + RenderFrame(scene, (*it)); + } + + it++; + } } } // if(m_rasterizer->Stereo()) @@ -786,13 +956,40 @@ void KX_KetsjiEngine::DoSound(KX_Scene* scene) MT_Vector3 listenervelocity = cam->GetLinearVelocity(); MT_Matrix3x3 listenerorientation = cam->NodeGetWorldOrientation(); - SND_Scene* soundscene = scene->GetSoundScene(); - soundscene->SetListenerTransform( - listenerposition, - listenervelocity, - listenerorientation); + { + AUD_3DData data; + float f; + + listenerorientation.getValue3x3(data.orientation); + listenerposition.getValue(data.position); + listenervelocity.getValue(data.velocity); + + f = data.position[1]; + data.position[1] = data.position[2]; + data.position[2] = -f; + + f = data.velocity[1]; + data.velocity[1] = data.velocity[2]; + data.velocity[2] = -f; + + f = data.orientation[1]; + data.orientation[1] = data.orientation[2]; + data.orientation[2] = -f; + + f = data.orientation[3]; + data.orientation[3] = -data.orientation[6]; + data.orientation[6] = f; + + f = data.orientation[4]; + data.orientation[4] = -data.orientation[8]; + data.orientation[8] = -f; + + f = data.orientation[5]; + data.orientation[5] = data.orientation[7]; + data.orientation[7] = f; - soundscene->Proceed(); + AUD_updateListener(&data); + } } @@ -826,7 +1023,7 @@ void KX_KetsjiEngine::SetWorldSettings(KX_WorldInfo* wi) wi->getAmbientColorBlue() ); - if (m_drawingmode == RAS_IRasterizer::KX_TEXTURED) + if (m_drawingmode >= RAS_IRasterizer::KX_SOLID) { if (wi->hasMist()) { @@ -838,10 +1035,6 @@ void KX_KetsjiEngine::SetWorldSettings(KX_WorldInfo* wi) wi->getMistColorBlue() ); } - else - { - m_rasterizer->DisableFog(); - } } } } @@ -894,6 +1087,11 @@ void KX_KetsjiEngine::SetCameraOverrideClipping(float near, float far) m_overrideCamFar = far; } +void KX_KetsjiEngine::SetCameraOverrideLens(float lens) +{ + m_overrideCamLens = lens; +} + void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport) { // In this function we make sure the rasterizer settings are upto @@ -923,7 +1121,7 @@ void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect area = userviewport; } - else if ( m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho ) { + else if ( !m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho ) { RAS_FramingManager::ComputeViewport( scene->GetFramingType(), m_canvas->GetDisplayArea(), @@ -943,16 +1141,13 @@ void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) { - CListValue *objectlist = scene->GetObjectList(); + CListValue *lightlist = scene->GetLightList(); int i, drawmode; m_rendertools->SetAuxilaryClientInfo(scene); - for(i=0; i<objectlist->GetCount(); i++) { - KX_GameObject *gameobj = (KX_GameObject*)objectlist->GetValue(i); - - if(!gameobj->IsLight()) - continue; + for(i=0; i<lightlist->GetCount(); i++) { + KX_GameObject *gameobj = (KX_GameObject*)lightlist->GetValue(i); KX_LightObject *light = (KX_LightObject*)gameobj; @@ -961,7 +1156,7 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) if(m_drawingmode == RAS_IRasterizer::KX_TEXTURED && light->HasShadowBuffer()) { /* make temporary camera */ RAS_CameraData camdata = RAS_CameraData(); - KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, false); + KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, true, true); cam->SetName("__shadow__cam__"); MT_Transform camtrans; @@ -974,7 +1169,6 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) light->BindShadowBuffer(m_rasterizer, cam, camtrans); /* update scene */ - scene->UpdateMeshTransformations(); scene->CalculateVisibleMeshes(m_rasterizer, cam, light->GetShadowLayer()); /* render */ @@ -994,13 +1188,11 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) { bool override_camera; RAS_Rect viewport, area; - float left, right, bottom, top, nearfrust, farfrust, focallength; - const float ortho = 100.0; + float nearfrust, farfrust, focallength; // KX_Camera* cam = scene->GetActiveCamera(); if (!cam) return; - GetSceneViewport(scene, cam, area, viewport); // store the computed viewport in the scene @@ -1018,19 +1210,24 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) override_camera = override_camera && (cam->GetName() == "__default__cam__"); if (override_camera && m_overrideCamUseOrtho) { - MT_CmMatrix4x4 projmat = m_overrideCamProjMat; - m_rasterizer->SetProjectionMatrix(projmat); + m_rasterizer->SetProjectionMatrix(m_overrideCamProjMat); + if (!cam->hasValidProjectionMatrix()) { + // needed to get frustrum planes for culling + MT_Matrix4x4 projmat; + projmat.setValue(m_overrideCamProjMat.getPointer()); + cam->SetProjectionMatrix(projmat); + } } else if (cam->hasValidProjectionMatrix() && !cam->GetViewport() ) { m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix()); } else { RAS_FrameFrustum frustum; - float lens = cam->GetLens(); bool orthographic = !cam->GetCameraData()->m_perspective; nearfrust = cam->GetCameraNear(); farfrust = cam->GetCameraFar(); focallength = cam->GetFocalLength(); + MT_Matrix4x4 projmat; if(override_camera) { nearfrust = m_overrideCamNear; @@ -1038,66 +1235,86 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) } if (orthographic) { - lens *= ortho; - nearfrust = (nearfrust + 1.0)*ortho; - farfrust *= ortho; - } - - RAS_FramingManager::ComputeFrustum( - scene->GetFramingType(), - area, - viewport, - lens, - nearfrust, - farfrust, - frustum - ); - left = frustum.x1 * m_cameraZoom; - right = frustum.x2 * m_cameraZoom; - bottom = frustum.y1 * m_cameraZoom; - top = frustum.y2 * m_cameraZoom; - nearfrust = frustum.camnear; - farfrust = frustum.camfar; + RAS_FramingManager::ComputeOrtho( + scene->GetFramingType(), + area, + viewport, + cam->GetScale(), + nearfrust, + farfrust, + frustum + ); + if (!cam->GetViewport()) { + frustum.x1 *= m_cameraZoom; + frustum.x2 *= m_cameraZoom; + frustum.y1 *= m_cameraZoom; + frustum.y2 *= m_cameraZoom; + } + projmat = m_rasterizer->GetOrthoMatrix( + frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar); - MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix( - left, right, bottom, top, nearfrust, farfrust, focallength); + } else { + RAS_FramingManager::ComputeFrustum( + scene->GetFramingType(), + area, + viewport, + cam->GetLens(), + nearfrust, + farfrust, + frustum + ); + if (!cam->GetViewport()) { + frustum.x1 *= m_cameraZoom; + frustum.x2 *= m_cameraZoom; + frustum.y1 *= m_cameraZoom; + frustum.y2 *= m_cameraZoom; + } + projmat = m_rasterizer->GetFrustumMatrix( + frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar, focallength); + } cam->SetProjectionMatrix(projmat); // Otherwise the projection matrix for each eye will be the same... - if (m_rasterizer->Stereo()) + if (!orthographic && m_rasterizer->Stereo()) cam->InvalidateProjectionMatrix(); } MT_Transform camtrans(cam->GetWorldToCamera()); - if (!cam->GetCameraData()->m_perspective) - camtrans.getOrigin()[2] *= ortho; MT_Matrix4x4 viewmat(camtrans); - m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(), - cam->GetCameraLocation(), cam->GetCameraOrientation()); + m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective); cam->SetModelviewMatrix(viewmat); - scene->UpdateMeshTransformations(); - // The following actually reschedules all vertices to be // redrawn. There is a cache between the actual rescheduling // and this call though. Visibility is imparted when this call // runs through the individual objects. + + m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_CULLING); + scene->CalculateVisibleMeshes(m_rasterizer,cam); + m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_RENDER); + scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools); + if (scene->GetPhysicsEnvironment()) + scene->GetPhysicsEnvironment()->debugDrawWorld(); + + m_rasterizer->FlushDebugLines(); + + //it's running once for every scene (i.e. overlay scenes have it running twice). That's not the ideal. PostRenderFrame(); } void KX_KetsjiEngine::PostRenderFrame() { - m_rendertools->PushMatrix(); m_rendertools->Render2DFilters(m_canvas); m_rendertools->MotionBlur(m_rasterizer); - m_rendertools->PopMatrix(); } void KX_KetsjiEngine::StopEngine() @@ -1138,15 +1355,19 @@ void KX_KetsjiEngine::AddScene(KX_Scene* scene) void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene) { bool override_camera = (m_overrideCam && (scene->GetName() == m_overrideSceneName)); - - // if there is no activecamera, or the camera is being - // overridden we need to construct a temporarily camera + + SG_SetActiveStage(SG_STAGE_SCENE); + + // if there is no activecamera, or the camera is being + // overridden we need to construct a temporarily camera if (!scene->GetActiveCamera() || override_camera) { KX_Camera* activecam = NULL; RAS_CameraData camdata = RAS_CameraData(); - activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata, false); + if (override_camera) camdata.m_lens = m_overrideCamLens; + + activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata); activecam->SetName("__default__cam__"); // set transformation @@ -1158,11 +1379,11 @@ void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene) activecam->NodeSetLocalPosition(camtrans.getOrigin()); activecam->NodeSetLocalOrientation(camtrans.getBasis()); - activecam->NodeUpdateGS(0,true); + activecam->NodeUpdateGS(0); } else { activecam->NodeSetLocalPosition(MT_Point3(0.0, 0.0, 0.0)); activecam->NodeSetLocalOrientation(MT_Vector3(0.0, 0.0, 0.0)); - activecam->NodeUpdateGS(0,true); + activecam->NodeUpdateGS(0); } scene->AddCamera(activecam); @@ -1217,7 +1438,7 @@ void KX_KetsjiEngine::RenderDebugProperties() m_canvas->GetWidth(), m_canvas->GetHeight()); double time = m_logger->GetAverage((KX_TimeCategory)j); - debugtxt.Format("%2.2f %%", time/tottime * 100.f); + debugtxt.Format("%.3fms (%2.2f %%)", time*1000.f, time/tottime * 100.f); m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, debugtxt.Ptr(), xcoord + 60 ,ycoord, @@ -1387,14 +1608,11 @@ KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename) KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice, m_mousedevice, m_networkdevice, - m_audiodevice, scenename, scene); - m_sceneconverter->ConvertScene(scenename, - tmpscene, + m_sceneconverter->ConvertScene(tmpscene, m_pythondictionary, - m_keyboarddevice, m_rendertools, m_canvas); @@ -1535,11 +1753,41 @@ void KX_KetsjiEngine::SetTicRate(double ticrate) m_ticrate = ticrate; } +int KX_KetsjiEngine::GetMaxLogicFrame() +{ + return m_maxLogicFrame; +} + +void KX_KetsjiEngine::SetMaxLogicFrame(int frame) +{ + m_maxLogicFrame = frame; +} + +int KX_KetsjiEngine::GetMaxPhysicsFrame() +{ + return m_maxPhysicsFrame; +} + +void KX_KetsjiEngine::SetMaxPhysicsFrame(int frame) +{ + m_maxPhysicsFrame = frame; +} + double KX_KetsjiEngine::GetAnimFrameRate() { return m_anim_framerate; } +double KX_KetsjiEngine::GetClockTime(void) const +{ + return m_clockTime; +} + +double KX_KetsjiEngine::GetRealTime(void) const +{ + return m_kxsystem->GetTimeInSeconds(); +} + void KX_KetsjiEngine::SetAnimFrameRate(double framerate) { m_anim_framerate = framerate; @@ -1642,4 +1890,3 @@ void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const } - diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index 1aa067a9962..acb9e53df8a 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -70,10 +70,10 @@ private: class RAS_IRenderTools* m_rendertools; class KX_ISceneConverter* m_sceneconverter; class NG_NetworkDeviceInterface* m_networkdevice; - class SND_IAudioDevice* m_audiodevice; PyObject* m_pythondictionary; class SCA_IInputDevice* m_keyboarddevice; class SCA_IInputDevice* m_mousedevice; + class KX_Dome* m_dome; // dome stereo mode /** Lists of scenes scheduled to be removed at the end of the frame. */ std::set<STR_String> m_removingScenes; @@ -102,6 +102,8 @@ private: double m_previousClockTime;//previous clock time double m_remainingTime; + static int m_maxLogicFrame; /* maximum number of consecutive logic frame */ + static int m_maxPhysicsFrame; /* maximum number of consecutive physics frame */ static double m_ticrate; static double m_anim_framerate; /* for animation playback only - ipo and action */ @@ -126,6 +128,7 @@ private: MT_CmMatrix4x4 m_overrideCamViewMat; float m_overrideCamNear; float m_overrideCamFar; + float m_overrideCamLens; bool m_stereo; int m_curreye; @@ -184,19 +187,17 @@ private: void RenderDebugProperties(); void RenderShadowBuffers(KX_Scene *scene); void SetBackGround(KX_WorldInfo* worldinfo); - void SetWorldSettings(KX_WorldInfo* worldinfo); void DoSound(KX_Scene* scene); public: - KX_KetsjiEngine(class KX_ISystem* system); virtual ~KX_KetsjiEngine(); // set the devices and stuff. the client must take care of creating these + void SetWorldSettings(KX_WorldInfo* worldinfo); void SetKeyboardDevice(SCA_IInputDevice* keyboarddevice); void SetMouseDevice(SCA_IInputDevice* mousedevice); void SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice); - void SetAudioDevice(SND_IAudioDevice* audiodevice); void SetCanvas(RAS_ICanvas* canvas); void SetRenderTools(RAS_IRenderTools* rendertools); void SetRasterizer(RAS_IRasterizer* rasterizer); @@ -205,6 +206,14 @@ public: void SetGame2IpoMode(bool game2ipo,int startFrame); RAS_IRasterizer* GetRasterizer(){return m_rasterizer;}; + RAS_ICanvas* GetCanvas(){return m_canvas;}; + RAS_IRenderTools* GetRenderTools(){return m_rendertools;}; + + /// Dome functions + void InitDome(short res, short mode, short angle, float resbuf, short tilt, struct Text* text); + void EndDome(); + void RenderDome(); + bool m_usedome; ///returns true if an update happened to indicate -> Render bool NextFrame(); @@ -232,6 +241,8 @@ public: void GetSceneViewport(KX_Scene* scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport); void SetDrawType(int drawingtype); + int GetDrawType(){return m_drawingmode;}; + void SetCameraZoom(float camzoom); void EnableCameraOverride(const STR_String& forscene); @@ -240,6 +251,7 @@ public: void SetCameraOverrideProjectionMatrix(const MT_CmMatrix4x4& mat); void SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat); void SetCameraOverrideClipping(float near, float far); + void SetCameraOverrideLens(float lens); /** * Sets display of all frames. @@ -254,6 +266,12 @@ public: bool GetUseFixedTime(void) const; /** + * Returns current render frame clock time + */ + double GetClockTime(void) const; + + double GetRealTime(void) const; + /** * Returns the difference between the local time of the scene (when it * was running and not suspended) and the "curtime" */ @@ -267,6 +285,22 @@ public: * Sets the number of logic updates per second. */ static void SetTicRate(double ticrate); + /** + * Gets the maximum number of logic frame before render frame + */ + static int GetMaxLogicFrame(); + /** + * Sets the maximum number of logic frame before render frame + */ + static void SetMaxLogicFrame(int frame); + /** + * Gets the maximum number of physics frame before render frame + */ + static int GetMaxPhysicsFrame(); + /** + * Sets the maximum number of physics frame before render frame + */ + static void SetMaxPhysicsFrame(int frame); /** * Gets the framerate for playing animations. (actions and ipos) @@ -361,6 +395,13 @@ protected: bool BeginFrame(); void ClearFrame(); void EndFrame(); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_KetsjiEngine"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_KETSJI_ENGINE diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp index e0f171e78e0..85c495bc2bd 100644 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ b/source/gameengine/Ketsji/KX_Light.cpp @@ -35,6 +35,8 @@ #pragma warning (disable : 4786) #endif +#include "GL/glew.h" + #include "KX_Light.h" #include "KX_Camera.h" #include "RAS_IRasterizer.h" @@ -43,20 +45,19 @@ #include "KX_PyMath.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "GPU_material.h" KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks, class RAS_IRenderTools* rendertools, const RAS_LightObject& lightobj, - bool glsl, - PyTypeObject* T - ) - : - KX_GameObject(sgReplicationInfo,callbacks,T), - m_rendertools(rendertools) + bool glsl) + : KX_GameObject(sgReplicationInfo,callbacks), + m_rendertools(rendertools) { m_lightobj = lightobj; - m_lightobj.m_worldmatrix = GetOpenGLMatrixPtr(); + m_lightobj.m_scene = sgReplicationInfo; + m_lightobj.m_light = this; m_rendertools->AddLight(&m_lightobj); m_glsl = glsl; m_blenderscene = ((KX_Scene*)sgReplicationInfo)->GetBlenderScene(); @@ -81,17 +82,104 @@ CValue* KX_LightObject::GetReplica() KX_LightObject* replica = new KX_LightObject(*this); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - - ProcessReplica(replica); + replica->ProcessReplica(); - replica->m_lightobj.m_worldmatrix = replica->GetOpenGLMatrixPtr(); + replica->m_lightobj.m_light = replica; m_rendertools->AddLight(&replica->m_lightobj); return replica; } +bool KX_LightObject::ApplyLight(KX_Scene *kxscene, int oblayer, int slot) +{ + KX_Scene* lightscene = (KX_Scene*)m_lightobj.m_scene; + float vec[4]; + int scenelayer = ~0; + + if(kxscene && kxscene->GetBlenderScene()) + scenelayer = kxscene->GetBlenderScene()->lay; + + /* only use lights in the same layer as the object */ + if(!(m_lightobj.m_layer & oblayer)) + return false; + /* only use lights in the same scene, and in a visible layer */ + if(kxscene != lightscene || !(m_lightobj.m_layer & scenelayer)) + return false; + + // lights don't get their openGL matrix updated, do it now + if(GetSGNode()->IsDirty()) + GetOpenGLMatrix(); + + MT_CmMatrix4x4& worldmatrix= *GetOpenGLMatrixPtr(); + + vec[0] = worldmatrix(0,3); + vec[1] = worldmatrix(1,3); + vec[2] = worldmatrix(2,3); + vec[3] = 1.0f; + + if(m_lightobj.m_type==RAS_LightObject::LIGHT_SUN) { + + vec[0] = worldmatrix(0,2); + vec[1] = worldmatrix(1,2); + vec[2] = worldmatrix(2,2); + //vec[0]= base->object->obmat[2][0]; + //vec[1]= base->object->obmat[2][1]; + //vec[2]= base->object->obmat[2][2]; + vec[3]= 0.0; + glLightfv((GLenum)(GL_LIGHT0+slot), GL_POSITION, vec); + } + else { + //vec[3]= 1.0; + glLightfv((GLenum)(GL_LIGHT0+slot), GL_POSITION, vec); + glLightf((GLenum)(GL_LIGHT0+slot), GL_CONSTANT_ATTENUATION, 1.0); + glLightf((GLenum)(GL_LIGHT0+slot), GL_LINEAR_ATTENUATION, m_lightobj.m_att1/m_lightobj.m_distance); + // without this next line it looks backward compatible. + //attennuation still is acceptable + glLightf((GLenum)(GL_LIGHT0+slot), GL_QUADRATIC_ATTENUATION, m_lightobj.m_att2/(m_lightobj.m_distance*m_lightobj.m_distance)); + + if(m_lightobj.m_type==RAS_LightObject::LIGHT_SPOT) { + vec[0] = -worldmatrix(0,2); + vec[1] = -worldmatrix(1,2); + vec[2] = -worldmatrix(2,2); + //vec[0]= -base->object->obmat[2][0]; + //vec[1]= -base->object->obmat[2][1]; + //vec[2]= -base->object->obmat[2][2]; + glLightfv((GLenum)(GL_LIGHT0+slot), GL_SPOT_DIRECTION, vec); + glLightf((GLenum)(GL_LIGHT0+slot), GL_SPOT_CUTOFF, m_lightobj.m_spotsize/2.0); + glLightf((GLenum)(GL_LIGHT0+slot), GL_SPOT_EXPONENT, 128.0*m_lightobj.m_spotblend); + } + else + glLightf((GLenum)(GL_LIGHT0+slot), GL_SPOT_CUTOFF, 180.0); + } + + if (m_lightobj.m_nodiffuse) { + vec[0] = vec[1] = vec[2] = vec[3] = 0.0; + } + else { + vec[0]= m_lightobj.m_energy*m_lightobj.m_red; + vec[1]= m_lightobj.m_energy*m_lightobj.m_green; + vec[2]= m_lightobj.m_energy*m_lightobj.m_blue; + vec[3]= 1.0; + } + + glLightfv((GLenum)(GL_LIGHT0+slot), GL_DIFFUSE, vec); + if(m_lightobj.m_nospecular) + { + vec[0] = vec[1] = vec[2] = vec[3] = 0.0; + } + else if (m_lightobj.m_nodiffuse) { + vec[0]= m_lightobj.m_energy*m_lightobj.m_red; + vec[1]= m_lightobj.m_energy*m_lightobj.m_green; + vec[2]= m_lightobj.m_energy*m_lightobj.m_blue; + vec[3]= 1.0; + } + + glLightfv((GLenum)(GL_LIGHT0+slot), GL_SPECULAR, vec); + glEnable((GLenum)(GL_LIGHT0+slot)); + + return true; +} + GPULamp *KX_LightObject::GetGPULamp() { if(m_glsl) @@ -104,8 +192,11 @@ void KX_LightObject::Update() { GPULamp *lamp; - if((lamp = GetGPULamp())) { + if((lamp = GetGPULamp()) != NULL && GetSGNode()) { float obmat[4][4]; + // lights don't get their openGL matrix updated, do it now + if (GetSGNode()->IsDirty()) + GetOpenGLMatrix(); double *dobmat = GetOpenGLMatrixPtr()->getPointer(); for(int i=0; i<4; i++) @@ -113,6 +204,8 @@ void KX_LightObject::Update() obmat[i][j] = (float)*dobmat; GPU_lamp_update(lamp, m_lightobj.m_layer, obmat); + GPU_lamp_update_colors(lamp, m_lightobj.m_red, m_lightobj.m_green, + m_lightobj.m_blue, m_lightobj.m_energy); } } @@ -158,12 +251,11 @@ void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_T cam->NodeSetLocalPosition(camtrans.getOrigin()); cam->NodeSetLocalOrientation(camtrans.getBasis()); - cam->NodeUpdateGS(0,true); + cam->NodeUpdateGS(0); /* setup rasterizer transformations */ ras->SetProjectionMatrix(projectionmat); - ras->SetViewMatrix(modelviewmat, cam->NodeGetWorldPosition(), - cam->GetCameraLocation(), cam->GetCameraOrientation()); + ras->SetViewMatrix(modelviewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective); } void KX_LightObject::UnbindShadowBuffer(RAS_IRasterizer *ras) @@ -172,183 +264,123 @@ void KX_LightObject::UnbindShadowBuffer(RAS_IRasterizer *ras) GPU_lamp_shadow_buffer_unbind(lamp); } -PyObject* KX_LightObject::_getattr(const STR_String& attr) +/* ------------------------------------------------------------------------- */ +/* Python Integration Hooks */ +/* ------------------------------------------------------------------------- */ + +PyTypeObject KX_LightObject::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "KX_LightObject", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, + &KX_GameObject::Sequence, + &KX_GameObject::Mapping, + 0,0,0, + NULL, + NULL, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &KX_GameObject::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyMethodDef KX_LightObject::Methods[] = { + {NULL,NULL} //Sentinel +}; + +PyAttributeDef KX_LightObject::Attributes[] = { + KX_PYATTRIBUTE_INT_RW("layer", 1, 20, true, KX_LightObject, m_lightobj.m_layer), + KX_PYATTRIBUTE_FLOAT_RW("energy", 0, 10, KX_LightObject, m_lightobj.m_energy), + KX_PYATTRIBUTE_FLOAT_RW("distance", 0.01, 5000, KX_LightObject, m_lightobj.m_distance), + KX_PYATTRIBUTE_RW_FUNCTION("color", KX_LightObject, pyattr_get_color, pyattr_set_color), + KX_PYATTRIBUTE_RW_FUNCTION("colour", KX_LightObject, pyattr_get_color, pyattr_set_color), + KX_PYATTRIBUTE_FLOAT_RW("lin_attenuation", 0, 1, KX_LightObject, m_lightobj.m_att1), + KX_PYATTRIBUTE_FLOAT_RW("quad_attenuation", 0, 1, KX_LightObject, m_lightobj.m_att2), + KX_PYATTRIBUTE_FLOAT_RW("spotsize", 1, 180, KX_LightObject, m_lightobj.m_spotsize), + KX_PYATTRIBUTE_FLOAT_RW("spotblend", 0, 1, KX_LightObject, m_lightobj.m_spotblend), + KX_PYATTRIBUTE_RO_FUNCTION("SPOT", KX_LightObject, pyattr_get_typeconst), + KX_PYATTRIBUTE_RO_FUNCTION("SUN", KX_LightObject, pyattr_get_typeconst), + KX_PYATTRIBUTE_RO_FUNCTION("NORMAL", KX_LightObject, pyattr_get_typeconst), + KX_PYATTRIBUTE_RW_FUNCTION("type", KX_LightObject, pyattr_get_type, pyattr_set_type), + { NULL } //Sentinel +}; + +PyObject* KX_LightObject::pyattr_get_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - if (attr == "layer") - return PyInt_FromLong(m_lightobj.m_layer); - - if (attr == "energy") - return PyFloat_FromDouble(m_lightobj.m_energy); - - if (attr == "distance") - return PyFloat_FromDouble(m_lightobj.m_distance); - - if (attr == "colour" || attr == "color") - return Py_BuildValue("[fff]", m_lightobj.m_red, m_lightobj.m_green, m_lightobj.m_blue); - - if (attr == "lin_attenuation") - return PyFloat_FromDouble(m_lightobj.m_att1); - - if (attr == "quad_attenuation") - return PyFloat_FromDouble(m_lightobj.m_att2); - - if (attr == "spotsize") - return PyFloat_FromDouble(m_lightobj.m_spotsize); - - if (attr == "spotblend") - return PyFloat_FromDouble(m_lightobj.m_spotblend); - - if (attr == "SPOT") - return PyInt_FromLong(RAS_LightObject::LIGHT_SPOT); - - if (attr == "SUN") - return PyInt_FromLong(RAS_LightObject::LIGHT_SUN); - - if (attr == "NORMAL") - return PyInt_FromLong(RAS_LightObject::LIGHT_NORMAL); - - if (attr == "type") - return PyInt_FromLong(m_lightobj.m_type); - - _getattr_up(KX_GameObject); + KX_LightObject* self = static_cast<KX_LightObject*>(self_v); + return Py_BuildValue("[fff]", self->m_lightobj.m_red, self->m_lightobj.m_green, self->m_lightobj.m_blue); } -int KX_LightObject::_setattr(const STR_String& attr, PyObject *pyvalue) +int KX_LightObject::pyattr_set_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - if (attr == "SPOT" || attr == "SUN" || attr == "NORMAL") - { - PyErr_Format(PyExc_RuntimeError, "Attribute %s is read only.", attr.ReadPtr()); - return 1; - } - - if (PyInt_Check(pyvalue)) - { - int value = PyInt_AsLong(pyvalue); - if (attr == "layer") - { - m_lightobj.m_layer = value; - return 0; - } - - if (attr == "type") - { - if (value >= RAS_LightObject::LIGHT_SPOT && value <= RAS_LightObject::LIGHT_NORMAL) - m_lightobj.m_type = (RAS_LightObject::LightType) value; - return 0; - } - } - - if (PyFloat_Check(pyvalue)) - { - float value = PyFloat_AsDouble(pyvalue); - if (attr == "energy") - { - m_lightobj.m_energy = value; - return 0; - } - - if (attr == "distance") - { - m_lightobj.m_distance = value; - return 0; - } - - if (attr == "lin_attenuation") - { - m_lightobj.m_att1 = value; - return 0; - } - - if (attr == "quad_attenuation") - { - m_lightobj.m_att2 = value; - return 0; - } - - if (attr == "spotsize") - { - m_lightobj.m_spotsize = value; - return 0; - } - - if (attr == "spotblend") - { - m_lightobj.m_spotblend = value; - return 0; - } - } + KX_LightObject* self = static_cast<KX_LightObject*>(self_v); - if (PySequence_Check(pyvalue)) + MT_Vector3 color; + if (PyVecTo(value, color)) { - if (attr == "colour" || attr == "color") - { - MT_Vector3 color; - if (PyVecTo(pyvalue, color)) - { - m_lightobj.m_red = color[0]; - m_lightobj.m_green = color[1]; - m_lightobj.m_blue = color[2]; - return 0; - } - return 1; - } + self->m_lightobj.m_red = color[0]; + self->m_lightobj.m_green = color[1]; + self->m_lightobj.m_blue = color[2]; + return PY_SET_ATTR_SUCCESS; } - - return KX_GameObject::_setattr(attr, pyvalue); + return PY_SET_ATTR_FAIL; } -PyMethodDef KX_LightObject::Methods[] = { - {NULL,NULL} //Sentinel -}; +PyObject* KX_LightObject::pyattr_get_typeconst(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + PyObject* retvalue; -char KX_LightObject::doc[] = "Module KX_LightObject\n\n" -"Constants:\n" -"\tSPOT\n" -"\tSUN\n" -"\tNORMAL\n" -"Attributes:\n" -"\ttype -> SPOT, SUN or NORMAL\n" -"\t\tThe type of light.\n" -"\tlayer -> integer bit field.\n" -"\t\tThe layers this light applies to.\n" -"\tenergy -> float.\n" -"\t\tThe brightness of the light.\n" -"\tdistance -> float.\n" -"\t\tThe effect radius of the light.\n" -"\tcolour -> list [r, g, b].\n" -"\tcolor -> list [r, g, b].\n" -"\t\tThe color of the light.\n" -"\tlin_attenuation -> float.\n" -"\t\tThe attenuation factor for the light.\n" -"\tspotsize -> float.\n" -"\t\tThe size of the spot.\n" -"\tspotblend -> float.\n" -"\t\tThe blend? of the spot.\n"; + const char* type = attrdef->m_name; -PyTypeObject KX_LightObject::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_LightObject", - sizeof(KX_LightObject), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, - doc -}; + if(strcmp(type, "SPOT")) { + retvalue = PyLong_FromSsize_t(RAS_LightObject::LIGHT_SPOT); + } else if (strcmp(type, "SUN")) { + retvalue = PyLong_FromSsize_t(RAS_LightObject::LIGHT_SUN); + } else if (strcmp(type, "NORMAL")) { + retvalue = PyLong_FromSsize_t(RAS_LightObject::LIGHT_NORMAL); + } -PyParentObject KX_LightObject::Parents[] = { - &KX_LightObject::Type, - &KX_GameObject::Type, - &SCA_IObject::Type, - &CValue::Type, - NULL -}; + return retvalue; +} + +PyObject* KX_LightObject::pyattr_get_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject* self = static_cast<KX_LightObject*>(self_v); + return PyLong_FromSsize_t(self->m_lightobj.m_type); +} + +int KX_LightObject::pyattr_set_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject* value) +{ + KX_LightObject* self = static_cast<KX_LightObject*>(self_v); + int val = PyLong_AsSsize_t(value); + if((val==-1 && PyErr_Occurred()) || val<0 || val>2) { + PyErr_SetString(PyExc_ValueError, "light.type= val: KX_LightObject, expected an int between 0 and 2"); + return PY_SET_ATTR_FAIL; + } + + switch(val) { + case 0: + self->m_lightobj.m_type = self->m_lightobj.LIGHT_SPOT; + break; + case 1: + self->m_lightobj.m_type = self->m_lightobj.LIGHT_SUN; + break; + case 2: + self->m_lightobj.m_type = self->m_lightobj.LIGHT_NORMAL; + break; + } + + return PY_SET_ATTR_SUCCESS; +} diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h index e5dbf0b7f4a..0b7ccbe81ab 100644 --- a/source/gameengine/Ketsji/KX_Light.h +++ b/source/gameengine/Ketsji/KX_Light.h @@ -47,24 +47,30 @@ protected: class RAS_IRenderTools* m_rendertools; //needed for registering and replication of lightobj bool m_glsl; Scene* m_blenderscene; - static char doc[]; public: - KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,class RAS_IRenderTools* rendertools,const struct RAS_LightObject& lightobj, bool glsl, PyTypeObject *T = &Type); + KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,class RAS_IRenderTools* rendertools,const struct RAS_LightObject& lightobj, bool glsl); virtual ~KX_LightObject(); virtual CValue* GetReplica(); RAS_LightObject* GetLightData() { return &m_lightobj;} - /* GLSL shadow */ + /* OpenGL Light */ + bool ApplyLight(KX_Scene *kxscene, int oblayer, int slot); + + /* GLSL Light */ struct GPULamp *GetGPULamp(); bool HasShadowBuffer(); int GetShadowLayer(); void BindShadowBuffer(class RAS_IRasterizer *ras, class KX_Camera *cam, class MT_Transform& camtrans); void UnbindShadowBuffer(class RAS_IRasterizer *ras); void Update(); - - virtual PyObject* _getattr(const STR_String& attr); /* lens, near, far, projection_matrix */ - virtual int _setattr(const STR_String& attr, PyObject *pyvalue); + + /* attributes */ + static PyObject* pyattr_get_color(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_color(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject* value); + static PyObject* pyattr_get_typeconst(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject* value); virtual bool IsLight(void) { return true; } }; diff --git a/source/gameengine/Ketsji/KX_LightIpoSGController.h b/source/gameengine/Ketsji/KX_LightIpoSGController.h index 98870cf5b3f..811dba5dba8 100644 --- a/source/gameengine/Ketsji/KX_LightIpoSGController.h +++ b/source/gameengine/Ketsji/KX_LightIpoSGController.h @@ -92,6 +92,13 @@ public: }; void AddInterpolator(KX_IInterpolator* interp); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_LightIpoSGController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // KX_LIGHTIPOSGCONTROLLER_H diff --git a/source/gameengine/Ketsji/KX_MaterialIpoController.h b/source/gameengine/Ketsji/KX_MaterialIpoController.h index 4d2e258bf94..906c12426eb 100644 --- a/source/gameengine/Ketsji/KX_MaterialIpoController.h +++ b/source/gameengine/Ketsji/KX_MaterialIpoController.h @@ -50,6 +50,13 @@ public: void AddInterpolator(KX_IInterpolator* interp); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_MaterialIpoController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; diff --git a/source/gameengine/Ketsji/KX_MeshProxy.cpp b/source/gameengine/Ketsji/KX_MeshProxy.cpp index 5cc102248f2..744fdb75796 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.cpp +++ b/source/gameengine/Ketsji/KX_MeshProxy.cpp @@ -46,81 +46,52 @@ #include "PyObjectPlus.h" PyTypeObject KX_MeshProxy::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_MeshProxy", - sizeof(KX_MeshProxy), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_MeshProxy::Parents[] = { - &KX_MeshProxy::Type, - &SCA_IObject::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &CValue::Type, - &PyObjectPlus::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_MeshProxy::Methods[] = { -{"getNumMaterials", (PyCFunction)KX_MeshProxy::sPyGetNumMaterials,METH_VARARGS}, -{"getNumPolygons", (PyCFunction)KX_MeshProxy::sPyGetNumPolygons,METH_NOARGS}, {"getMaterialName", (PyCFunction)KX_MeshProxy::sPyGetMaterialName,METH_VARARGS}, {"getTextureName", (PyCFunction)KX_MeshProxy::sPyGetTextureName,METH_VARARGS}, {"getVertexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetVertexArrayLength,METH_VARARGS}, {"getVertex", (PyCFunction)KX_MeshProxy::sPyGetVertex,METH_VARARGS}, {"getPolygon", (PyCFunction)KX_MeshProxy::sPyGetPolygon,METH_VARARGS}, -KX_PYMETHODTABLE(KX_MeshProxy, reinstancePhysicsMesh), //{"getIndexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetIndexArrayLength,METH_VARARGS}, - {NULL,NULL} //Sentinel }; -void KX_MeshProxy::SetMeshModified(bool v) -{ - m_meshobj->SetMeshModified(v); -} +PyAttributeDef KX_MeshProxy::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("materials", KX_MeshProxy, pyattr_get_materials), + KX_PYATTRIBUTE_RO_FUNCTION("numPolygons", KX_MeshProxy, pyattr_get_numPolygons), + KX_PYATTRIBUTE_RO_FUNCTION("numMaterials", KX_MeshProxy, pyattr_get_numMaterials), + { NULL } //Sentinel +}; -PyObject* -KX_MeshProxy::_getattr(const STR_String& attr) +void KX_MeshProxy::SetMeshModified(bool v) { - if (attr == "materials") - { - PyObject *materials = PyList_New(0); - list<RAS_MeshMaterial>::iterator mit = m_meshobj->GetFirstMaterial(); - for(; mit != m_meshobj->GetLastMaterial(); ++mit) - { - RAS_IPolyMaterial *polymat = mit->m_bucket->GetPolyMaterial(); - - if(polymat->GetFlag() & RAS_BLENDERMAT) - { - KX_BlenderMaterial *mat = static_cast<KX_BlenderMaterial*>(polymat); - PyList_Append(materials, mat); - }else - { - PyList_Append(materials, static_cast<KX_PolygonMaterial*>(polymat)); - } - } - return materials; - } - _getattr_up(SCA_IObject); + m_meshobj->SetMeshModified(v); } - - KX_MeshProxy::KX_MeshProxy(RAS_MeshObject* mesh) - : m_meshobj(mesh) + : CValue(), m_meshobj(mesh) { } @@ -135,37 +106,20 @@ CValue* KX_MeshProxy::Calc(VALUE_OPERATOR op, CValue *val) { return NULL;} CValue* KX_MeshProxy::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) { return NULL;} const STR_String & KX_MeshProxy::GetText() {return m_meshobj->GetName();}; -float KX_MeshProxy::GetNumber() { return -1;} -STR_String KX_MeshProxy::GetName() { return m_meshobj->GetName();} -void KX_MeshProxy::SetName(STR_String name) { }; +double KX_MeshProxy::GetNumber() { return -1;} +STR_String& KX_MeshProxy::GetName() { return m_meshobj->GetName();} +void KX_MeshProxy::SetName(const char *name) { }; CValue* KX_MeshProxy::GetReplica() { return NULL;} -void KX_MeshProxy::ReplicaSetName(STR_String name) {}; // stuff for python integration - -PyObject* KX_MeshProxy::PyGetNumMaterials(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - int num = m_meshobj->NumMaterials(); - return PyInt_FromLong(num); -} -PyObject* KX_MeshProxy::PyGetNumPolygons(PyObject* self) -{ - int num = m_meshobj->NumPolygons(); - return PyInt_FromLong(num); -} - -PyObject* KX_MeshProxy::PyGetMaterialName(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_MeshProxy::PyGetMaterialName(PyObject* args, PyObject* kwds) { int matid= 1; STR_String matname; - if (PyArg_ParseTuple(args,"i",&matid)) + if (PyArg_ParseTuple(args,"i:getMaterialName",&matid)) { matname = m_meshobj->GetMaterialName(matid); } @@ -173,19 +127,17 @@ PyObject* KX_MeshProxy::PyGetMaterialName(PyObject* self, return NULL; } - return PyString_FromString(matname.Ptr()); + return PyUnicode_FromString(matname.Ptr()); } -PyObject* KX_MeshProxy::PyGetTextureName(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_MeshProxy::PyGetTextureName(PyObject* args, PyObject* kwds) { int matid= 1; STR_String matname; - if (PyArg_ParseTuple(args,"i",&matid)) + if (PyArg_ParseTuple(args,"i:getTextureName",&matid)) { matname = m_meshobj->GetTextureName(matid); } @@ -193,84 +145,167 @@ PyObject* KX_MeshProxy::PyGetTextureName(PyObject* self, return NULL; } - return PyString_FromString(matname.Ptr()); + return PyUnicode_FromString(matname.Ptr()); } -PyObject* KX_MeshProxy::PyGetVertexArrayLength(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_MeshProxy::PyGetVertexArrayLength(PyObject* args, PyObject* kwds) { - int matid= -1; - int length = -1; + int matid= 0; + int length = 0; - if (PyArg_ParseTuple(args,"i",&matid)) + if (!PyArg_ParseTuple(args,"i:getVertexArrayLength",&matid)) + return NULL; + + + RAS_MeshMaterial *mmat = m_meshobj->GetMeshMaterial(matid); /* can be NULL*/ + + if (mmat) { - RAS_MeshMaterial *mmat = m_meshobj->GetMeshMaterial(matid); RAS_IPolyMaterial* mat = mmat->m_bucket->GetPolyMaterial(); - if (mat) length = m_meshobj->NumVertices(mat); } - else { - return NULL; - } - - return PyInt_FromLong(length); - + + return PyLong_FromSsize_t(length); } -PyObject* KX_MeshProxy::PyGetVertex(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_MeshProxy::PyGetVertex(PyObject* args, PyObject* kwds) { - int vertexindex= 1; - int matindex= 1; - PyObject* vertexob = NULL; + int vertexindex; + int matindex; - if (PyArg_ParseTuple(args,"ii",&matindex,&vertexindex)) - { - RAS_TexVert* vertex = m_meshobj->GetVertex(matindex,vertexindex); - if (vertex) - { - vertexob = new KX_VertexProxy(this, vertex); - } - } - else { + if (!PyArg_ParseTuple(args,"ii:getVertex",&matindex,&vertexindex)) + return NULL; + + RAS_TexVert* vertex = m_meshobj->GetVertex(matindex,vertexindex); + + if(vertex==NULL) { + PyErr_SetString(PyExc_ValueError, "mesh.getVertex(mat_idx, vert_idx): KX_MeshProxy, could not get a vertex at the given indicies"); return NULL; } - - return vertexob; - + + return (new KX_VertexProxy(this, vertex))->NewProxy(true); } -PyObject* KX_MeshProxy::PyGetPolygon(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_MeshProxy::PyGetPolygon(PyObject* args, PyObject* kwds) { int polyindex= 1; PyObject* polyob = NULL; - if (!PyArg_ParseTuple(args,"i",&polyindex)) + if (!PyArg_ParseTuple(args,"i:getPolygon",&polyindex)) + return NULL; + + if (polyindex<0 || polyindex >= m_meshobj->NumPolygons()) + { + PyErr_SetString(PyExc_AttributeError, "mesh.getPolygon(int): KX_MeshProxy, invalid polygon index"); return NULL; + } + RAS_Polygon* polygon = m_meshobj->GetPolygon(polyindex); if (polygon) { - polyob = new KX_PolyProxy(m_meshobj, polygon); + polyob = (new KX_PolyProxy(m_meshobj, polygon))->NewProxy(true); } - else - { - PyErr_SetString(PyExc_AttributeError, "Invalid polygon index"); + else { + PyErr_SetString(PyExc_AttributeError, "mesh.getPolygon(int): KX_MeshProxy, polygon is NULL, unknown reason"); } return polyob; } -KX_PYMETHODDEF_DOC(KX_MeshProxy, reinstancePhysicsMesh, -"Reinstance the physics mesh.") +PyObject* KX_MeshProxy::pyattr_get_materials(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_MeshProxy* self= static_cast<KX_MeshProxy*>(self_v); + + int tot= self->m_meshobj->NumMaterials(); + int i; + + PyObject *materials = PyList_New( tot ); + + list<RAS_MeshMaterial>::iterator mit= self->m_meshobj->GetFirstMaterial(); + + + for(i=0; i<tot; mit++, i++) { + RAS_IPolyMaterial *polymat = mit->m_bucket->GetPolyMaterial(); + + /* Why do we need to check for RAS_BLENDERMAT if both are cast to a (PyObject*)? - Campbell */ + if(polymat->GetFlag() & RAS_BLENDERMAT) + { + KX_BlenderMaterial *mat = static_cast<KX_BlenderMaterial*>(polymat); + PyList_SET_ITEM(materials, i, mat->GetProxy()); + } + else { + KX_PolygonMaterial *mat = static_cast<KX_PolygonMaterial*>(polymat); + PyList_SET_ITEM(materials, i, mat->GetProxy()); + } + } + return materials; +} + +PyObject * KX_MeshProxy::pyattr_get_numMaterials(void * selfv, const KX_PYATTRIBUTE_DEF * attrdef) { + KX_MeshProxy * self = static_cast<KX_MeshProxy *> (selfv); + return PyLong_FromSsize_t(self->m_meshobj->NumMaterials()); +} + +PyObject * KX_MeshProxy::pyattr_get_numPolygons(void * selfv, const KX_PYATTRIBUTE_DEF * attrdef) { + KX_MeshProxy * self = static_cast<KX_MeshProxy *> (selfv); + return PyLong_FromSsize_t(self->m_meshobj->NumPolygons()); +} + +/* a close copy of ConvertPythonToGameObject but for meshes */ +bool ConvertPythonToMesh(PyObject * value, RAS_MeshObject **object, bool py_none_ok, const char *error_prefix) { - //this needs to be reviewed, it is dependend on Sumo/Solid. Who is using this ? - Py_RETURN_NONE;//(KX_ReInstanceShapeFromMesh(m_meshobj)) ? Py_RETURN_TRUE : Py_RETURN_FALSE; + if (value==NULL) { + PyErr_Format(PyExc_TypeError, "%s, python pointer NULL, should never happen", error_prefix); + *object = NULL; + return false; + } + + if (value==Py_None) { + *object = NULL; + + if (py_none_ok) { + return true; + } else { + PyErr_Format(PyExc_TypeError, "%s, expected KX_MeshProxy or a KX_MeshProxy name, None is invalid", error_prefix); + return false; + } + } + + if (PyUnicode_Check(value)) { + *object = (RAS_MeshObject*)SCA_ILogicBrick::m_sCurrentLogicManager->GetMeshByName(STR_String( _PyUnicode_AsString(value) )); + + if (*object) { + return true; + } else { + PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_MeshProxy in this scene", error_prefix, _PyUnicode_AsString(value)); + return false; + } + } + + if (PyObject_TypeCheck(value, &KX_MeshProxy::Type)) { + KX_MeshProxy *kx_mesh = static_cast<KX_MeshProxy*>BGE_PROXY_REF(value); + + /* sets the error */ + if (kx_mesh==NULL) { + PyErr_Format(PyExc_SystemError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix); + return false; + } + + *object = kx_mesh->GetMesh(); + return true; + } + + *object = NULL; + + if (py_none_ok) { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_MeshProxy, a string or None", error_prefix); + } else { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_MeshProxy or a string", error_prefix); + } + + return false; } diff --git a/source/gameengine/Ketsji/KX_MeshProxy.h b/source/gameengine/Ketsji/KX_MeshProxy.h index 3335c349673..55684aa5ee9 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.h +++ b/source/gameengine/Ketsji/KX_MeshProxy.h @@ -31,7 +31,10 @@ #include "SCA_IObject.h" -class KX_MeshProxy : public SCA_IObject +/* utility conversion function */ +bool ConvertPythonToMesh(PyObject * value, class RAS_MeshObject **object, bool py_none_ok, const char *error_prefix); + +class KX_MeshProxy : public CValue { Py_Header; @@ -46,24 +49,27 @@ public: virtual CValue* Calc(VALUE_OPERATOR op, CValue *val) ; virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); virtual const STR_String & GetText(); - virtual float GetNumber(); - virtual STR_String GetName(); - virtual void SetName(STR_String name); // Set the name of the value - virtual void ReplicaSetName(STR_String name); + virtual double GetNumber(); + virtual RAS_MeshObject* GetMesh() { return m_meshobj; } + virtual STR_String& GetName(); + virtual void SetName(const char *name); // Set the name of the value virtual CValue* GetReplica(); // stuff for python integration - virtual PyObject* _getattr(const STR_String& attr); - KX_PYMETHOD(KX_MeshProxy,GetNumMaterials); + + KX_PYMETHOD(KX_MeshProxy,GetNumMaterials); // Deprecated KX_PYMETHOD(KX_MeshProxy,GetMaterialName); KX_PYMETHOD(KX_MeshProxy,GetTextureName); - KX_PYMETHOD_NOARGS(KX_MeshProxy,GetNumPolygons); + KX_PYMETHOD_NOARGS(KX_MeshProxy,GetNumPolygons); // Deprecated // both take materialid (int) KX_PYMETHOD(KX_MeshProxy,GetVertexArrayLength); KX_PYMETHOD(KX_MeshProxy,GetVertex); KX_PYMETHOD(KX_MeshProxy,GetPolygon); - KX_PYMETHOD_DOC(KX_MeshProxy, reinstancePhysicsMesh); + + static PyObject* pyattr_get_materials(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject * pyattr_get_numMaterials(void * self, const KX_PYATTRIBUTE_DEF * attrdef); + static PyObject * pyattr_get_numPolygons(void * self, const KX_PYATTRIBUTE_DEF * attrdef); }; #endif //__KX_MESHPROXY diff --git a/source/gameengine/Ketsji/KX_MotionState.cpp b/source/gameengine/Ketsji/KX_MotionState.cpp index 15f100af915..60455d33312 100644 --- a/source/gameengine/Ketsji/KX_MotionState.cpp +++ b/source/gameengine/Ketsji/KX_MotionState.cpp @@ -44,7 +44,7 @@ KX_MotionState::~KX_MotionState() void KX_MotionState::getWorldPosition(float& posX,float& posY,float& posZ) { - MT_Point3 pos = m_node->GetWorldPosition(); + const MT_Point3& pos = m_node->GetWorldPosition(); posX = pos[0]; posY = pos[1]; posZ = pos[2]; @@ -52,7 +52,7 @@ void KX_MotionState::getWorldPosition(float& posX,float& posY,float& posZ) void KX_MotionState::getWorldScaling(float& scaleX,float& scaleY,float& scaleZ) { - MT_Vector3 scale = m_node->GetWorldScaling(); + const MT_Vector3& scale = m_node->GetWorldScaling(); scaleX = scale[0]; scaleY = scale[1]; scaleZ = scale[2]; @@ -67,10 +67,21 @@ void KX_MotionState::getWorldOrientation(float& quatIma0,float& quatIma1,float& quatReal = orn[3]; } +void KX_MotionState::getWorldOrientation(float* ori) +{ + const MT_Matrix3x3& mat = m_node->GetWorldOrientation(); + mat.getValue(ori); +} + +void KX_MotionState::setWorldOrientation(const float* ori) +{ + m_node->SetLocalOrientation(ori); +} + void KX_MotionState::setWorldPosition(float posX,float posY,float posZ) { m_node->SetLocalPosition(MT_Point3(posX,posY,posZ)); - m_node->SetWorldPosition(MT_Point3(posX,posY,posZ)); + //m_node->SetWorldPosition(MT_Point3(posX,posY,posZ)); } void KX_MotionState::setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal) @@ -82,13 +93,15 @@ void KX_MotionState::setWorldOrientation(float quatIma0,float quatIma1,float qua orn[3] = quatReal; m_node->SetLocalOrientation(orn); - m_node->SetWorldOrientation(orn); + //m_node->SetWorldOrientation(orn); } void KX_MotionState::calculateWorldTransformations() { - m_node->ComputeWorldTransforms(NULL); + //Not needed, will be done in KX_Scene::UpdateParents() after the physics simulation + //bool parentUpdated = false; + //m_node->ComputeWorldTransforms(NULL, parentUpdated); } diff --git a/source/gameengine/Ketsji/KX_MotionState.h b/source/gameengine/Ketsji/KX_MotionState.h index c83af664817..63c265aa8a7 100644 --- a/source/gameengine/Ketsji/KX_MotionState.h +++ b/source/gameengine/Ketsji/KX_MotionState.h @@ -31,6 +31,10 @@ #include "PHY_IMotionState.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class KX_MotionState : public PHY_IMotionState { class SG_Spatial* m_node; @@ -44,8 +48,16 @@ public: virtual void getWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal); virtual void setWorldPosition(float posX,float posY,float posZ); virtual void setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal); + virtual void getWorldOrientation(float* ori); + virtual void setWorldOrientation(const float* ori); virtual void calculateWorldTransformations(); + + +#ifdef WITH_CXX_GUARDEDALLOC + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_MotionState"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_MOTIONSTATE diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp index 28279b9a6b8..8abc4f6b897 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -42,6 +42,7 @@ #include "KX_Scene.h" #include "KX_Camera.h" #include "KX_MouseFocusSensor.h" +#include "KX_PyMath.h" #include "KX_RayCast.h" #include "KX_IPhysicsController.h" @@ -60,14 +61,13 @@ KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager* eventmgr, int starty, short int mousemode, int focusmode, - RAS_ICanvas* canvas, + bool bTouchPulse, KX_Scene* kxscene, KX_KetsjiEngine *kxengine, - SCA_IObject* gameobj, - PyTypeObject* T) - : SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj, T), + SCA_IObject* gameobj) + : SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj), m_focusmode(focusmode), - m_gp_canvas(canvas), + m_bTouchPulse(bTouchPulse), m_kxscene(kxscene), m_kxengine(kxengine) { @@ -79,10 +79,16 @@ void KX_MouseFocusSensor::Init() m_mouse_over_in_previous_frame = (m_invert)?true:false; m_positive_event = false; m_hitObject = 0; + m_hitObject_Last = NULL; m_reset = true; + + m_hitPosition.setValue(0,0,0); + m_prevTargetPoint.setValue(0,0,0); + m_prevSourcePoint.setValue(0,0,0); + m_hitNormal.setValue(0,0,1); } -bool KX_MouseFocusSensor::Evaluate(CValue* event) +bool KX_MouseFocusSensor::Evaluate() { bool result = false; bool obHasFocus = false; @@ -104,7 +110,10 @@ bool KX_MouseFocusSensor::Evaluate(CValue* event) m_positive_event = true; if (!m_mouse_over_in_previous_frame) { result = true; - } + } + else if(m_bTouchPulse && (m_hitObject != m_hitObject_Last)) { + result = true; + } } if (reset) { // force an event @@ -115,12 +124,13 @@ bool KX_MouseFocusSensor::Evaluate(CValue* event) * mode is never used, because the converter never makes this * sensor for a mouse-key event. It is here for * completeness. */ - result = SCA_MouseSensor::Evaluate(event); + result = SCA_MouseSensor::Evaluate(); m_positive_event = (m_val!=0); } m_mouse_over_in_previous_frame = obHasFocus; - + m_hitObject_Last = (void *)m_hitObject; + return result; } @@ -149,12 +159,8 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, KX_RayCast* r -bool KX_MouseFocusSensor::ParentObjectHasFocus(void) +bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam) { - m_hitObject = 0; - m_hitPosition = MT_Vector3(0,0,0); - m_hitNormal = MT_Vector3(1,0,0); - /* All screen handling in the gameengine is done by GL, * specifically the model/view and projection parts. The viewport * part is in the creator. @@ -186,6 +192,7 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) * = 1.0 - 2(y_blender - y_lb)/height * * */ + /* Because we don't want to worry about resize events, camera * changes and all that crap, we just determine this over and @@ -194,15 +201,20 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) * canvas, the test is irrelevant. The 1.0 makes sure the * calculations don't bomb. Maybe we should explicitly guard for * division by 0.0...*/ - - KX_Camera* cam = m_kxscene->GetActiveCamera(); - - /* get the scenes current viewport. we recompute it because there - * may be multiple cameras and m_kxscene->GetSceneViewport() only - * has the one that was last drawn */ - + RAS_Rect area, viewport; + short m_y_inv = m_kxengine->GetCanvas()->GetHeight()-m_y; + m_kxengine->GetSceneViewport(m_kxscene, cam, area, viewport); + + /* Check if the mouse is in the viewport */ + if (( m_x < viewport.m_x2 && // less then right + m_x > viewport.m_x1 && // more then then left + m_y_inv < viewport.m_y2 && // below top + m_y_inv > viewport.m_y1) == 0) // above bottom + { + return false; + } float height = float(viewport.m_y2 - viewport.m_y1 + 1); float width = float(viewport.m_x2 - viewport.m_x1 + 1); @@ -210,14 +222,17 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) float x_lb = float(viewport.m_x1); float y_lb = float(viewport.m_y1); + MT_Vector4 frompoint; + MT_Vector4 topoint; + + /* m_y_inv - inverting for a bounds check is only part of it, now make relative to view bounds */ + m_y_inv = (viewport.m_y2 - m_y_inv) + viewport.m_y1; + + /* There's some strangeness I don't fully get here... These values - * _should_ be wrong! */ + * _should_ be wrong! - see from point Z values */ + - - /* old: */ - float nearclip = 0.0; - float farclip = 1.0; - /* build the from and to point in normalized device coordinates * Looks like normailized device coordinates are [-1,1] in x [-1,1] in y * [0,-1] in z @@ -225,23 +240,19 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) * The actual z coordinates used don't have to be exact just infront and * behind of the near and far clip planes. */ - MT_Vector4 frompoint = MT_Vector4( - (2 * (m_x-x_lb) / width) - 1.0, - 1.0 - (2 * (m_y - y_lb) / height), - nearclip, - 1.0 - ); - MT_Vector4 topoint = MT_Vector4( - (2 * (m_x-x_lb) / width) - 1.0, - 1.0 - (2 * (m_y-y_lb) / height), - farclip, - 1.0 - ); + frompoint.setValue( (2 * (m_x-x_lb) / width) - 1.0, + 1.0 - (2 * (m_y_inv - y_lb) / height), + /*cam->GetCameraData()->m_perspective ? 0.0:cdata->m_clipstart,*/ /* real clipstart is scaled in ortho for some reason, zero is ok */ + 0.0, /* nearclip, see above comments */ + 1.0 ); + + topoint.setValue( (2 * (m_x-x_lb) / width) - 1.0, + 1.0 - (2 * (m_y_inv-y_lb) / height), + cam->GetCameraData()->m_perspective ? 1.0:cam->GetCameraData()->m_clipend, /* farclip, see above comments */ + 1.0 ); /* camera to world */ MT_Transform wcs_camcs_tranform = cam->GetWorldToCamera(); - if (!cam->GetCameraData()->m_perspective) - wcs_camcs_tranform.getOrigin()[2] *= 100.0; MT_Transform cams_wcs_transform; cams_wcs_transform.invert(wcs_camcs_tranform); @@ -259,31 +270,74 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) topoint = camcs_wcs_matrix * topoint; /* from hom wcs to 3d wcs: */ - MT_Point3 frompoint3 = MT_Point3(frompoint[0]/frompoint[3], - frompoint[1]/frompoint[3], - frompoint[2]/frompoint[3]); - MT_Point3 topoint3 = MT_Point3(topoint[0]/topoint[3], - topoint[1]/topoint[3], - topoint[2]/topoint[3]); - m_prevTargetPoint = topoint3; - m_prevSourcePoint = frompoint3; + m_prevSourcePoint.setValue( frompoint[0]/frompoint[3], + frompoint[1]/frompoint[3], + frompoint[2]/frompoint[3]); + + m_prevTargetPoint.setValue( topoint[0]/topoint[3], + topoint[1]/topoint[3], + topoint[2]/topoint[3]); /* 2. Get the object from PhysicsEnvironment */ /* Shoot! Beware that the first argument here is an * ignore-object. We don't ignore anything... */ - KX_IPhysicsController* physics_controller = cam->GetPhysicsController(); PHY_IPhysicsEnvironment* physics_environment = m_kxscene->GetPhysicsEnvironment(); - bool result = false; - KX_RayCast::Callback<KX_MouseFocusSensor> callback(this,physics_controller); - KX_RayCast::RayTest(physics_environment, frompoint3, topoint3, callback); + + KX_RayCast::RayTest(physics_environment, m_prevSourcePoint, m_prevTargetPoint, callback); + + if (m_hitObject) + return true; - result = (m_hitObject!=0); + return false; +} - return result; +bool KX_MouseFocusSensor::ParentObjectHasFocus() +{ + m_hitObject = 0; + m_hitPosition.setValue(0,0,0); + m_hitNormal.setValue(1,0,0); + + KX_Camera *cam= m_kxscene->GetActiveCamera(); + + if(ParentObjectHasFocusCamera(cam)) + return true; + + list<class KX_Camera*>* cameras = m_kxscene->GetCameras(); + list<KX_Camera*>::iterator it = cameras->begin(); + + while(it != cameras->end()) + { + if(((*it) != cam) && (*it)->GetViewport()) + if (ParentObjectHasFocusCamera(*it)) + return true; + + it++; + } + + return false; +} + +const MT_Point3& KX_MouseFocusSensor::RaySource() const +{ + return m_prevSourcePoint; +} +const MT_Point3& KX_MouseFocusSensor::RayTarget() const +{ + return m_prevTargetPoint; +} + +const MT_Point3& KX_MouseFocusSensor::HitPosition() const +{ + return m_hitPosition; +} + +const MT_Vector3& KX_MouseFocusSensor::HitNormal() const +{ + return m_hitNormal; } /* ------------------------------------------------------------------------- */ @@ -292,159 +346,87 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_MouseFocusSensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_MouseFocusSensor", - sizeof(KX_MouseFocusSensor), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_MouseFocusSensor::Parents[] = { - &KX_MouseFocusSensor::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_MouseSensor::Type, - &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_MouseFocusSensor::Methods[] = { - {"getRayTarget", (PyCFunction) KX_MouseFocusSensor::sPyGetRayTarget, METH_VARARGS, (PY_METHODCHAR)GetRayTarget_doc}, - {"getRaySource", (PyCFunction) KX_MouseFocusSensor::sPyGetRaySource, METH_VARARGS, (PY_METHODCHAR)GetRaySource_doc}, - {"getHitObject",(PyCFunction) KX_MouseFocusSensor::sPyGetHitObject,METH_VARARGS, (PY_METHODCHAR)GetHitObject_doc}, - {"getHitPosition",(PyCFunction) KX_MouseFocusSensor::sPyGetHitPosition,METH_VARARGS, (PY_METHODCHAR)GetHitPosition_doc}, - {"getHitNormal",(PyCFunction) KX_MouseFocusSensor::sPyGetHitNormal,METH_VARARGS, (PY_METHODCHAR)GetHitNormal_doc}, - {"getRayDirection",(PyCFunction) KX_MouseFocusSensor::sPyGetRayDirection,METH_VARARGS, (PY_METHODCHAR)GetRayDirection_doc}, - - {NULL,NULL} //Sentinel }; -PyObject* KX_MouseFocusSensor::_getattr(const STR_String& attr) { - _getattr_up(SCA_MouseSensor); -} - +PyAttributeDef KX_MouseFocusSensor::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("raySource", KX_MouseFocusSensor, pyattr_get_ray_source), + KX_PYATTRIBUTE_RO_FUNCTION("rayTarget", KX_MouseFocusSensor, pyattr_get_ray_target), + KX_PYATTRIBUTE_RO_FUNCTION("rayDirection", KX_MouseFocusSensor, pyattr_get_ray_direction), + KX_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_MouseFocusSensor, pyattr_get_hit_object), + KX_PYATTRIBUTE_RO_FUNCTION("hitPosition", KX_MouseFocusSensor, pyattr_get_hit_position), + KX_PYATTRIBUTE_RO_FUNCTION("hitNormal", KX_MouseFocusSensor, pyattr_get_hit_normal), + KX_PYATTRIBUTE_BOOL_RW("usePulseFocus", KX_MouseFocusSensor,m_bTouchPulse), + { NULL } //Sentinel +}; -const char KX_MouseFocusSensor::GetHitObject_doc[] = -"getHitObject()\n" -"\tReturns the name of the object that was hit by this ray.\n"; -PyObject* KX_MouseFocusSensor::PyGetHitObject(PyObject* self, - PyObject* args, - PyObject* kwds) +/* Attributes */ +PyObject* KX_MouseFocusSensor::pyattr_get_ray_source(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - if (m_hitObject) - { - return m_hitObject->AddRef(); - } - Py_Return; + KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v); + return PyObjectFrom(self->RaySource()); } - -const char KX_MouseFocusSensor::GetHitPosition_doc[] = -"getHitPosition()\n" -"\tReturns the position (in worldcoordinates) where the object was hit by this ray.\n"; -PyObject* KX_MouseFocusSensor::PyGetHitPosition(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_MouseFocusSensor::pyattr_get_ray_target(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - - MT_Point3 pos = m_hitPosition; - - PyObject* resultlist = PyList_New(3); - int index; - for (index=0;index<3;index++) - { - PyList_SetItem(resultlist,index,PyFloat_FromDouble(pos[index])); - } - return resultlist; - + KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v); + return PyObjectFrom(self->RayTarget()); } -const char KX_MouseFocusSensor::GetRayDirection_doc[] = -"getRayDirection()\n" -"\tReturns the direction from the ray (in worldcoordinates) .\n"; -PyObject* KX_MouseFocusSensor::PyGetRayDirection(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_MouseFocusSensor::pyattr_get_ray_direction(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - - MT_Vector3 dir = m_prevTargetPoint - m_prevSourcePoint; - dir.normalize(); - - PyObject* resultlist = PyList_New(3); - int index; - for (index=0;index<3;index++) - { - PyList_SetItem(resultlist,index,PyFloat_FromDouble(dir[index])); - } - return resultlist; - + KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v); + MT_Vector3 dir = self->RayTarget() - self->RaySource(); + if(MT_fuzzyZero(dir)) dir.setValue(0,0,0); + else dir.normalize(); + return PyObjectFrom(dir); } -const char KX_MouseFocusSensor::GetHitNormal_doc[] = -"getHitNormal()\n" -"\tReturns the normal (in worldcoordinates) of the object at the location where the object was hit by this ray.\n"; -PyObject* KX_MouseFocusSensor::PyGetHitNormal(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_MouseFocusSensor::pyattr_get_hit_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - MT_Vector3 pos = m_hitNormal; - - PyObject* resultlist = PyList_New(3); - int index; - for (index=0;index<3;index++) - { - PyList_SetItem(resultlist,index,PyFloat_FromDouble(pos[index])); - } - return resultlist; - + KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v); + + if(self->m_hitObject) + return self->m_hitObject->GetProxy(); + + Py_RETURN_NONE; } - -/* getRayTarget */ -const char KX_MouseFocusSensor::GetRayTarget_doc[] = -"getRayTarget()\n" -"\tReturns the target of the ray that seeks the focus object,\n" -"\tin worldcoordinates."; -PyObject* KX_MouseFocusSensor::PyGetRayTarget(PyObject* self, - PyObject* args, - PyObject* kwds) { - PyObject *retVal = PyList_New(3); - - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_prevTargetPoint[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_prevTargetPoint[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_prevTargetPoint[2])); - - return retVal; +PyObject* KX_MouseFocusSensor::pyattr_get_hit_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v); + return PyObjectFrom(self->HitPosition()); } -/* getRayTarget */ -const char KX_MouseFocusSensor::GetRaySource_doc[] = -"getRaySource()\n" -"\tReturns the source of the ray that seeks the focus object,\n" -"\tin worldcoordinates."; -PyObject* KX_MouseFocusSensor::PyGetRaySource(PyObject* self, - PyObject* args, - PyObject* kwds) { - PyObject *retVal = PyList_New(3); - - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_prevSourcePoint[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_prevSourcePoint[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_prevSourcePoint[2])); - - return retVal; +PyObject* KX_MouseFocusSensor::pyattr_get_hit_normal(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_MouseFocusSensor* self= static_cast<KX_MouseFocusSensor*>(self_v); + return PyObjectFrom(self->HitNormal()); } + + /* eof */ diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h index 6731444699b..7b53557467f 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h @@ -49,28 +49,27 @@ class KX_MouseFocusSensor : public SCA_MouseSensor public: - KX_MouseFocusSensor(class SCA_MouseManager* keybdmgr, + KX_MouseFocusSensor(class SCA_MouseManager* eventmgr, int startx, int starty, short int mousemode, int focusmode, - RAS_ICanvas* canvas, + bool bTouchPulse, KX_Scene* kxscene, KX_KetsjiEngine* kxengine, - SCA_IObject* gameobj, - PyTypeObject* T=&Type ); + SCA_IObject* gameobj); virtual ~KX_MouseFocusSensor() { ; }; virtual CValue* GetReplica() { CValue* replica = new KX_MouseFocusSensor(*this); // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; }; /** * @attention Overrides default evaluate. */ - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual void Init(); virtual bool IsPositiveTrigger() { @@ -82,23 +81,26 @@ class KX_MouseFocusSensor : public SCA_MouseSensor bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); bool NeedRayCast(KX_ClientObjectInfo* client) { return true; } - + const MT_Point3& RaySource() const; + const MT_Point3& RayTarget() const; + const MT_Point3& HitPosition() const; + const MT_Vector3& HitNormal() const; /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); - - KX_PYMETHOD_DOC(KX_MouseFocusSensor,GetRayTarget); - KX_PYMETHOD_DOC(KX_MouseFocusSensor,GetRaySource); - - KX_PYMETHOD_DOC(KX_MouseFocusSensor,GetHitObject); - KX_PYMETHOD_DOC(KX_MouseFocusSensor,GetHitPosition); - KX_PYMETHOD_DOC(KX_MouseFocusSensor,GetHitNormal); - KX_PYMETHOD_DOC(KX_MouseFocusSensor,GetRayDirection); + /* attributes */ + static PyObject* pyattr_get_ray_source(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_ray_target(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_ray_direction(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_hit_object(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_hit_position(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_hit_normal(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + /* --------------------------------------------------------------------- */ SCA_IObject* m_hitObject; + void* m_hitObject_Last; /* only use for comparison, never access */ private: /** @@ -112,13 +114,22 @@ class KX_MouseFocusSensor : public SCA_MouseSensor bool m_mouse_over_in_previous_frame; /** + * Flags whether changes in hit object should trigger a pulse + */ + bool m_bTouchPulse; + + /** * Flags whether the previous test evaluated positive. */ bool m_positive_event; + /** + * Tests whether the object is in mouse focus for this camera + */ + bool ParentObjectHasFocusCamera(KX_Camera *cam); /** - * Tests whether the object is in mouse focus in this frame. + * Tests whether the object is in mouse focus in this scene. */ bool ParentObjectHasFocus(void); @@ -142,12 +153,6 @@ class KX_MouseFocusSensor : public SCA_MouseSensor * the object was hit. */ MT_Vector3 m_hitNormal; - - /** - * The active canvas. The size of this canvas determines a part of - * the start position of the picking ray. */ - RAS_ICanvas* m_gp_canvas; - /** * The KX scene that holds the camera. The camera position * determines a part of the start location of the picking ray. */ diff --git a/source/gameengine/Ketsji/KX_NearSensor.cpp b/source/gameengine/Ketsji/KX_NearSensor.cpp index bae87c28123..c6a6304cb2c 100644 --- a/source/gameengine/Ketsji/KX_NearSensor.cpp +++ b/source/gameengine/Ketsji/KX_NearSensor.cpp @@ -36,33 +36,30 @@ #include "KX_Scene.h" // needed to create a replica #include "PHY_IPhysicsEnvironment.h" #include "PHY_IPhysicsController.h" - +#include "PHY_IMotionState.h" #ifdef HAVE_CONFIG_H #include <config.h> #endif KX_NearSensor::KX_NearSensor(SCA_EventManager* eventmgr, KX_GameObject* gameobj, - double margin, - double resetmargin, + float margin, + float resetmargin, bool bFindMaterial, const STR_String& touchedpropname, - class KX_Scene* scene, - PHY_IPhysicsController* ctrl, - PyTypeObject* T) + PHY_IPhysicsController* ctrl) :KX_TouchSensor(eventmgr, gameobj, bFindMaterial, - touchedpropname, - /* scene, */ - T), + false, + touchedpropname), m_Margin(margin), m_ResetMargin(resetmargin) { gameobj->getClientInfo()->m_sensors.remove(this); - m_client_info = new KX_ClientObjectInfo(gameobj, KX_ClientObjectInfo::NEAR); + m_client_info = new KX_ClientObjectInfo(gameobj, KX_ClientObjectInfo::SENSOR); m_client_info->m_sensors.push_back(this); //DT_ShapeHandle shape = (DT_ShapeHandle) vshape; @@ -81,82 +78,50 @@ void KX_NearSensor::SynchronizeTransform() // not linked to the parent object, must synchronize it. if (m_physCtrl) { + PHY_IMotionState* motionState = m_physCtrl->GetMotionState(); KX_GameObject* parent = ((KX_GameObject*)GetParent()); - MT_Vector3 pos = parent->NodeGetWorldPosition(); - MT_Quaternion orn = parent->NodeGetWorldOrientation().getRotation(); - m_physCtrl->setPosition(pos.x(),pos.y(),pos.z()); - m_physCtrl->setOrientation(orn.x(),orn.y(),orn.z(),orn.w()); - m_physCtrl->calcXform(); - } -} - -void KX_NearSensor::RegisterSumo(KX_TouchEventManager *touchman) -{ - if (m_physCtrl) - { - touchman->GetPhysicsEnvironment()->addSensor(m_physCtrl); + const MT_Point3& pos = parent->NodeGetWorldPosition(); + float ori[12]; + parent->NodeGetWorldOrientation().getValue(ori); + motionState->setWorldPosition(pos[0], pos[1], pos[2]); + motionState->setWorldOrientation(ori); + m_physCtrl->WriteMotionStateToDynamics(true); } } -void KX_NearSensor::UnregisterSumo(KX_TouchEventManager* touchman) +CValue* KX_NearSensor::GetReplica() { - if (m_physCtrl) - { - touchman->GetPhysicsEnvironment()->removeSensor(m_physCtrl); - } + KX_NearSensor* replica = new KX_NearSensor(*this); + replica->ProcessReplica(); + return replica; } -CValue* KX_NearSensor::GetReplica() +void KX_NearSensor::ProcessReplica() { - KX_NearSensor* replica = new KX_NearSensor(*this); - replica->m_colliders = new CListValue(); - replica->Init(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); + KX_TouchSensor::ProcessReplica(); - replica->m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::NEAR); + m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::SENSOR); - if (replica->m_physCtrl) + if (m_physCtrl) { - replica->m_physCtrl = replica->m_physCtrl->GetReplica(); - if (replica->m_physCtrl) + m_physCtrl = m_physCtrl->GetReplica(); + if (m_physCtrl) { //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->addSensor(replica->m_physCtrl); - replica->m_physCtrl->SetMargin(m_Margin); - replica->m_physCtrl->setNewClientInfo(replica->m_client_info); + m_physCtrl->SetMargin(m_Margin); + m_physCtrl->setNewClientInfo(m_client_info); } } - //static_cast<KX_TouchEventManager*>(m_eventmgr)->RegisterSensor(this); - //todo: make sure replication works fine - //>m_sumoObj = new SM_Object(DT_NewSphere(0.0),NULL,NULL,NULL); - //replica->m_sumoObj->setMargin(m_Margin); - //replica->m_sumoObj->setClientObject(replica->m_client_info); - - ((KX_GameObject*)replica->GetParent())->GetSGNode()->ComputeWorldTransforms(NULL); - replica->SynchronizeTransform(); - - return replica; } - - void KX_NearSensor::ReParent(SCA_IObject* parent) { + SCA_ISensor::ReParent(parent); m_client_info->m_gameobject = static_cast<KX_GameObject*>(parent); m_client_info->m_sensors.push_back(this); - - -/* KX_ClientObjectInfo *client_info = gameobj->getClientInfo(); - client_info->m_gameobject = gameobj; - client_info->m_auxilary_info = NULL; - - client_info->m_sensors.push_back(this); - SCA_ISensor::ReParent(parent); -*/ - ((KX_GameObject*)GetParent())->GetSGNode()->ComputeWorldTransforms(NULL); + //Synchronize here with the actual parent. SynchronizeTransform(); - SCA_ISensor::ReParent(parent); } @@ -177,8 +142,24 @@ KX_NearSensor::~KX_NearSensor() delete m_client_info; } +void KX_NearSensor::SetPhysCtrlRadius() +{ + if (m_bTriggered) + { + if (m_physCtrl) + { + m_physCtrl->SetRadius(m_ResetMargin); + } + } else + { + if (m_physCtrl) + { + m_physCtrl->SetRadius(m_Margin); + } + } +} -bool KX_NearSensor::Evaluate(CValue* event) +bool KX_NearSensor::Evaluate() { bool result = false; // KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent()); @@ -186,20 +167,9 @@ bool KX_NearSensor::Evaluate(CValue* event) if (m_bTriggered != m_bLastTriggered) { m_bLastTriggered = m_bTriggered; - if (m_bTriggered) - { - if (m_physCtrl) - { - m_physCtrl->SetRadius(m_ResetMargin); - } - } else - { - if (m_physCtrl) - { - m_physCtrl->SetRadius(m_Margin); - } - - } + + SetPhysCtrlRadius(); + result = true; } @@ -240,7 +210,7 @@ bool KX_NearSensor::BroadPhaseFilterCollision(void*obj1,void*obj2) bool KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData * coll_data) { // KX_TouchEventManager* toucheventmgr = static_cast<KX_TouchEventManager*>(m_eventmgr); - KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent()); +// KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent()); // need the mapping from PHY_IPhysicsController to gameobjects now @@ -272,56 +242,49 @@ bool KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData //} } - return DT_CONTINUE; + return false; // was DT_CONTINUE; but this was defined in Sumo as false } +/* ------------------------------------------------------------------------- */ +/* Python Functions */ +/* ------------------------------------------------------------------------- */ + +//No methods + +/* ------------------------------------------------------------------------- */ +/* Python Integration Hooks */ +/* ------------------------------------------------------------------------- */ -// python embedding PyTypeObject KX_NearSensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_NearSensor", - sizeof(KX_NearSensor), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - - - -PyParentObject KX_NearSensor::Parents[] = { - &KX_NearSensor::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &KX_TouchSensor::Type, - &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; - - PyMethodDef KX_NearSensor::Methods[] = { - {"setProperty", (PyCFunction) KX_NearSensor::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, - {"getProperty", (PyCFunction) KX_NearSensor::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, - {"getHitObject",(PyCFunction) KX_NearSensor::sPyGetHitObject, METH_VARARGS, (PY_METHODCHAR)GetHitObject_doc}, - {"getHitObjectList", (PyCFunction) KX_NearSensor::sPyGetHitObjectList, METH_VARARGS, (PY_METHODCHAR)GetHitObjectList_doc}, + //No methods {NULL,NULL} //Sentinel }; - -PyObject* -KX_NearSensor::_getattr(const STR_String& attr) -{ - _getattr_up(KX_TouchSensor); -} - +PyAttributeDef KX_NearSensor::Attributes[] = { + KX_PYATTRIBUTE_FLOAT_RW_CHECK("distance", 0, 100, KX_NearSensor, m_Margin, CheckResetDistance), + KX_PYATTRIBUTE_FLOAT_RW_CHECK("resetDistance", 0, 100, KX_NearSensor, m_ResetMargin, CheckResetDistance), + {NULL} //Sentinel +}; diff --git a/source/gameengine/Ketsji/KX_NearSensor.h b/source/gameengine/Ketsji/KX_NearSensor.h index 3f7078ef9fd..4f0247d209d 100644 --- a/source/gameengine/Ketsji/KX_NearSensor.h +++ b/source/gameengine/Ketsji/KX_NearSensor.h @@ -42,20 +42,18 @@ class KX_NearSensor : public KX_TouchSensor { Py_Header; protected: - double m_Margin; - double m_ResetMargin; - KX_Scene* m_scene; + float m_Margin; + float m_ResetMargin; + KX_ClientObjectInfo* m_client_info; public: KX_NearSensor(class SCA_EventManager* eventmgr, class KX_GameObject* gameobj, - double margin, - double resetmargin, + float margin, + float resetmargin, bool bFindMaterial, const STR_String& touchedpropname, - class KX_Scene* scene, - PHY_IPhysicsController* ctrl, - PyTypeObject* T=&Type); + PHY_IPhysicsController* ctrl); /* public: KX_NearSensor(class SCA_EventManager* eventmgr, @@ -64,22 +62,40 @@ public: double resetmargin, bool bFindMaterial, const STR_String& touchedpropname, - class KX_Scene* scene, - PyTypeObject* T=&Type); + class KX_Scene* scene); */ virtual ~KX_NearSensor(); virtual void SynchronizeTransform(); virtual CValue* GetReplica(); - virtual bool Evaluate(CValue* event); + virtual void ProcessReplica(); + virtual void SetPhysCtrlRadius(); + virtual bool Evaluate(); virtual void ReParent(SCA_IObject* parent); virtual bool NewHandleCollision(void* obj1,void* obj2, const PHY_CollData * coll_data); virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2); - virtual void RegisterSumo(KX_TouchEventManager *touchman); - virtual void UnregisterSumo(KX_TouchEventManager* touchman); - - virtual PyObject* _getattr(const STR_String& attr); + virtual bool BroadPhaseSensorFilterCollision(void*obj1,void*obj2) { return false; }; + virtual sensortype GetSensorType() { return ST_NEAR; } + + /* --------------------------------------------------------------------- */ + /* Python interface ---------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + + //No methods + + //This method is used to make sure the distance does not exceed the reset distance + static int CheckResetDistance(void *self, const PyAttributeDef*) + { + KX_NearSensor* sensor = reinterpret_cast<KX_NearSensor*>(self); + + if (sensor->m_Margin > sensor->m_ResetMargin) + sensor->m_ResetMargin = sensor->m_Margin; + + sensor->SetPhysCtrlRadius(); + + return 0; + } }; diff --git a/source/gameengine/Ketsji/KX_ObColorIpoSGController.h b/source/gameengine/Ketsji/KX_ObColorIpoSGController.h index 6d63dd77683..a32d027be9c 100644 --- a/source/gameengine/Ketsji/KX_ObColorIpoSGController.h +++ b/source/gameengine/Ketsji/KX_ObColorIpoSGController.h @@ -67,6 +67,13 @@ public: void AddInterpolator(KX_IInterpolator* interp); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_ObColorIpoSGController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // KX_OBCOLORIPOSGCONTROLLER_H diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp index 98e73d4f0d7..2601ced9c38 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp @@ -31,6 +31,7 @@ #include "KX_ObjectActuator.h" #include "KX_GameObject.h" +#include "KX_PyMath.h" // For PyVecTo - should this include be put in PyObjectPlus? #include "KX_IPhysicsController.h" #ifdef HAVE_CONFIG_H @@ -44,6 +45,7 @@ KX_ObjectActuator:: KX_ObjectActuator( SCA_IObject* gameobj, + KX_GameObject* refobj, const MT_Vector3& force, const MT_Vector3& torque, const MT_Vector3& dloc, @@ -51,10 +53,9 @@ KX_ObjectActuator( const MT_Vector3& linV, const MT_Vector3& angV, const short damping, - const KX_LocalFlags& flag, - PyTypeObject* T + const KX_LocalFlags& flag ) : - SCA_IActuator(gameobj,T), + SCA_IActuator(gameobj), m_force(force), m_torque(torque), m_dloc(dloc), @@ -65,21 +66,32 @@ KX_ObjectActuator( m_current_linear_factor(0.0), m_current_angular_factor(0.0), m_damping(damping), + m_previous_error(0.0,0.0,0.0), + m_error_accumulator(0.0,0.0,0.0), m_bitLocalFlag (flag), + m_reference(refobj), m_active_combined_velocity (false), m_linear_damping_active(false), - m_angular_damping_active(false), - m_error_accumulator(0.0,0.0,0.0), - m_previous_error(0.0,0.0,0.0) + m_angular_damping_active(false) { if (m_bitLocalFlag.ServoControl) { // in servo motion, the force is local if the target velocity is local m_bitLocalFlag.Force = m_bitLocalFlag.LinearVelocity; + + m_pid = m_torque; } + if (m_reference) + m_reference->RegisterActuator(this); UpdateFuzzyFlags(); } +KX_ObjectActuator::~KX_ObjectActuator() +{ + if (m_reference) + m_reference->UnregisterActuator(this); +} + bool KX_ObjectActuator::Update() { @@ -128,11 +140,23 @@ bool KX_ObjectActuator::Update() if (mass < MT_EPSILON) return false; MT_Vector3 v = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity); + if (m_reference) + { + const MT_Point3& mypos = parent->NodeGetWorldPosition(); + const MT_Point3& refpos = m_reference->NodeGetWorldPosition(); + MT_Point3 relpos; + relpos = (mypos-refpos); + MT_Vector3 vel= m_reference->GetVelocity(relpos); + if (m_bitLocalFlag.LinearVelocity) + // must convert in local space + vel = parent->NodeGetWorldOrientation().transposed()*vel; + v -= vel; + } MT_Vector3 e = m_linear_velocity - v; MT_Vector3 dv = e - m_previous_error; MT_Vector3 I = m_error_accumulator + e; - m_force = m_torque.x()*e+m_torque.y()*I+m_torque.z()*dv; + m_force = m_pid.x()*e+m_pid.y()*I+m_pid.z()*dv; // to automatically adapt the PID coefficient to mass; m_force *= mass; if (m_bitLocalFlag.Torque) @@ -253,13 +277,37 @@ CValue* KX_ObjectActuator::GetReplica() KX_ObjectActuator* replica = new KX_ObjectActuator(*this);//m_float,GetName()); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - return replica; } +void KX_ObjectActuator::ProcessReplica() +{ + SCA_IActuator::ProcessReplica(); + if (m_reference) + m_reference->RegisterActuator(this); +} + +bool KX_ObjectActuator::UnlinkObject(SCA_IObject* clientobj) +{ + if (clientobj == (SCA_IObject*)m_reference) + { + // this object is being deleted, we cannot continue to use it as reference. + m_reference = NULL; + return true; + } + return false; +} +void KX_ObjectActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + void **h_obj = (*obj_map)[m_reference]; + if (h_obj) { + if (m_reference) + m_reference->UnregisterActuator(this); + m_reference = (KX_GameObject*)(*h_obj); + m_reference->RegisterActuator(this); + } +} /* some 'standard' utilities... */ bool KX_ObjectActuator::isValid(KX_ObjectActuator::KX_OBJECT_ACT_VEC_TYPE type) @@ -277,363 +325,320 @@ bool KX_ObjectActuator::isValid(KX_ObjectActuator::KX_OBJECT_ACT_VEC_TYPE type) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_ObjectActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_ObjectActuator", - sizeof(KX_ObjectActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_ObjectActuator::Parents[] = { - &KX_ObjectActuator::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_ObjectActuator::Methods[] = { - {"getForce", (PyCFunction) KX_ObjectActuator::sPyGetForce, METH_NOARGS}, - {"setForce", (PyCFunction) KX_ObjectActuator::sPySetForce, METH_VARARGS}, - {"getTorque", (PyCFunction) KX_ObjectActuator::sPyGetTorque, METH_NOARGS}, - {"setTorque", (PyCFunction) KX_ObjectActuator::sPySetTorque, METH_VARARGS}, - {"getDLoc", (PyCFunction) KX_ObjectActuator::sPyGetDLoc, METH_NOARGS}, - {"setDLoc", (PyCFunction) KX_ObjectActuator::sPySetDLoc, METH_VARARGS}, - {"getDRot", (PyCFunction) KX_ObjectActuator::sPyGetDRot, METH_NOARGS}, - {"setDRot", (PyCFunction) KX_ObjectActuator::sPySetDRot, METH_VARARGS}, - {"getLinearVelocity", (PyCFunction) KX_ObjectActuator::sPyGetLinearVelocity, METH_NOARGS}, - {"setLinearVelocity", (PyCFunction) KX_ObjectActuator::sPySetLinearVelocity, METH_VARARGS}, - {"getAngularVelocity", (PyCFunction) KX_ObjectActuator::sPyGetAngularVelocity, METH_NOARGS}, - {"setAngularVelocity", (PyCFunction) KX_ObjectActuator::sPySetAngularVelocity, METH_VARARGS}, - {"setDamping", (PyCFunction) KX_ObjectActuator::sPySetDamping, METH_VARARGS}, - {"getDamping", (PyCFunction) KX_ObjectActuator::sPyGetDamping, METH_NOARGS}, - {"setForceLimitX", (PyCFunction) KX_ObjectActuator::sPySetForceLimitX, METH_VARARGS}, - {"getForceLimitX", (PyCFunction) KX_ObjectActuator::sPyGetForceLimitX, METH_NOARGS}, - {"setForceLimitY", (PyCFunction) KX_ObjectActuator::sPySetForceLimitY, METH_VARARGS}, - {"getForceLimitY", (PyCFunction) KX_ObjectActuator::sPyGetForceLimitY, METH_NOARGS}, - {"setForceLimitZ", (PyCFunction) KX_ObjectActuator::sPySetForceLimitZ, METH_VARARGS}, - {"getForceLimitZ", (PyCFunction) KX_ObjectActuator::sPyGetForceLimitZ, METH_NOARGS}, - {"setPID", (PyCFunction) KX_ObjectActuator::sPyGetPID, METH_NOARGS}, - {"getPID", (PyCFunction) KX_ObjectActuator::sPySetPID, METH_VARARGS}, - - - {NULL,NULL} //Sentinel }; -PyObject* KX_ObjectActuator::_getattr(const STR_String& attr) { - _getattr_up(SCA_IActuator); +PyAttributeDef KX_ObjectActuator::Attributes[] = { + KX_PYATTRIBUTE_VECTOR_RW_CHECK("force", -1000, 1000, false, KX_ObjectActuator, m_force, PyUpdateFuzzyFlags), + KX_PYATTRIBUTE_BOOL_RW("useLocalForce", KX_ObjectActuator, m_bitLocalFlag.Force), + KX_PYATTRIBUTE_VECTOR_RW_CHECK("torque", -1000, 1000, false, KX_ObjectActuator, m_torque, PyUpdateFuzzyFlags), + KX_PYATTRIBUTE_BOOL_RW("useLocalTorque", KX_ObjectActuator, m_bitLocalFlag.Torque), + KX_PYATTRIBUTE_VECTOR_RW_CHECK("dLoc", -1000, 1000, false, KX_ObjectActuator, m_dloc, PyUpdateFuzzyFlags), + KX_PYATTRIBUTE_BOOL_RW("useLocalDLoc", KX_ObjectActuator, m_bitLocalFlag.DLoc), + KX_PYATTRIBUTE_VECTOR_RW_CHECK("dRot", -1000, 1000, false, KX_ObjectActuator, m_drot, PyUpdateFuzzyFlags), + KX_PYATTRIBUTE_BOOL_RW("useLocalDRot", KX_ObjectActuator, m_bitLocalFlag.DRot), +#ifdef USE_MATHUTILS + KX_PYATTRIBUTE_RW_FUNCTION("linV", KX_ObjectActuator, pyattr_get_linV, pyattr_set_linV), + KX_PYATTRIBUTE_RW_FUNCTION("angV", KX_ObjectActuator, pyattr_get_angV, pyattr_set_angV), +#else + KX_PYATTRIBUTE_VECTOR_RW_CHECK("linV", -1000, 1000, false, KX_ObjectActuator, m_linear_velocity, PyUpdateFuzzyFlags), + KX_PYATTRIBUTE_VECTOR_RW_CHECK("angV", -1000, 1000, false, KX_ObjectActuator, m_angular_velocity, PyUpdateFuzzyFlags), +#endif + KX_PYATTRIBUTE_BOOL_RW("useLocalLinV", KX_ObjectActuator, m_bitLocalFlag.LinearVelocity), + KX_PYATTRIBUTE_BOOL_RW("useLocalAngV", KX_ObjectActuator, m_bitLocalFlag.AngularVelocity), + KX_PYATTRIBUTE_SHORT_RW("damping", 0, 1000, false, KX_ObjectActuator, m_damping), + KX_PYATTRIBUTE_RW_FUNCTION("forceLimitX", KX_ObjectActuator, pyattr_get_forceLimitX, pyattr_set_forceLimitX), + KX_PYATTRIBUTE_RW_FUNCTION("forceLimitY", KX_ObjectActuator, pyattr_get_forceLimitY, pyattr_set_forceLimitY), + KX_PYATTRIBUTE_RW_FUNCTION("forceLimitZ", KX_ObjectActuator, pyattr_get_forceLimitZ, pyattr_set_forceLimitZ), + KX_PYATTRIBUTE_VECTOR_RW_CHECK("pid", -100, 200, true, KX_ObjectActuator, m_pid, PyCheckPid), + KX_PYATTRIBUTE_RW_FUNCTION("reference", KX_ObjectActuator,pyattr_get_reference,pyattr_set_reference), + { NULL } //Sentinel }; -/* 1. set ------------------------------------------------------------------ */ -/* Removed! */ +/* Attribute get/set functions */ -/* 2. getForce */ -PyObject* KX_ObjectActuator::PyGetForce(PyObject* self) +#ifdef USE_MATHUTILS + +/* These require an SGNode */ +#define MATHUTILS_VEC_CB_LINV 1 +#define MATHUTILS_VEC_CB_ANGV 2 + +static int mathutils_kxobactu_vector_cb_index= -1; /* index for our callbacks */ + +static int mathutils_obactu_generic_check(PyObject *self_v) { - PyObject *retVal = PyList_New(4); + KX_ObjectActuator* self= static_cast<KX_ObjectActuator*>BGE_PROXY_REF(self_v); + if(self==NULL) + return 0; - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_force[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_force[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_force[2])); - PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.Force)); - - return retVal; + return 1; } -/* 3. setForce */ -PyObject* KX_ObjectActuator::PySetForce(PyObject* self, - PyObject* args, - PyObject* kwds) + +static int mathutils_obactu_vector_get(PyObject *self_v, int subtype, float *vec_from) { - float vecArg[3]; - int bToggle = 0; - if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1], - &vecArg[2], &bToggle)) { - return NULL; + KX_ObjectActuator* self= static_cast<KX_ObjectActuator*>BGE_PROXY_REF(self_v); + if(self==NULL) + return 0; + + switch(subtype) { + case MATHUTILS_VEC_CB_LINV: + self->m_linear_velocity.getValue(vec_from); + break; + case MATHUTILS_VEC_CB_ANGV: + self->m_angular_velocity.getValue(vec_from); + break; } - m_force.setValue(vecArg); - m_bitLocalFlag.Force = PyArgToBool(bToggle); - UpdateFuzzyFlags(); - Py_Return; + + return 1; } -/* 4. getTorque */ -PyObject* KX_ObjectActuator::PyGetTorque(PyObject* self) +static int mathutils_obactu_vector_set(PyObject *self_v, int subtype, float *vec_to) { - PyObject *retVal = PyList_New(4); + KX_ObjectActuator* self= static_cast<KX_ObjectActuator*>BGE_PROXY_REF(self_v); + if(self==NULL) + return 0; + + switch(subtype) { + case MATHUTILS_VEC_CB_LINV: + self->m_linear_velocity.setValue(vec_to); + break; + case MATHUTILS_VEC_CB_ANGV: + self->m_angular_velocity.setValue(vec_to); + break; + } - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_torque[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_torque[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_torque[2])); - PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.Torque)); - - return retVal; + return 1; } -/* 5. setTorque */ -PyObject* KX_ObjectActuator::PySetTorque(PyObject* self, - PyObject* args, - PyObject* kwds) + +static int mathutils_obactu_vector_get_index(PyObject *self_v, int subtype, float *vec_from, int index) { - float vecArg[3]; - int bToggle = 0; - if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1], - &vecArg[2], &bToggle)) { - return NULL; - } - m_torque.setValue(vecArg); - m_bitLocalFlag.Torque = PyArgToBool(bToggle); - UpdateFuzzyFlags(); - Py_Return; + float f[4]; + /* lazy, avoid repeteing the case statement */ + if(!mathutils_obactu_vector_get(self_v, subtype, f)) + return 0; + + vec_from[index]= f[index]; + return 1; } -/* 6. getDLoc */ -PyObject* KX_ObjectActuator::PyGetDLoc(PyObject* self) +static int mathutils_obactu_vector_set_index(PyObject *self_v, int subtype, float *vec_to, int index) { - PyObject *retVal = PyList_New(4); + float f= vec_to[index]; - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_dloc[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_dloc[2])); - PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.DLoc)); - - return retVal; + /* lazy, avoid repeteing the case statement */ + if(!mathutils_obactu_vector_get(self_v, subtype, vec_to)) + return 0; + + vec_to[index]= f; + mathutils_obactu_vector_set(self_v, subtype, vec_to); + + return 1; } -/* 7. setDLoc */ -PyObject* KX_ObjectActuator::PySetDLoc(PyObject* self, - PyObject* args, - PyObject* kwds) + +Mathutils_Callback mathutils_obactu_vector_cb = { + mathutils_obactu_generic_check, + mathutils_obactu_vector_get, + mathutils_obactu_vector_set, + mathutils_obactu_vector_get_index, + mathutils_obactu_vector_set_index +}; + +PyObject* KX_ObjectActuator::pyattr_get_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - float vecArg[3]; - int bToggle = 0; - if(!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1], - &vecArg[2], &bToggle)) { - return NULL; - } - m_dloc.setValue(vecArg); - m_bitLocalFlag.DLoc = PyArgToBool(bToggle); - UpdateFuzzyFlags(); - Py_Return; + return newVectorObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_LINV); } -/* 8. getDRot */ -PyObject* KX_ObjectActuator::PyGetDRot(PyObject* self) +int KX_ObjectActuator::pyattr_set_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - PyObject *retVal = PyList_New(4); + KX_ObjectActuator* self= static_cast<KX_ObjectActuator*>(self_v); + if (!PyVecTo(value, self->m_linear_velocity)) + return PY_SET_ATTR_FAIL; - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_drot[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_drot[2])); - PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.DRot)); - - return retVal; + return PY_SET_ATTR_SUCCESS; } -/* 9. setDRot */ -PyObject* KX_ObjectActuator::PySetDRot(PyObject* self, - PyObject* args, - PyObject* kwds) + +PyObject* KX_ObjectActuator::pyattr_get_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - float vecArg[3]; - int bToggle = 0; - if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1], - &vecArg[2], &bToggle)) { - return NULL; - } - m_drot.setValue(vecArg); - m_bitLocalFlag.DRot = PyArgToBool(bToggle); - UpdateFuzzyFlags(); - Py_Return; + return newVectorObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_ANGV); } -/* 10. getLinearVelocity */ -PyObject* KX_ObjectActuator::PyGetLinearVelocity(PyObject* self) { - PyObject *retVal = PyList_New(4); - - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2])); - PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.LinearVelocity)); - - return retVal; -} +int KX_ObjectActuator::pyattr_set_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_ObjectActuator* self= static_cast<KX_ObjectActuator*>(self_v); + if (!PyVecTo(value, self->m_angular_velocity)) + return PY_SET_ATTR_FAIL; -/* 11. setLinearVelocity */ -PyObject* KX_ObjectActuator::PySetLinearVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) { - float vecArg[3]; - int bToggle = 0; - if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1], - &vecArg[2], &bToggle)) { - return NULL; - } - m_linear_velocity.setValue(vecArg); - m_bitLocalFlag.LinearVelocity = PyArgToBool(bToggle); - UpdateFuzzyFlags(); - Py_Return; + return PY_SET_ATTR_SUCCESS; } -/* 12. getAngularVelocity */ -PyObject* KX_ObjectActuator::PyGetAngularVelocity(PyObject* self) { - PyObject *retVal = PyList_New(4); - - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_angular_velocity[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_angular_velocity[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_angular_velocity[2])); - PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.AngularVelocity)); - - return retVal; -} -/* 13. setAngularVelocity */ -PyObject* KX_ObjectActuator::PySetAngularVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) { - float vecArg[3]; - int bToggle = 0; - if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1], - &vecArg[2], &bToggle)) { - return NULL; - } - m_angular_velocity.setValue(vecArg); - m_bitLocalFlag.AngularVelocity = PyArgToBool(bToggle); - UpdateFuzzyFlags(); - Py_Return; +void KX_ObjectActuator_Mathutils_Callback_Init(void) +{ + // register mathutils callbacks, ok to run more then once. + mathutils_kxobactu_vector_cb_index= Mathutils_RegisterCallback(&mathutils_obactu_vector_cb); } -/* 13. setDamping */ -PyObject* KX_ObjectActuator::PySetDamping(PyObject* self, - PyObject* args, - PyObject* kwds) { - int damping = 0; - if (!PyArg_ParseTuple(args, "i", &damping) || damping < 0 || damping > 1000) { - return NULL; - } - m_damping = damping; - Py_Return; -} +#endif // USE_MATHUTILS -/* 13. getVelocityDamping */ -PyObject* KX_ObjectActuator::PyGetDamping(PyObject* self) { - return Py_BuildValue("i",m_damping); -} -/* 6. getForceLimitX */ -PyObject* KX_ObjectActuator::PyGetForceLimitX(PyObject* self) +PyObject* KX_ObjectActuator::pyattr_get_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { + KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v); PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[0])); - PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.Torque)); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(self->m_dloc[0])); + PyList_SET_ITEM(retVal, 2, PyBool_FromLong(self->m_bitLocalFlag.Torque)); return retVal; } -/* 7. setForceLimitX */ -PyObject* KX_ObjectActuator::PySetForceLimitX(PyObject* self, - PyObject* args, - PyObject* kwds) + +int KX_ObjectActuator::pyattr_set_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - float vecArg[2]; - int bToggle = 0; - if(!PyArg_ParseTuple(args, "ffi", &vecArg[0], &vecArg[1], &bToggle)) { - return NULL; + KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v); + + PyObject* seq = PySequence_Fast(value, ""); + if (seq && PySequence_Fast_GET_SIZE(seq) == 3) + { + self->m_drot[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0)); + self->m_dloc[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1)); + self->m_bitLocalFlag.Torque = (PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 2)) != 0); + + if (!PyErr_Occurred()) + { + Py_DECREF(seq); + return PY_SET_ATTR_SUCCESS; + } } - m_drot[0] = vecArg[0]; - m_dloc[0] = vecArg[1]; - m_bitLocalFlag.Torque = PyArgToBool(bToggle); - Py_Return; + + Py_XDECREF(seq); + + PyErr_SetString(PyExc_ValueError, "expected a sequence of 2 floats and a bool"); + return PY_SET_ATTR_FAIL; } -/* 6. getForceLimitY */ -PyObject* KX_ObjectActuator::PyGetForceLimitY(PyObject* self) +PyObject* KX_ObjectActuator::pyattr_get_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { + KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v); PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[1])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[1])); - PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.DLoc)); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[1])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(self->m_dloc[1])); + PyList_SET_ITEM(retVal, 2, PyBool_FromLong(self->m_bitLocalFlag.DLoc)); return retVal; } -/* 7. setForceLimitY */ -PyObject* KX_ObjectActuator::PySetForceLimitY(PyObject* self, - PyObject* args, - PyObject* kwds) + +int KX_ObjectActuator::pyattr_set_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - float vecArg[2]; - int bToggle = 0; - if(!PyArg_ParseTuple(args, "ffi", &vecArg[0], &vecArg[1], &bToggle)) { - return NULL; + KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v); + + PyObject* seq = PySequence_Fast(value, ""); + if (seq && PySequence_Fast_GET_SIZE(seq) == 3) + { + self->m_drot[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0)); + self->m_dloc[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1)); + self->m_bitLocalFlag.DLoc = (PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 2)) != 0); + + if (!PyErr_Occurred()) + { + Py_DECREF(seq); + return PY_SET_ATTR_SUCCESS; + } } - m_drot[1] = vecArg[0]; - m_dloc[1] = vecArg[1]; - m_bitLocalFlag.DLoc = PyArgToBool(bToggle); - Py_Return; + + Py_XDECREF(seq); + + PyErr_SetString(PyExc_ValueError, "expected a sequence of 2 floats and a bool"); + return PY_SET_ATTR_FAIL; } -/* 6. getForceLimitZ */ -PyObject* KX_ObjectActuator::PyGetForceLimitZ(PyObject* self) +PyObject* KX_ObjectActuator::pyattr_get_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { + KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v); PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[2])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[2])); - PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.DRot)); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[2])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(self->m_dloc[2])); + PyList_SET_ITEM(retVal, 2, PyBool_FromLong(self->m_bitLocalFlag.DRot)); return retVal; } -/* 7. setForceLimitZ */ -PyObject* KX_ObjectActuator::PySetForceLimitZ(PyObject* self, - PyObject* args, - PyObject* kwds) + +int KX_ObjectActuator::pyattr_set_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - float vecArg[2]; - int bToggle = 0; - if(!PyArg_ParseTuple(args, "ffi", &vecArg[0], &vecArg[1], &bToggle)) { - return NULL; + KX_ObjectActuator* self = reinterpret_cast<KX_ObjectActuator*>(self_v); + + PyObject* seq = PySequence_Fast(value, ""); + if (seq && PySequence_Fast_GET_SIZE(seq) == 3) + { + self->m_drot[2] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0)); + self->m_dloc[2] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1)); + self->m_bitLocalFlag.DRot = (PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 2)) != 0); + + if (!PyErr_Occurred()) + { + Py_DECREF(seq); + return PY_SET_ATTR_SUCCESS; + } } - m_drot[2] = vecArg[0]; - m_dloc[2] = vecArg[1]; - m_bitLocalFlag.DRot = PyArgToBool(bToggle); - Py_Return; + + Py_XDECREF(seq); + + PyErr_SetString(PyExc_ValueError, "expected a sequence of 2 floats and a bool"); + return PY_SET_ATTR_FAIL; } -/* 4. getPID */ -PyObject* KX_ObjectActuator::PyGetPID(PyObject* self) +PyObject* KX_ObjectActuator::pyattr_get_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) { - PyObject *retVal = PyList_New(3); - - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_torque[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_torque[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_torque[2])); + KX_ObjectActuator* actuator = static_cast<KX_ObjectActuator*>(self); + if (!actuator->m_reference) + Py_RETURN_NONE; - return retVal; + return actuator->m_reference->GetProxy(); } -/* 5. setPID */ -PyObject* KX_ObjectActuator::PySetPID(PyObject* self, - PyObject* args, - PyObject* kwds) + +int KX_ObjectActuator::pyattr_set_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - float vecArg[3]; - if (!PyArg_ParseTuple(args, "fff", &vecArg[0], &vecArg[1], &vecArg[2])) { - return NULL; + KX_ObjectActuator* actuator = static_cast<KX_ObjectActuator*>(self); + KX_GameObject *refOb; + + if (!ConvertPythonToGameObject(value, &refOb, true, "actu.reference = value: KX_ObjectActuator")) + return PY_SET_ATTR_FAIL; + + if (actuator->m_reference) + actuator->m_reference->UnregisterActuator(actuator); + + if(refOb==NULL) { + actuator->m_reference= NULL; } - m_torque.setValue(vecArg); - Py_Return; + else { + actuator->m_reference = refOb; + actuator->m_reference->RegisterActuator(actuator); + } + + return PY_SET_ATTR_SUCCESS; } - - - - /* eof */ diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.h b/source/gameengine/Ketsji/KX_ObjectActuator.h index aa686f41233..7a8c7de16b1 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.h +++ b/source/gameengine/Ketsji/KX_ObjectActuator.h @@ -35,8 +35,14 @@ #include "SCA_IActuator.h" #include "MT_Vector3.h" +#ifdef USE_MATHUTILS +void KX_ObjectActuator_Mathutils_Callback_Init(void); +#endif + +class KX_GameObject; + // -// Bitfield that stores the flags for each CValue derived class +// Stores the flags for each CValue derived class // struct KX_LocalFlags { KX_LocalFlags() : @@ -55,20 +61,20 @@ struct KX_LocalFlags { { } - unsigned short Force : 1; - unsigned short Torque : 1; - unsigned short DRot : 1; - unsigned short DLoc : 1; - unsigned short LinearVelocity : 1; - unsigned short AngularVelocity : 1; - unsigned short AddOrSetLinV : 1; - unsigned short ServoControl : 1; - unsigned short ZeroForce : 1; - unsigned short ZeroTorque : 1; - unsigned short ZeroDRot : 1; - unsigned short ZeroDLoc : 1; - unsigned short ZeroLinearVelocity : 1; - unsigned short ZeroAngularVelocity : 1; + bool Force; + bool Torque; + bool DRot; + bool DLoc; + bool LinearVelocity; + bool AngularVelocity; + bool AddOrSetLinV; + bool ServoControl; + bool ZeroForce; + bool ZeroTorque; + bool ZeroDRot; + bool ZeroDLoc; + bool ZeroLinearVelocity; + bool ZeroAngularVelocity; }; class KX_ObjectActuator : public SCA_IActuator @@ -80,7 +86,8 @@ class KX_ObjectActuator : public SCA_IActuator MT_Vector3 m_dloc; MT_Vector3 m_drot; MT_Vector3 m_linear_velocity; - MT_Vector3 m_angular_velocity; + MT_Vector3 m_angular_velocity; + MT_Vector3 m_pid; MT_Scalar m_linear_length2; MT_Scalar m_angular_length2; // used in damping @@ -91,7 +98,7 @@ class KX_ObjectActuator : public SCA_IActuator MT_Vector3 m_previous_error; MT_Vector3 m_error_accumulator; KX_LocalFlags m_bitLocalFlag; - + KX_GameObject* m_reference; // A hack bool -- oh no sorry everyone // This bool is used to check if we have informed // the physics object that we are no longer @@ -120,6 +127,7 @@ public: KX_ObjectActuator( SCA_IObject* gameobj, + KX_GameObject* refobj, const MT_Vector3& force, const MT_Vector3& torque, const MT_Vector3& dloc, @@ -127,11 +135,13 @@ public: const MT_Vector3& linV, const MT_Vector3& angV, const short damping, - const KX_LocalFlags& flag, - PyTypeObject* T=&Type + const KX_LocalFlags& flag ); - + ~KX_ObjectActuator(); CValue* GetReplica(); + void ProcessReplica(); + bool UnlinkObject(SCA_IObject* clientobj); + void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map); void SetForceLoc(const double force[3]) { /*m_force=force;*/ } void UpdateFuzzyFlags() @@ -152,31 +162,60 @@ public: /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - - KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForce); - KX_PYMETHOD(KX_ObjectActuator,SetForce); - KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetTorque); - KX_PYMETHOD(KX_ObjectActuator,SetTorque); - KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetDLoc); - KX_PYMETHOD(KX_ObjectActuator,SetDLoc); - KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetDRot); - KX_PYMETHOD(KX_ObjectActuator,SetDRot); - KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetLinearVelocity); - KX_PYMETHOD(KX_ObjectActuator,SetLinearVelocity); - KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetAngularVelocity); - KX_PYMETHOD(KX_ObjectActuator,SetAngularVelocity); - KX_PYMETHOD(KX_ObjectActuator,SetDamping); - KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetDamping); - KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForceLimitX); - KX_PYMETHOD(KX_ObjectActuator,SetForceLimitX); - KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForceLimitY); - KX_PYMETHOD(KX_ObjectActuator,SetForceLimitY); - KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForceLimitZ); - KX_PYMETHOD(KX_ObjectActuator,SetForceLimitZ); - KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetPID); - KX_PYMETHOD(KX_ObjectActuator,SetPID); + + /* Attributes */ + static PyObject* pyattr_get_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + +#ifdef USE_MATHUTILS + static PyObject* pyattr_get_linV(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_linV(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_angV(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_angV(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); +#endif + + // This lets the attribute macros use UpdateFuzzyFlags() + static int PyUpdateFuzzyFlags(void *self, const PyAttributeDef *attrdef) + { + KX_ObjectActuator* act = reinterpret_cast<KX_ObjectActuator*>(self); + act->UpdateFuzzyFlags(); + return 0; + } + + // This is the keep the PID values in check after they are assigned with Python + static int PyCheckPid(void *self, const PyAttributeDef *attrdef) + { + KX_ObjectActuator* act = reinterpret_cast<KX_ObjectActuator*>(self); + + //P 0 to 200 + if (act->m_pid[0] < 0) { + act->m_pid[0] = 0; + } else if (act->m_pid[0] > 200) { + act->m_pid[0] = 200; + } + + //I 0 to 3 + if (act->m_pid[1] < 0) { + act->m_pid[1] = 0; + } else if (act->m_pid[1] > 3) { + act->m_pid[1] = 3; + } + + //D -100 to 100 + if (act->m_pid[2] < -100) { + act->m_pid[2] = -100; + } else if (act->m_pid[2] > 100) { + act->m_pid[2] = 100; + } + + return 0; + } }; #endif //__KX_OBJECTACTUATOR diff --git a/source/gameengine/Ketsji/KX_OdePhysicsController.cpp b/source/gameengine/Ketsji/KX_OdePhysicsController.cpp deleted file mode 100644 index 6a701a5f25b..00000000000 --- a/source/gameengine/Ketsji/KX_OdePhysicsController.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/** - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * The contents of this file may be used under the terms of either the GNU - * General Public License Version 2 or later (the "GPL", see - * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or - * later (the "BL", see http://www.blender.org/BL/ ) which has to be - * bought from the Blender Foundation to become active, in which case the - * above mentioned GPL option does not apply. - * - * The Original Code is Copyright (C) 2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ -#include "KX_ConvertPhysicsObject.h" - -#ifdef USE_ODE - -#include "KX_OdePhysicsController.h" -#include "KX_GameObject.h" -#include "KX_MotionState.h" - -#include "MT_assert.h" - -#include "PHY_IPhysicsEnvironment.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -KX_OdePhysicsController::KX_OdePhysicsController( - bool dyna, - bool fullRigidBody, - bool phantom, - class PHY_IMotionState* motionstate, - struct dxSpace* space, - struct dxWorld* world, - float mass, - float friction, - float restitution, - bool implicitsphere, - float center[3], - float extends[3], - float radius - ) -: KX_IPhysicsController(dyna,(PHY_IPhysicsController*)this), -ODEPhysicsController( -dyna,fullRigidBody,phantom,motionstate, -space,world,mass,friction,restitution, -implicitsphere,center,extends,radius) -{ -}; - - -bool KX_OdePhysicsController::Update(double time) -{ - return SynchronizeMotionStates(time); -} - -void KX_OdePhysicsController::SetObject (SG_IObject* object) -{ - SG_Controller::SetObject(object); - - // cheating here... - KX_GameObject* gameobj = (KX_GameObject*) object->GetSGClientObject(); - gameobj->SetPhysicsController(this); - -} - - - -void KX_OdePhysicsController::applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse) -{ - ODEPhysicsController::applyImpulse(attach[0],attach[1],attach[2],impulse[0],impulse[1],impulse[2]); -} - - - -void KX_OdePhysicsController::RelativeTranslate(const MT_Vector3& dloc,bool local) -{ - ODEPhysicsController::RelativeTranslate(dloc[0],dloc[1],dloc[2],local); - -} -void KX_OdePhysicsController::RelativeRotate(const MT_Matrix3x3& drot,bool local) -{ - double oldmat[12]; - drot.getValue(oldmat); - float newmat[9]; - float *m = &newmat[0]; - double *orgm = &oldmat[0]; - - *m++ = *orgm++;*m++ = *orgm++;*m++ = *orgm++;orgm++; - *m++ = *orgm++;*m++ = *orgm++;*m++ = *orgm++;orgm++; - *m++ = *orgm++;*m++ = *orgm++;*m++ = *orgm++;orgm++; - - ODEPhysicsController::RelativeRotate(newmat,local); - -} - -void KX_OdePhysicsController::ApplyTorque(const MT_Vector3& torque,bool local) -{ - ODEPhysicsController::ApplyTorque(torque[0],torque[1],torque[2],local); - -} -void KX_OdePhysicsController::ApplyForce(const MT_Vector3& force,bool local) -{ - ODEPhysicsController::ApplyForce(force[0],force[1],force[2],local); - -} -MT_Vector3 KX_OdePhysicsController::GetLinearVelocity() -{ - return MT_Vector3(0,0,0); -} - -MT_Vector3 KX_OdePhysicsController::GetVelocity(const MT_Point3& pos) -{ - return MT_Vector3(0,0,0); -} - -void KX_OdePhysicsController::SetAngularVelocity(const MT_Vector3& ang_vel,bool local) -{ - -} -void KX_OdePhysicsController::SetLinearVelocity(const MT_Vector3& lin_vel,bool local) -{ - ODEPhysicsController::SetLinearVelocity(lin_vel[0],lin_vel[1],lin_vel[2],local); -} - -void KX_OdePhysicsController::setOrientation(const MT_Matrix3x3& rot) -{ - MT_Quaternion orn = rot.getRotation(); - ODEPhysicsController::setOrientation(orn[0],orn[1],orn[2],orn[3]); -} - -void KX_OdePhysicsController::getOrientation(MT_Quaternion& orn) -{ - float florn[4]; - florn[0]=orn[0]; - florn[1]=orn[1]; - florn[2]=orn[2]; - florn[3]=orn[3]; - ODEPhysicsController::getOrientation(florn[0],florn[1],florn[2],florn[3]); - orn[0] = florn[0]; - orn[1] = florn[1]; - orn[2] = florn[2]; - orn[3] = florn[3]; - - -} - -void KX_OdePhysicsController::setPosition(const MT_Point3& pos) -{ - ODEPhysicsController::setPosition(pos[0],pos[1],pos[2]); -} - -void KX_OdePhysicsController::setScaling(const MT_Vector3& scaling) -{ -} - -MT_Scalar KX_OdePhysicsController::GetMass() -{ - return ODEPhysicsController::getMass(); -} - -MT_Scalar KX_OdePhysicsController::GetRadius() -{ - return MT_Scalar(0.f); -} - -MT_Vector3 KX_OdePhysicsController::getReactionForce() -{ - return MT_Vector3(0,0,0); -} -void KX_OdePhysicsController::setRigidBody(bool rigid) -{ - -} - -void KX_OdePhysicsController::SuspendDynamics(bool) -{ - ODEPhysicsController::SuspendDynamics(); -} -void KX_OdePhysicsController::RestoreDynamics() -{ - ODEPhysicsController::RestoreDynamics(); -} - - -SG_Controller* KX_OdePhysicsController::GetReplica(class SG_Node* destnode) -{ - PHY_IMotionState* motionstate = new KX_MotionState(destnode); - KX_OdePhysicsController* copyctrl = new KX_OdePhysicsController(*this); - - // nlin: copied from KX_SumoPhysicsController.cpp. Not 100% sure what this does.... - // furthermore, the parentctrl is not used in ODEPhysicsController::PostProcessReplica, but - // maybe it can/should be used in the future... - - // begin copy block ------------------------------------------------------------------ - - //parentcontroller is here be able to avoid collisions between parent/child - - PHY_IPhysicsController* parentctrl = NULL; - - if (destnode != destnode->GetRootSGParent()) - { - KX_GameObject* clientgameobj = (KX_GameObject*) destnode->GetRootSGParent()->GetSGClientObject(); - if (clientgameobj) - { - parentctrl = (KX_OdePhysicsController*)clientgameobj->GetPhysicsController(); - } else - { - // it could be a false node, try the children - NodeList::const_iterator childit; - for ( - childit = destnode->GetSGChildren().begin(); - childit!= destnode->GetSGChildren().end(); - ++childit - ) { - KX_GameObject* clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); - if (clientgameobj) - { - parentctrl = (KX_OdePhysicsController*)clientgameobj->GetPhysicsController(); - } - } - } - } - // end copy block ------------------------------------------------------------------ - - copyctrl->PostProcessReplica(motionstate, this); - - return copyctrl; - -} - -void KX_OdePhysicsController::resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) -{ -} - - -void KX_OdePhysicsController::SetSumoTransform(bool nondynaonly) -{ - -} - // todo: remove next line ! -void KX_OdePhysicsController::SetSimulatedTime(double time) -{ - -} - -#endif //USE_ODE diff --git a/source/gameengine/Ketsji/KX_OdePhysicsController.h b/source/gameengine/Ketsji/KX_OdePhysicsController.h deleted file mode 100644 index 53050f6ce3e..00000000000 --- a/source/gameengine/Ketsji/KX_OdePhysicsController.h +++ /dev/null @@ -1,102 +0,0 @@ -/** - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * The contents of this file may be used under the terms of either the GNU - * General Public License Version 2 or later (the "GPL", see - * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or - * later (the "BL", see http://www.blender.org/BL/ ) which has to be - * bought from the Blender Foundation to become active, in which case the - * above mentioned GPL option does not apply. - * - * The Original Code is Copyright (C) 2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ -#ifndef __KX_ODEPHYSICSCONTROLLER_H -#define __KX_ODEPHYSICSCONTROLLER_H - -#include "KX_IPhysicsController.h" -#include "OdePhysicsController.h" - -/** - Physics Controller, a special kind of Scene Graph Transformation Controller. - It get's callbacks from Physics in case a transformation change took place. - Each time the scene graph get's updated, the controller get's a chance - in the 'Update' method to reflect changed. -*/ - -class KX_OdePhysicsController : public KX_IPhysicsController, public ODEPhysicsController - -{ - -public: - KX_OdePhysicsController( - bool dyna, - bool fullRigidBody, - bool phantom, - class PHY_IMotionState* motionstate, - struct dxSpace* space, - struct dxWorld* world, - float mass, - float friction, - float restitution, - bool implicitsphere, - float center[3], - float extends[3], - float radius); - - virtual ~KX_OdePhysicsController() {}; - - virtual void applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse); - virtual void SetObject (SG_IObject* object); - - virtual void RelativeTranslate(const MT_Vector3& dloc,bool local); - virtual void RelativeRotate(const MT_Matrix3x3& drot,bool local); - virtual void ApplyTorque(const MT_Vector3& torque,bool local); - virtual void ApplyForce(const MT_Vector3& force,bool local); - virtual MT_Vector3 GetLinearVelocity(); - virtual MT_Vector3 GetVelocity(const MT_Point3& pos); - virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local); - virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local); - virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ); - virtual void getOrientation(MT_Quaternion& orn); - virtual void setOrientation(const MT_Matrix3x3& orn); - virtual void setPosition(const MT_Point3& pos); - virtual void setScaling(const MT_Vector3& scaling); - virtual MT_Scalar GetMass(); - virtual MT_Vector3 getReactionForce(); - virtual void setRigidBody(bool rigid); - - virtual void SuspendDynamics(bool); - virtual void RestoreDynamics(); - virtual MT_Scalar GetRadius(); - - virtual SG_Controller* GetReplica(class SG_Node* destnode); - - - virtual void SetSumoTransform(bool nondynaonly); - // todo: remove next line ! - virtual void SetSimulatedTime(double time); - - // call from scene graph to update - virtual bool Update(double time); - - void - SetOption( - int option, - int value - ){ - // intentionally empty - }; - -}; - -#endif //__KX_ODEPHYSICSCONTROLLER_H - diff --git a/source/gameengine/Ketsji/KX_OrientationInterpolator.h b/source/gameengine/Ketsji/KX_OrientationInterpolator.h index 2bd9f69d824..d8ecc74277c 100644 --- a/source/gameengine/Ketsji/KX_OrientationInterpolator.h +++ b/source/gameengine/Ketsji/KX_OrientationInterpolator.h @@ -50,6 +50,13 @@ public: private: MT_Matrix3x3& m_target; KX_IScalarInterpolator *m_ipos[3]; + + +#ifdef WITH_CXX_GUARDEDALLOC +private: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_OrientationInterpolator"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Ketsji/KX_ParentActuator.cpp b/source/gameengine/Ketsji/KX_ParentActuator.cpp index eb56e8de679..20e982f03e0 100644 --- a/source/gameengine/Ketsji/KX_ParentActuator.cpp +++ b/source/gameengine/Ketsji/KX_ParentActuator.cpp @@ -1,7 +1,7 @@ /** * Set or remove an objects parent * - * $Id: SCA_ParentActuator.cpp 13932 2008-03-01 19:05:41Z ben2610 $ + * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -48,10 +48,13 @@ KX_ParentActuator::KX_ParentActuator(SCA_IObject *gameobj, int mode, - SCA_IObject *ob, - PyTypeObject* T) - : SCA_IActuator(gameobj, T), + bool addToCompound, + bool ghost, + SCA_IObject *ob) + : SCA_IActuator(gameobj), m_mode(mode), + m_addToCompound(addToCompound), + m_ghost(ghost), m_ob(ob) { if (m_ob) @@ -73,8 +76,6 @@ CValue* KX_ParentActuator::GetReplica() KX_ParentActuator* replica = new KX_ParentActuator(*this); // replication just copy the m_base pointer => common random generator replica->ProcessReplica(); - CValue::AddDataToReplica(replica); - return replica; } @@ -119,11 +120,11 @@ bool KX_ParentActuator::Update() return false; // do nothing on negative events KX_GameObject *obj = (KX_GameObject*) GetParent(); - KX_Scene *scene = PHY_GetActiveScene(); + KX_Scene *scene = KX_GetActiveScene(); switch (m_mode) { case KX_PARENT_SET: if (m_ob) - obj->SetParent(scene, (KX_GameObject*)m_ob); + obj->SetParent(scene, (KX_GameObject*)m_ob, m_addToCompound, m_ghost); break; case KX_PARENT_REMOVE: obj->RemoveParent(scene); @@ -139,83 +140,65 @@ bool KX_ParentActuator::Update() /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_ParentActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_ParentActuator", - sizeof(KX_ParentActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_ParentActuator::Parents[] = { - &KX_ParentActuator::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_ParentActuator::Methods[] = { - {"setObject", (PyCFunction) KX_ParentActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc}, - {"getObject", (PyCFunction) KX_ParentActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc}, {NULL,NULL} //Sentinel }; -PyObject* KX_ParentActuator::_getattr(const STR_String& attr) { - _getattr_up(SCA_IActuator); -} - -/* 1. setObject */ -const char KX_ParentActuator::SetObject_doc[] = -"setObject(object)\n" -"\t- object: KX_GameObject, string or None\n" -"\tSet the object to set as parent.\n"; -PyObject* KX_ParentActuator::PySetObject(PyObject* self, PyObject* value) { - KX_GameObject *gameobj; - - if (!ConvertPythonToGameObject(value, &gameobj, true)) - return NULL; // ConvertPythonToGameObject sets the error - - if (m_ob != NULL) - m_ob->UnregisterActuator(this); - - m_ob = (SCA_IObject*)gameobj; - if (m_ob) - m_ob->RegisterActuator(this); - - Py_RETURN_NONE; -} - -/* 2. getObject */ +PyAttributeDef KX_ParentActuator::Attributes[] = { + KX_PYATTRIBUTE_RW_FUNCTION("object", KX_ParentActuator, pyattr_get_object, pyattr_set_object), + KX_PYATTRIBUTE_INT_RW("mode", KX_PARENT_NODEF+1, KX_PARENT_MAX-1, true, KX_ParentActuator, m_mode), + KX_PYATTRIBUTE_BOOL_RW("compound", KX_ParentActuator, m_addToCompound), + KX_PYATTRIBUTE_BOOL_RW("ghost", KX_ParentActuator, m_ghost), + { NULL } //Sentinel +}; -/* get obj ---------------------------------------------------------- */ -const char KX_ParentActuator::GetObject_doc[] = -"getObject(name_only = 1)\n" -"name_only - optional arg, when true will return the KX_GameObject rather then its name\n" -"\tReturns the object that is set to.\n"; -PyObject* KX_ParentActuator::PyGetObject(PyObject* self, PyObject* args) +PyObject* KX_ParentActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) { - int ret_name_only = 1; - if (!PyArg_ParseTuple(args, "|i", &ret_name_only)) - return NULL; - - if (!m_ob) + KX_ParentActuator* actuator = static_cast<KX_ParentActuator*>(self); + if (!actuator->m_ob) Py_RETURN_NONE; - - if (ret_name_only) - return PyString_FromString(m_ob->GetName()); else - return m_ob->AddRef(); + return actuator->m_ob->GetProxy(); +} + +int KX_ParentActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_ParentActuator* actuator = static_cast<KX_ParentActuator*>(self); + KX_GameObject *gameobj; + + if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_ParentActuator")) + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + + if (actuator->m_ob != NULL) + actuator->m_ob->UnregisterActuator(actuator); + + actuator->m_ob = (SCA_IObject*) gameobj; + + if (actuator->m_ob) + actuator->m_ob->RegisterActuator(actuator); + + return PY_SET_ATTR_SUCCESS; } /* eof */ diff --git a/source/gameengine/Ketsji/KX_ParentActuator.h b/source/gameengine/Ketsji/KX_ParentActuator.h index e2b30ba2d0f..f750affc8a1 100644 --- a/source/gameengine/Ketsji/KX_ParentActuator.h +++ b/source/gameengine/Ketsji/KX_ParentActuator.h @@ -2,7 +2,7 @@ * Set or remove an objects parent * * - * $Id: KX_ParentActuator.h 3271 2004-10-16 11:41:50Z kester $ + * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -46,6 +46,9 @@ class KX_ParentActuator : public SCA_IActuator /** Mode */ int m_mode; + /** option */ + bool m_addToCompound; + bool m_ghost; /** Object to set as parent */ SCA_IObject *m_ob; @@ -57,13 +60,15 @@ class KX_ParentActuator : public SCA_IActuator KX_PARENT_NODEF = 0, KX_PARENT_SET, KX_PARENT_REMOVE, + KX_PARENT_MAX }; KX_ParentActuator(class SCA_IObject* gameobj, int mode, - SCA_IObject *ob, - PyTypeObject* T=&Type); + bool addToCompound, + bool ghost, + SCA_IObject *ob); virtual ~KX_ParentActuator(); virtual bool Update(); @@ -76,12 +81,9 @@ class KX_ParentActuator : public SCA_IActuator /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); - - /* 1. setObject */ - KX_PYMETHOD_DOC_O(KX_ParentActuator,SetObject); - /* 2. getObject */ - KX_PYMETHOD_DOC_VARARGS(KX_ParentActuator,GetObject); + /* These are used to get and set m_ob */ + static PyObject* pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); }; /* end of class KX_ParentActuator : public SCA_PropertyActuator */ diff --git a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp index da4f05ced7c..edb19002671 100644 --- a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp +++ b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp @@ -39,8 +39,8 @@ KX_PhysicsObjectWrapper::KX_PhysicsObjectWrapper( PHY_IPhysicsController* ctrl, - PHY_IPhysicsEnvironment* physenv,PyTypeObject *T) : - PyObjectPlus(T), + PHY_IPhysicsEnvironment* physenv) : + PyObjectPlus(), m_ctrl(ctrl), m_physenv(physenv) { @@ -51,12 +51,10 @@ KX_PhysicsObjectWrapper::~KX_PhysicsObjectWrapper() } -PyObject* KX_PhysicsObjectWrapper::PySetPosition(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_PhysicsObjectWrapper::PySetPosition(PyObject* args) { float x,y,z; - if (PyArg_ParseTuple(args,"fff",&x,&y,&z)) + if (PyArg_ParseTuple(args,"fff:setPosition",&x,&y,&z)) { m_ctrl->setPosition(x,y,z); } @@ -67,13 +65,11 @@ PyObject* KX_PhysicsObjectWrapper::PySetPosition(PyObject* self, } -PyObject* KX_PhysicsObjectWrapper::PySetLinearVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_PhysicsObjectWrapper::PySetLinearVelocity(PyObject* args) { float x,y,z; int local; - if (PyArg_ParseTuple(args,"fffi",&x,&y,&z,&local)) + if (PyArg_ParseTuple(args,"fffi:setLinearVelocity",&x,&y,&z,&local)) { m_ctrl->SetLinearVelocity(x,y,z,local != 0); } @@ -83,13 +79,11 @@ PyObject* KX_PhysicsObjectWrapper::PySetLinearVelocity(PyObject* self, Py_RETURN_NONE; } -PyObject* KX_PhysicsObjectWrapper::PySetAngularVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_PhysicsObjectWrapper::PySetAngularVelocity(PyObject* args) { float x,y,z; int local; - if (PyArg_ParseTuple(args,"fffi",&x,&y,&z,&local)) + if (PyArg_ParseTuple(args,"fffi:setAngularVelocity",&x,&y,&z,&local)) { m_ctrl->SetAngularVelocity(x,y,z,local != 0); } @@ -99,12 +93,10 @@ PyObject* KX_PhysicsObjectWrapper::PySetAngularVelocity(PyObject* self, Py_RETURN_NONE; } -PyObject* KX_PhysicsObjectWrapper::PySetActive(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_PhysicsObjectWrapper::PySetActive(PyObject* args) { int active; - if (PyArg_ParseTuple(args,"i",&active)) + if (PyArg_ParseTuple(args,"i:setActive",&active)) { m_ctrl->SetActive(active!=0); } @@ -115,60 +107,33 @@ PyObject* KX_PhysicsObjectWrapper::PySetActive(PyObject* self, } - +PyAttributeDef KX_PhysicsObjectWrapper::Attributes[] = { + { NULL } //Sentinel +}; //python specific stuff PyTypeObject KX_PhysicsObjectWrapper::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_PhysicsObjectWrapper", - sizeof(KX_PhysicsObjectWrapper), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 -}; - -PyParentObject KX_PhysicsObjectWrapper::Parents[] = { - &KX_PhysicsObjectWrapper::Type, - NULL -}; - -PyObject* KX_PhysicsObjectWrapper::_getattr(const STR_String& attr) -{ - _getattr_up(PyObjectPlus); -} - - -int KX_PhysicsObjectWrapper::_setattr(const STR_String& attr,PyObject* pyobj) -{ - PyTypeObject* type = pyobj->ob_type; - int result = 1; - - - if (type == &PyInt_Type) - { - result = 0; - } - if (type == &PyString_Type) - { - result = 0; - } - if (result) - result = PyObjectPlus::_setattr(attr,pyobj); - - return result; + PyVarObject_HEAD_INIT(NULL, 0) + "KX_PhysicsObjectWrapper", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &PyObjectPlus::Type, + 0,0,0,0,0,0, + py_base_new }; - PyMethodDef KX_PhysicsObjectWrapper::Methods[] = { {"setPosition",(PyCFunction) KX_PhysicsObjectWrapper::sPySetPosition, METH_VARARGS}, {"setLinearVelocity",(PyCFunction) KX_PhysicsObjectWrapper::sPySetLinearVelocity, METH_VARARGS}, diff --git a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.h b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.h index 3dbd1be9323..fa6fd1d1f2a 100644 --- a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.h +++ b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.h @@ -35,17 +35,14 @@ class KX_PhysicsObjectWrapper : public PyObjectPlus { Py_Header; - - virtual PyObject* _getattr(const STR_String& attr); - virtual int _setattr(const STR_String& attr, PyObject *value); public: - KX_PhysicsObjectWrapper(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsEnvironment* physenv,PyTypeObject *T = &Type); + KX_PhysicsObjectWrapper(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsEnvironment* physenv); virtual ~KX_PhysicsObjectWrapper(); - KX_PYMETHOD(KX_PhysicsObjectWrapper , SetPosition); - KX_PYMETHOD(KX_PhysicsObjectWrapper,SetLinearVelocity); - KX_PYMETHOD(KX_PhysicsObjectWrapper,SetAngularVelocity); - KX_PYMETHOD(KX_PhysicsObjectWrapper,SetActive); + KX_PYMETHOD_VARARGS(KX_PhysicsObjectWrapper,SetPosition); + KX_PYMETHOD_VARARGS(KX_PhysicsObjectWrapper,SetLinearVelocity); + KX_PYMETHOD_VARARGS(KX_PhysicsObjectWrapper,SetAngularVelocity); + KX_PYMETHOD_VARARGS(KX_PhysicsObjectWrapper,SetActive); private: class PHY_IPhysicsController* m_ctrl; diff --git a/source/gameengine/Ketsji/KX_PolyProxy.cpp b/source/gameengine/Ketsji/KX_PolyProxy.cpp index c6f6bc2db01..af8e0510a11 100644 --- a/source/gameengine/Ketsji/KX_PolyProxy.cpp +++ b/source/gameengine/Ketsji/KX_PolyProxy.cpp @@ -39,116 +39,128 @@ #include "KX_PyMath.h" PyTypeObject KX_PolyProxy::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_PolyProxy", - sizeof(KX_PolyProxy), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_PolyProxy::Parents[] = { - &KX_PolyProxy::Type, - &SCA_IObject::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_PolyProxy::Methods[] = { - KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterialIndex), - KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getNumVertex), - KX_PYMETHODTABLE_NOARG(KX_PolyProxy,isVisible), - KX_PYMETHODTABLE_NOARG(KX_PolyProxy,isCollider), - KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterialName), - KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getTextureName), + KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,getMaterialIndex), + KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,getNumVertex), + KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,isVisible), + KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,isCollider), + KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,getMaterialName), + KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,getTextureName), KX_PYMETHODTABLE(KX_PolyProxy,getVertexIndex), - KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMesh), - KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterial), + KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,getMesh), + KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,getMaterial), {NULL,NULL} //Sentinel }; -PyObject* -KX_PolyProxy::_getattr(const STR_String& attr) +PyAttributeDef KX_PolyProxy::Attributes[] = { + /* All dummy's so they come up in a dir() */ + //KX_PYATTRIBUTE_TODO("DummyProps"), + KX_PYATTRIBUTE_DUMMY("matname"), + KX_PYATTRIBUTE_DUMMY("texture"), + KX_PYATTRIBUTE_DUMMY("material"), + KX_PYATTRIBUTE_DUMMY("matid"), + KX_PYATTRIBUTE_DUMMY("v1"), + KX_PYATTRIBUTE_DUMMY("v2"), + KX_PYATTRIBUTE_DUMMY("v3"), + KX_PYATTRIBUTE_DUMMY("v4"), + KX_PYATTRIBUTE_DUMMY("visible"), + KX_PYATTRIBUTE_DUMMY("collide"), + { NULL } //Sentinel +}; + +#if 0 +PyObject* KX_PolyProxy::py_getattro(PyObject *attr) { - if (attr == "matname") + char *attr_str= _PyUnicode_AsString(attr); + if (!strcmp(attr_str, "matname")) { - return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName()); + return PyUnicode_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName()); } - if (attr == "texture") + if (!strcmp(attr_str, "texture")) { - return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName()); + return PyUnicode_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName()); } - if (attr == "material") + if (!strcmp(attr_str, "material")) { RAS_IPolyMaterial *polymat = m_polygon->GetMaterial()->GetPolyMaterial(); if(polymat->GetFlag() & RAS_BLENDERMAT) { KX_BlenderMaterial* mat = static_cast<KX_BlenderMaterial*>(polymat); - Py_INCREF(mat); - return mat; + return mat->GetProxy(); } else { KX_PolygonMaterial* mat = static_cast<KX_PolygonMaterial*>(polymat); - Py_INCREF(mat); - return mat; + return mat->GetProxy(); } } - if (attr == "matid") + if (!strcmp(attr_str, "matid")) { // we'll have to scan through the material bucket of the mes and compare with // the one of the polygon RAS_MaterialBucket* polyBucket = m_polygon->GetMaterial(); unsigned int matid; - for (matid=0; matid<m_mesh->NumMaterials(); matid++) + for (matid=0; matid<(unsigned int)m_mesh->NumMaterials(); matid++) { RAS_MeshMaterial* meshMat = m_mesh->GetMeshMaterial(matid); if (meshMat->m_bucket == polyBucket) // found it break; } - return PyInt_FromLong(matid); + return PyLong_FromSsize_t(matid); } - if (attr == "v1") + if (!strcmp(attr_str, "v1")) { - return PyInt_FromLong(m_polygon->GetVertexOffset(0)); + return PyLong_FromSsize_t(m_polygon->GetVertexOffsetAbs(m_mesh, 0)); } - if (attr == "v2") + if (!strcmp(attr_str, "v2")) { - return PyInt_FromLong(m_polygon->GetVertexOffset(1)); + return PyLong_FromSsize_t(m_polygon->GetVertexOffsetAbs(m_mesh, 1)); } - if (attr == "v3") + if (!strcmp(attr_str, "v3")) { - return PyInt_FromLong(m_polygon->GetVertexOffset(2)); + return PyLong_FromSsize_t(m_polygon->GetVertexOffsetAbs(m_mesh, 2)); } - if (attr == "v4") + if (!strcmp(attr_str, "v4")) { - return PyInt_FromLong(((m_polygon->VertexCount()>3)?m_polygon->GetVertexOffset(3):0)); + return PyLong_FromSsize_t(((m_polygon->VertexCount()>3)?m_polygon->GetVertexOffsetAbs(m_mesh, 3):0)); } - if (attr == "visible") + if (!strcmp(attr_str, "visible")) { - return PyInt_FromLong(m_polygon->IsVisible()); + return PyLong_FromSsize_t(m_polygon->IsVisible()); } - if (attr == "collide") + if (!strcmp(attr_str, "collide")) { - return PyInt_FromLong(m_polygon->IsCollider()); + return PyLong_FromSsize_t(m_polygon->IsCollider()); } - _getattr_up(SCA_IObject); + // py_getattro_up(CValue); // XXX -- todo, make all these attributes } +#endif KX_PolyProxy::KX_PolyProxy(const RAS_MeshObject*mesh, RAS_Polygon* polygon) -: m_mesh((RAS_MeshObject*)mesh), - m_polygon(polygon) +: m_polygon(polygon), + m_mesh((RAS_MeshObject*)mesh) { } @@ -162,58 +174,56 @@ CValue* KX_PolyProxy::Calc(VALUE_OPERATOR, CValue *) { return NULL;} CValue* KX_PolyProxy::CalcFinal(VALUE_DATA_TYPE, VALUE_OPERATOR, CValue *) { return NULL;} STR_String sPolyName="polygone"; const STR_String & KX_PolyProxy::GetText() {return sPolyName;}; -float KX_PolyProxy::GetNumber() { return -1;} -STR_String KX_PolyProxy::GetName() { return sPolyName;} -void KX_PolyProxy::SetName(STR_String) { }; +double KX_PolyProxy::GetNumber() { return -1;} +STR_String& KX_PolyProxy::GetName() { return sPolyName;} +void KX_PolyProxy::SetName(const char *) { }; CValue* KX_PolyProxy::GetReplica() { return NULL;} -void KX_PolyProxy::ReplicaSetName(STR_String) {}; - // stuff for python integration -KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterialIndex, +KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getMaterialIndex, "getMaterialIndex() : return the material index of the polygon in the mesh\n") { RAS_MaterialBucket* polyBucket = m_polygon->GetMaterial(); unsigned int matid; - for (matid=0; matid<m_mesh->NumMaterials(); matid++) + for (matid=0; matid<(unsigned int)m_mesh->NumMaterials(); matid++) { RAS_MeshMaterial* meshMat = m_mesh->GetMeshMaterial(matid); if (meshMat->m_bucket == polyBucket) // found it break; } - return PyInt_FromLong(matid); + return PyLong_FromSsize_t(matid); } -KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getNumVertex, +KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getNumVertex, "getNumVertex() : returns the number of vertex of the polygon, 3 or 4\n") { - return PyInt_FromLong(m_polygon->VertexCount()); + return PyLong_FromSsize_t(m_polygon->VertexCount()); } -KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, isVisible, +KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, isVisible, "isVisible() : returns whether the polygon is visible or not\n") { - return PyInt_FromLong(m_polygon->IsVisible()); + return PyLong_FromSsize_t(m_polygon->IsVisible()); } -KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, isCollider, +KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, isCollider, "isCollider() : returns whether the polygon is receives collision or not\n") { - return PyInt_FromLong(m_polygon->IsCollider()); + return PyLong_FromSsize_t(m_polygon->IsCollider()); } -KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterialName, +KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getMaterialName, "getMaterialName() : returns the polygon material name, \"NoMaterial\" if no material\n") { - return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName()); + return PyUnicode_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName()); } -KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getTextureName, +KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getTextureName, "getTexturelName() : returns the polygon texture name, \"NULL\" if no texture\n") { - return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName()); + return PyUnicode_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName()); } KX_PYMETHODDEF_DOC(KX_PolyProxy, getVertexIndex, @@ -223,43 +233,41 @@ KX_PYMETHODDEF_DOC(KX_PolyProxy, getVertexIndex, "Note: getVertexIndex(3) on a triangle polygon returns 0\n") { int index; - if (!PyArg_ParseTuple(args,"i",&index)) + if (!PyArg_ParseTuple(args,"i:getVertexIndex",&index)) { return NULL; } if (index < 0 || index > 3) { - PyErr_SetString(PyExc_AttributeError, "Valid range for index is 0-3"); + PyErr_SetString(PyExc_AttributeError, "poly.getVertexIndex(int): KX_PolyProxy, expected an index between 0-3"); return NULL; } if (index < m_polygon->VertexCount()) { - return PyInt_FromLong(m_polygon->GetVertexOffset(index)); + return PyLong_FromSsize_t(m_polygon->GetVertexOffsetAbs(m_mesh, index)); } - return PyInt_FromLong(0); + return PyLong_FromSsize_t(0); } -KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMesh, +KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getMesh, "getMesh() : returns a mesh proxy\n") { KX_MeshProxy* meshproxy = new KX_MeshProxy((RAS_MeshObject*)m_mesh); - return meshproxy; + return meshproxy->NewProxy(true); } -KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterial, +KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getMaterial, "getMaterial() : returns a material\n") { RAS_IPolyMaterial *polymat = m_polygon->GetMaterial()->GetPolyMaterial(); if(polymat->GetFlag() & RAS_BLENDERMAT) { KX_BlenderMaterial* mat = static_cast<KX_BlenderMaterial*>(polymat); - Py_INCREF(mat); - return mat; + return mat->GetProxy(); } else { KX_PolygonMaterial* mat = static_cast<KX_PolygonMaterial*>(polymat); - Py_INCREF(mat); - return mat; + return mat->GetProxy(); } } diff --git a/source/gameengine/Ketsji/KX_PolyProxy.h b/source/gameengine/Ketsji/KX_PolyProxy.h index 506e2c2a656..e619617d312 100644 --- a/source/gameengine/Ketsji/KX_PolyProxy.h +++ b/source/gameengine/Ketsji/KX_PolyProxy.h @@ -31,7 +31,7 @@ #include "SCA_IObject.h" -class KX_PolyProxy : public SCA_IObject +class KX_PolyProxy : public CValue { Py_Header; protected: @@ -45,15 +45,13 @@ public: CValue* Calc(VALUE_OPERATOR op, CValue *val) ; CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); const STR_String & GetText(); - float GetNumber(); - STR_String GetName(); - void SetName(STR_String name); // Set the name of the value - void ReplicaSetName(STR_String name); + double GetNumber(); + STR_String& GetName(); + void SetName(const char *name); // Set the name of the value CValue* GetReplica(); // stuff for python integration - virtual PyObject* _getattr(const STR_String& attr); KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterialIndex) KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getNumVertex) diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp index c9180bf3a80..5b4322ae4cd 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp @@ -51,36 +51,49 @@ #include "KX_PyMath.h" -KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname, - Material *material, - int tile, - int tilexrep, - int tileyrep, - int mode, - int transp, - bool alpha, - bool zsort, - int lightlayer, - struct MTFace* tface, - unsigned int* mcol, - PyTypeObject *T) - : PyObjectPlus(T), - RAS_IPolyMaterial(texname, - STR_String(material?material->id.name:""), +KX_PolygonMaterial::KX_PolygonMaterial() + : PyObjectPlus(), + RAS_IPolyMaterial(), + + m_tface(NULL), + m_mcol(NULL), + m_material(NULL), + m_pymaterial(NULL), + m_pass(0) +{ +} + +void KX_PolygonMaterial::Initialize( + const STR_String &texname, + Material* ma, + int materialindex, + int tile, + int tilexrep, + int tileyrep, + int mode, + int transp, + bool alpha, + bool zsort, + int lightlayer, + struct MTFace* tface, + unsigned int* mcol) +{ + RAS_IPolyMaterial::Initialize( + texname, + ma?ma->id.name:"", + materialindex, tile, tilexrep, tileyrep, mode, transp, alpha, - zsort, - lightlayer), - m_tface(tface), - m_mcol(mcol), - m_material(material), - m_pymaterial(0), - m_pass(0) -{ + zsort); + m_tface = tface; + m_mcol = mcol; + m_material = ma; + m_pymaterial = 0; + m_pass = 0; } KX_PolygonMaterial::~KX_PolygonMaterial() @@ -98,17 +111,18 @@ bool KX_PolygonMaterial::Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingI { PyObject *pyRasty = PyCObject_FromVoidPtr((void*)rasty, NULL); /* new reference */ PyObject *pyCachingInfo = PyCObject_FromVoidPtr((void*) &cachingInfo, NULL); /* new reference */ - - PyObject *ret = PyObject_CallMethod(m_pymaterial, "activate", "(NNO)", pyRasty, pyCachingInfo, (PyObject*) this); + PyObject *ret = PyObject_CallMethod(m_pymaterial, "activate", "(NNO)", pyRasty, pyCachingInfo, (PyObject*) this->m_proxy); if (ret) { - bool value = PyInt_AsLong(ret); + bool value = PyLong_AsSsize_t(ret); Py_DECREF(ret); dopass = value; } else { PyErr_Print(); + PyErr_Clear(); + PySys_SetObject( (char *)"last_traceback", NULL); } } else @@ -134,7 +148,7 @@ void KX_PolygonMaterial::DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& c if (GetCachingInfo() != cachingInfo) { if (!cachingInfo) - GPU_set_tpage(NULL); + GPU_set_tpage(NULL, 0); cachingInfo = GetCachingInfo(); @@ -142,10 +156,10 @@ void KX_PolygonMaterial::DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& c { Image *ima = (Image*)m_tface->tpage; GPU_update_image_time(ima, rasty->GetTime()); - GPU_set_tpage(m_tface); + GPU_set_tpage(m_tface, 1); } else - GPU_set_tpage(NULL); + GPU_set_tpage(NULL, 0); if(m_drawingmode & RAS_IRasterizer::KX_TWOSIDE) rasty->SetCullFace(false); @@ -157,15 +171,32 @@ void KX_PolygonMaterial::DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& c rasty->SetLines(true); else rasty->SetLines(false); + rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity); + rasty->SetShinyness(m_shininess); + rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0); + if (m_material) + rasty->SetPolygonOffset(-m_material->zoffs, 0.0); } - rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity); - rasty->SetShinyness(m_shininess); - rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0); - if (m_material) - rasty->SetPolygonOffset(-m_material->zoffs, 0.0); + //rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity); + //rasty->SetShinyness(m_shininess); + //rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0); + //if (m_material) + // rasty->SetPolygonOffset(-m_material->zoffs, 0.0); } +void KX_PolygonMaterial::GetMaterialRGBAColor(unsigned char *rgba) const +{ + if (m_material) { + *rgba++ = (unsigned char) (m_material->r*255.0); + *rgba++ = (unsigned char) (m_material->g*255.0); + *rgba++ = (unsigned char) (m_material->b*255.0); + *rgba++ = (unsigned char) (m_material->alpha*255.0); + } else + RAS_IPolyMaterial::GetMaterialRGBAColor(rgba); +} + + //---------------------------------------------------------------------------- //Python @@ -180,186 +211,65 @@ PyMethodDef KX_PolygonMaterial::Methods[] = { {NULL,NULL} //Sentinel }; +PyAttributeDef KX_PolygonMaterial::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("texture", KX_PolygonMaterial, pyattr_get_texture), + KX_PYATTRIBUTE_RO_FUNCTION("material", KX_PolygonMaterial, pyattr_get_material), /* should probably be .name ? */ + + KX_PYATTRIBUTE_INT_RW("tile", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tile), + KX_PYATTRIBUTE_INT_RW("tilexrep", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tilexrep), + KX_PYATTRIBUTE_INT_RW("tileyrep", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tileyrep), + KX_PYATTRIBUTE_INT_RW("drawingmode", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_drawingmode), + //KX_PYATTRIBUTE_INT_RW("lightlayer", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_lightlayer), -PyTypeObject KX_PolygonMaterial::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_PolygonMaterial", - sizeof(KX_PolygonMaterial), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0 //&cvalue_as_number, -}; - -PyParentObject KX_PolygonMaterial::Parents[] = { - &PyObjectPlus::Type, - &KX_PolygonMaterial::Type, - NULL -}; - -PyObject* KX_PolygonMaterial::_getattr(const STR_String& attr) -{ - if (attr == "texture") - return PyString_FromString(m_texturename.ReadPtr()); - if (attr == "material") - return PyString_FromString(m_materialname.ReadPtr()); - - if (attr == "tface") - return PyCObject_FromVoidPtr(m_tface, NULL); - - if (attr == "gl_texture") - { - Image *ima = m_tface->tpage; - int bind = 0; - if (ima) - bind = ima->bindcode; - - return PyInt_FromLong(bind); - } + KX_PYATTRIBUTE_BOOL_RW("transparent", KX_PolygonMaterial, m_alpha), + KX_PYATTRIBUTE_BOOL_RW("zsort", KX_PolygonMaterial, m_zsort), - if (attr == "tile") - return PyInt_FromLong(m_tile); - if (attr == "tilexrep") - return PyInt_FromLong(m_tilexrep); - if (attr == "tileyrep") - return PyInt_FromLong(m_tileyrep); + KX_PYATTRIBUTE_FLOAT_RW("shininess", 0.0f, 1000.0f, KX_PolygonMaterial, m_shininess), + KX_PYATTRIBUTE_FLOAT_RW("specularity", 0.0f, 1000.0f, KX_PolygonMaterial, m_specularity), - if (attr == "drawingmode") - return PyInt_FromLong(m_drawingmode); - if (attr == "transparent") - return PyInt_FromLong(m_alpha); - if (attr == "zsort") - return PyInt_FromLong(m_zsort); - if (attr == "lightlayer") - return PyInt_FromLong(m_lightlayer); - if (attr == "triangle") - // deprecated, triangle/quads shouldn't have been a material property - return 0; - - if (attr == "diffuse") - return PyObjectFrom(m_diffuse); - if (attr == "shininess") - return PyFloat_FromDouble(m_shininess); - if (attr == "specular") - return PyObjectFrom(m_specular); - if (attr == "specularity") - return PyFloat_FromDouble(m_specularity); + KX_PYATTRIBUTE_RW_FUNCTION("diffuse", KX_PolygonMaterial, pyattr_get_texture, pyattr_set_diffuse), + KX_PYATTRIBUTE_RW_FUNCTION("specular",KX_PolygonMaterial, pyattr_get_specular, pyattr_set_specular), - _getattr_up(PyObjectPlus); -} - -int KX_PolygonMaterial::_setattr(const STR_String &attr, PyObject *pyvalue) -{ - if (PyFloat_Check(pyvalue)) - { - float value = PyFloat_AsDouble(pyvalue); - if (attr == "shininess") - { - m_shininess = value; - return 0; - } - - if (attr == "specularity") - { - m_specularity = value; - return 0; - } - } - - if (PyInt_Check(pyvalue)) - { - int value = PyInt_AsLong(pyvalue); - if (attr == "tile") - { - m_tile = value; - return 0; - } - - if (attr == "tilexrep") - { - m_tilexrep = value; - return 0; - } - - if (attr == "tileyrep") - { - m_tileyrep = value; - return 0; - } - - if (attr == "drawingmode") - { - m_drawingmode = value; - return 0; - } - - if (attr == "transparent") - { - m_alpha = value; - return 0; - } - - if (attr == "zsort") - { - m_zsort = value; - return 0; - } - - if (attr == "lightlayer") - { - m_lightlayer = value; - return 0; - } - - // This probably won't work... - if (attr == "triangle") - { - // deprecated, triangle/quads shouldn't have been a material property - return 0; - } - } + KX_PYATTRIBUTE_RO_FUNCTION("tface", KX_PolygonMaterial, pyattr_get_tface), /* How the heck is this even useful??? - Campbell */ + KX_PYATTRIBUTE_RO_FUNCTION("gl_texture", KX_PolygonMaterial, pyattr_get_gl_texture), /* could be called 'bindcode' */ - if (PySequence_Check(pyvalue)) - { - if (PySequence_Size(pyvalue) == 3) - { - MT_Vector3 value; - if (PyVecTo(pyvalue, value)) - { - if (attr == "diffuse") - { - m_diffuse = value; - return 0; - } - - if (attr == "specular") - { - m_specular = value; - return 0; - } - } - } - } + /* triangle used to be an attribute, removed for 2.49, nobody should be using it */ + { NULL } //Sentinel +}; - return PyObjectPlus::_setattr(attr, pyvalue); -} +PyTypeObject KX_PolygonMaterial::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "KX_PolygonMaterial", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &PyObjectPlus::Type, + 0,0,0,0,0,0, + py_base_new +}; KX_PYMETHODDEF_DOC(KX_PolygonMaterial, setCustomMaterial, "setCustomMaterial(material)") { PyObject *material; - if (PyArg_ParseTuple(args, "O", &material)) + if (PyArg_ParseTuple(args, "O:setCustomMaterial", &material)) { - if (m_pymaterial) + if (m_pymaterial) { Py_DECREF(m_pymaterial); - + } m_pymaterial = material; Py_INCREF(m_pymaterial); - Py_Return; + Py_RETURN_NONE; } return NULL; @@ -368,14 +278,14 @@ KX_PYMETHODDEF_DOC(KX_PolygonMaterial, setCustomMaterial, "setCustomMaterial(mat KX_PYMETHODDEF_DOC(KX_PolygonMaterial, updateTexture, "updateTexture(tface, rasty)") { PyObject *pyrasty, *pytface; - if (PyArg_ParseTuple(args, "O!O!", &PyCObject_Type, &pytface, &PyCObject_Type, &pyrasty)) + if (PyArg_ParseTuple(args, "O!O!:updateTexture", &PyCObject_Type, &pytface, &PyCObject_Type, &pyrasty)) { MTFace *tface = (MTFace*) PyCObject_AsVoidPtr(pytface); RAS_IRasterizer *rasty = (RAS_IRasterizer*) PyCObject_AsVoidPtr(pyrasty); Image *ima = (Image*)tface->tpage; GPU_update_image_time(ima, rasty->GetTime()); - Py_Return; + Py_RETURN_NONE; } return NULL; @@ -384,11 +294,11 @@ KX_PYMETHODDEF_DOC(KX_PolygonMaterial, updateTexture, "updateTexture(tface, rast KX_PYMETHODDEF_DOC(KX_PolygonMaterial, setTexture, "setTexture(tface)") { PyObject *pytface; - if (PyArg_ParseTuple(args, "O!", &PyCObject_Type, &pytface)) + if (PyArg_ParseTuple(args, "O!:setTexture", &PyCObject_Type, &pytface)) { MTFace *tface = (MTFace*) PyCObject_AsVoidPtr(pytface); - GPU_set_tpage(tface); - Py_Return; + GPU_set_tpage(tface, 1); + Py_RETURN_NONE; } return NULL; @@ -397,16 +307,82 @@ KX_PYMETHODDEF_DOC(KX_PolygonMaterial, setTexture, "setTexture(tface)") KX_PYMETHODDEF_DOC(KX_PolygonMaterial, activate, "activate(rasty, cachingInfo)") { PyObject *pyrasty, *pyCachingInfo; - if (PyArg_ParseTuple(args, "O!O!", &PyCObject_Type, &pyrasty, &PyCObject_Type, &pyCachingInfo)) + if (PyArg_ParseTuple(args, "O!O!:activate", &PyCObject_Type, &pyrasty, &PyCObject_Type, &pyCachingInfo)) { RAS_IRasterizer *rasty = static_cast<RAS_IRasterizer*>(PyCObject_AsVoidPtr(pyrasty)); TCachingInfo *cachingInfo = static_cast<TCachingInfo*>(PyCObject_AsVoidPtr(pyCachingInfo)); if (rasty && cachingInfo) { DefaultActivate(rasty, *cachingInfo); - Py_Return; + Py_RETURN_NONE; } } return NULL; } + +PyObject* KX_PolygonMaterial::pyattr_get_texture(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v); + return PyUnicode_FromString(self->m_texturename.ReadPtr()); +} + +PyObject* KX_PolygonMaterial::pyattr_get_material(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v); + return PyUnicode_FromString(self->m_materialname.ReadPtr()); +} + +/* this does not seem useful */ +PyObject* KX_PolygonMaterial::pyattr_get_tface(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v); + return PyCObject_FromVoidPtr(self->m_tface, NULL); +} + +PyObject* KX_PolygonMaterial::pyattr_get_gl_texture(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v); + int bindcode= 0; + if (self->m_tface && self->m_tface->tpage) + bindcode= self->m_tface->tpage->bindcode; + + return PyLong_FromSsize_t(bindcode); +} + + +PyObject* KX_PolygonMaterial::pyattr_get_diffuse(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v); + return PyObjectFrom(self->m_diffuse); +} + +int KX_PolygonMaterial::pyattr_set_diffuse(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v); + MT_Vector3 vec; + + if (!PyVecTo(value, vec)) + return PY_SET_ATTR_FAIL; + + self->m_diffuse= vec; + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_PolygonMaterial::pyattr_get_specular(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v); + return PyObjectFrom(self->m_specular); +} + +int KX_PolygonMaterial::pyattr_set_specular(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_PolygonMaterial* self= static_cast<KX_PolygonMaterial*>(self_v); + MT_Vector3 vec; + + if (!PyVecTo(value, vec)) + return PY_SET_ATTR_FAIL; + + self->m_specular= vec; + return PY_SET_ATTR_SUCCESS; +} diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.h b/source/gameengine/Ketsji/KX_PolygonMaterial.h index fe116f757db..dc42bd2f81b 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.h +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.h @@ -33,6 +33,11 @@ #include "RAS_MaterialBucket.h" #include "RAS_IRasterizer.h" +#include "DNA_ID.h" + +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif struct MTFace; struct Material; @@ -52,14 +57,15 @@ private: MTFace* m_tface; unsigned int* m_mcol; Material* m_material; - PyObject* m_pymaterial; mutable int m_pass; public: - - KX_PolygonMaterial(const STR_String &texname, + + KX_PolygonMaterial(); + void Initialize(const STR_String &texname, Material* ma, + int materialindex, int tile, int tilexrep, int tileyrep, @@ -69,8 +75,8 @@ public: bool zsort, int lightlayer, struct MTFace* tface, - unsigned int* mcol, - PyTypeObject *T = &Type); + unsigned int* mcol); + virtual ~KX_PolygonMaterial(); /** @@ -106,8 +112,8 @@ public: { return m_mcol; } - - + virtual void GetMaterialRGBAColor(unsigned char *rgba) const; + KX_PYMETHOD_DOC(KX_PolygonMaterial, updateTexture); KX_PYMETHOD_DOC(KX_PolygonMaterial, setTexture); KX_PYMETHOD_DOC(KX_PolygonMaterial, activate); @@ -115,8 +121,18 @@ public: KX_PYMETHOD_DOC(KX_PolygonMaterial, setCustomMaterial); KX_PYMETHOD_DOC(KX_PolygonMaterial, loadProgram); - virtual PyObject* _getattr(const STR_String& attr); - virtual int _setattr(const STR_String& attr, PyObject *pyvalue); + virtual PyObject* py_repr(void) { return PyUnicode_FromString(m_material ? ((ID *)m_material)->name+2 : ""); } + + static PyObject* pyattr_get_texture(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_material(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + + static PyObject* pyattr_get_tface(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_gl_texture(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + + static PyObject* pyattr_get_diffuse(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_diffuse(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_specular(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_specular(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); }; #endif // __KX_POLYGONMATERIAL_H__ diff --git a/source/gameengine/Ketsji/KX_PositionInterpolator.h b/source/gameengine/Ketsji/KX_PositionInterpolator.h index bff0b4201c2..f6c6fa98a0e 100644 --- a/source/gameengine/Ketsji/KX_PositionInterpolator.h +++ b/source/gameengine/Ketsji/KX_PositionInterpolator.h @@ -50,6 +50,13 @@ public: private: MT_Point3& m_target; KX_IScalarInterpolator *m_ipos[3]; + + +#ifdef WITH_CXX_GUARDEDALLOC +private: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_PositionInterpolator"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp index fb37eded450..04cec3c9106 100644 --- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp +++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp @@ -33,6 +33,7 @@ #include "KX_PhysicsObjectWrapper.h" #include "PHY_IPhysicsController.h" #include "PHY_IVehicle.h" +#include "MT_Matrix3x3.h" #include "PyObjectPlus.h" @@ -381,7 +382,7 @@ static PyObject* gPyGetVehicleConstraint(PyObject* self, if (vehicle) { KX_VehicleWrapper* pyWrapper = new KX_VehicleWrapper(vehicle,PHY_GetActiveEnvironment()); - return pyWrapper; + return pyWrapper->NewProxy(true); } } @@ -404,6 +405,8 @@ static PyObject* gPyCreateConstraint(PyObject* self, int physicsid=0,physicsid2 = 0,constrainttype=0,extrainfo=0; int len = PyTuple_Size(args); int success = 1; + int flag = 0; + float pivotX=1,pivotY=1,pivotZ=1,axisX=0,axisY=0,axisZ=1; if (len == 3) { @@ -420,6 +423,11 @@ static PyObject* gPyCreateConstraint(PyObject* self, success = PyArg_ParseTuple(args,"iiiffffff",&physicsid,&physicsid2,&constrainttype, &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ); } + else if (len == 10) + { + success = PyArg_ParseTuple(args,"iiiffffffi",&physicsid,&physicsid2,&constrainttype, + &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ,&flag); + } else if (len==4) { success = PyArg_ParseTuple(args,"iiii",&physicsid,&physicsid2,&constrainttype,&extrainfo); @@ -435,12 +443,36 @@ static PyObject* gPyCreateConstraint(PyObject* self, PHY_IPhysicsController* physctrl2 = (PHY_IPhysicsController*) physicsid2; if (physctrl) //TODO:check for existance of this pointer! { - int constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,pivotX,pivotY,pivotZ,axisX,axisY,axisZ,0); + PHY_ConstraintType ct = (PHY_ConstraintType) constrainttype; + int constraintid =0; + + if (ct == PHY_GENERIC_6DOF_CONSTRAINT) + { + //convert from euler angle into axis + float radsPerDeg = 6.283185307179586232f / 360.f; + + //we need to pass a full constraint frame, not just axis + //localConstraintFrameBasis + MT_Matrix3x3 localCFrame(MT_Vector3(radsPerDeg*axisX,radsPerDeg*axisY,radsPerDeg*axisZ)); + MT_Vector3 axis0 = localCFrame.getColumn(0); + MT_Vector3 axis1 = localCFrame.getColumn(1); + MT_Vector3 axis2 = localCFrame.getColumn(2); + + constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype, + pivotX,pivotY,pivotZ, + (float)axis0.x(),(float)axis0.y(),(float)axis0.z(), + (float)axis1.x(),(float)axis1.y(),(float)axis1.z(), + (float)axis2.x(),(float)axis2.y(),(float)axis2.z(),flag); + + } else + { + constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,pivotX,pivotY,pivotZ,axisX,axisY,axisZ,0); + } KX_ConstraintWrapper* wrap = new KX_ConstraintWrapper((enum PHY_ConstraintType)constrainttype,constraintid,PHY_GetActiveEnvironment()); - return wrap; + return wrap->NewProxy(true); } @@ -510,61 +542,71 @@ static PyObject* gPyRemoveConstraint(PyObject* self, static struct PyMethodDef physicsconstraints_methods[] = { {"setGravity",(PyCFunction) gPySetGravity, - METH_VARARGS, (PY_METHODCHAR)gPySetGravity__doc__}, + METH_VARARGS, (const char *)gPySetGravity__doc__}, {"setDebugMode",(PyCFunction) gPySetDebugMode, - METH_VARARGS, (PY_METHODCHAR)gPySetDebugMode__doc__}, + METH_VARARGS, (const char *)gPySetDebugMode__doc__}, /// settings that influence quality of the rigidbody dynamics {"setNumIterations",(PyCFunction) gPySetNumIterations, - METH_VARARGS, (PY_METHODCHAR)gPySetNumIterations__doc__}, + METH_VARARGS, (const char *)gPySetNumIterations__doc__}, {"setNumTimeSubSteps",(PyCFunction) gPySetNumTimeSubSteps, - METH_VARARGS, (PY_METHODCHAR)gPySetNumTimeSubSteps__doc__}, + METH_VARARGS, (const char *)gPySetNumTimeSubSteps__doc__}, {"setDeactivationTime",(PyCFunction) gPySetDeactivationTime, - METH_VARARGS, (PY_METHODCHAR)gPySetDeactivationTime__doc__}, + METH_VARARGS, (const char *)gPySetDeactivationTime__doc__}, {"setDeactivationLinearTreshold",(PyCFunction) gPySetDeactivationLinearTreshold, - METH_VARARGS, (PY_METHODCHAR)gPySetDeactivationLinearTreshold__doc__}, + METH_VARARGS, (const char *)gPySetDeactivationLinearTreshold__doc__}, {"setDeactivationAngularTreshold",(PyCFunction) gPySetDeactivationAngularTreshold, - METH_VARARGS, (PY_METHODCHAR)gPySetDeactivationAngularTreshold__doc__}, + METH_VARARGS, (const char *)gPySetDeactivationAngularTreshold__doc__}, {"setContactBreakingTreshold",(PyCFunction) gPySetContactBreakingTreshold, - METH_VARARGS, (PY_METHODCHAR)gPySetContactBreakingTreshold__doc__}, + METH_VARARGS, (const char *)gPySetContactBreakingTreshold__doc__}, {"setCcdMode",(PyCFunction) gPySetCcdMode, - METH_VARARGS, (PY_METHODCHAR)gPySetCcdMode__doc__}, + METH_VARARGS, (const char *)gPySetCcdMode__doc__}, {"setSorConstant",(PyCFunction) gPySetSorConstant, - METH_VARARGS, (PY_METHODCHAR)gPySetSorConstant__doc__}, + METH_VARARGS, (const char *)gPySetSorConstant__doc__}, {"setSolverTau",(PyCFunction) gPySetSolverTau, - METH_VARARGS, (PY_METHODCHAR)gPySetSolverTau__doc__}, + METH_VARARGS, (const char *)gPySetSolverTau__doc__}, {"setSolverDamping",(PyCFunction) gPySetSolverDamping, - METH_VARARGS, (PY_METHODCHAR)gPySetSolverDamping__doc__}, + METH_VARARGS, (const char *)gPySetSolverDamping__doc__}, {"setLinearAirDamping",(PyCFunction) gPySetLinearAirDamping, - METH_VARARGS, (PY_METHODCHAR)gPySetLinearAirDamping__doc__}, + METH_VARARGS, (const char *)gPySetLinearAirDamping__doc__}, {"setUseEpa",(PyCFunction) gPySetUseEpa, - METH_VARARGS, (PY_METHODCHAR)gPySetUseEpa__doc__}, + METH_VARARGS, (const char *)gPySetUseEpa__doc__}, {"setSolverType",(PyCFunction) gPySetSolverType, - METH_VARARGS, (PY_METHODCHAR)gPySetSolverType__doc__}, + METH_VARARGS, (const char *)gPySetSolverType__doc__}, {"createConstraint",(PyCFunction) gPyCreateConstraint, - METH_VARARGS, (PY_METHODCHAR)gPyCreateConstraint__doc__}, + METH_VARARGS, (const char *)gPyCreateConstraint__doc__}, {"getVehicleConstraint",(PyCFunction) gPyGetVehicleConstraint, - METH_VARARGS, (PY_METHODCHAR)gPyGetVehicleConstraint__doc__}, + METH_VARARGS, (const char *)gPyGetVehicleConstraint__doc__}, {"removeConstraint",(PyCFunction) gPyRemoveConstraint, - METH_VARARGS, (PY_METHODCHAR)gPyRemoveConstraint__doc__}, + METH_VARARGS, (const char *)gPyRemoveConstraint__doc__}, {"getAppliedImpulse",(PyCFunction) gPyGetAppliedImpulse, - METH_VARARGS, (PY_METHODCHAR)gPyGetAppliedImpulse__doc__}, + METH_VARARGS, (const char *)gPyGetAppliedImpulse__doc__}, //sentinel { NULL, (PyCFunction) NULL, 0, NULL } }; - +static struct PyModuleDef PhysicsConstraints_module_def = { + {}, /* m_base */ + "PhysicsConstraints", /* m_name */ + PhysicsConstraints_module_documentation, /* m_doc */ + 0, /* m_size */ + physicsconstraints_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; PyObject* initPythonConstraintBinding() { @@ -573,15 +615,25 @@ PyObject* initPythonConstraintBinding() PyObject* m; PyObject* d; - - m = Py_InitModule4("PhysicsConstraints", physicsconstraints_methods, - PhysicsConstraints_module_documentation, - (PyObject*)NULL,PYTHON_API_VERSION); + /* Use existing module where possible + * be careful not to init any runtime vars after this */ + m = PyImport_ImportModule( "PhysicsConstraints" ); + if(m) { + Py_DECREF(m); + return m; + } + else { + PyErr_Clear(); + + m = PyModule_Create(&PhysicsConstraints_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), PhysicsConstraints_module_def.m_name, m); + } // Add some symbolic constants to the module d = PyModule_GetDict(m); - ErrorObject = PyString_FromString("PhysicsConstraints.error"); + ErrorObject = PyUnicode_FromString("PhysicsConstraints.error"); PyDict_SetItemString(d, "error", ErrorObject); + Py_DECREF(ErrorObject); // XXXX Add constants here diff --git a/source/gameengine/Ketsji/KX_PyMath.cpp b/source/gameengine/Ketsji/KX_PyMath.cpp index afb20acec2d..a41dab194dd 100644 --- a/source/gameengine/Ketsji/KX_PyMath.cpp +++ b/source/gameengine/Ketsji/KX_PyMath.cpp @@ -44,68 +44,150 @@ #include "ListValue.h" #include "KX_Python.h" +#include "KX_PyMath.h" -bool PyObject_IsMT_Matrix(PyObject *pymat, unsigned int rank) +bool PyOrientationTo(PyObject* pyval, MT_Matrix3x3 &rot, const char *error_prefix) { - if (!pymat) - return false; - - unsigned int y; - if (PySequence_Check(pymat)) + int size= PySequence_Size(pyval); + + if (size == 4) { - unsigned int rows = PySequence_Size(pymat); - if (rows != rank) - return false; + MT_Quaternion qrot; + if (PyQuatTo(pyval, qrot)) + { + rot.setRotation(qrot); + return true; + } + } + else if (size == 3) { + /* 3x3 matrix or euler */ + MT_Vector3 erot; + if (PyVecTo(pyval, erot)) + { + rot.setEuler(erot); + return true; + } + PyErr_Clear(); - bool ismatrix = true; - for (y = 0; y < rank && ismatrix; y++) + if (PyMatTo(pyval, rot)) { - PyObject *pyrow = PySequence_GetItem(pymat, y); /* new ref */ - if (PySequence_Check(pyrow)) - { - if (((unsigned int)PySequence_Size(pyrow)) != rank) - ismatrix = false; - } else - ismatrix = false; - Py_DECREF(pyrow); + return true; } - return ismatrix; } + + PyErr_Format(PyExc_TypeError, "%s, could not set the orientation from a 3x3 matrix, quaternion or euler sequence", error_prefix); return false; } +bool PyQuatTo(PyObject* pyval, MT_Quaternion &qrot) +{ + if(!PyVecTo(pyval, qrot)) + return false; + + /* annoying!, Blender/Mathutils have the W axis first! */ + MT_Scalar w= qrot[0]; /* from python, this is actually the W */ + qrot[0]= qrot[1]; + qrot[1]= qrot[2]; + qrot[2]= qrot[3]; + qrot[3]= w; + + return true; +} PyObject* PyObjectFrom(const MT_Matrix4x4 &mat) { - return Py_BuildValue("[[ffff][ffff][ffff][ffff]]", - mat[0][0], mat[0][1], mat[0][2], mat[0][3], - mat[1][0], mat[1][1], mat[1][2], mat[1][3], - mat[2][0], mat[2][1], mat[2][2], mat[2][3], - mat[3][0], mat[3][1], mat[3][2], mat[3][3]); +#ifdef USE_MATHUTILS + float fmat[16]; + mat.getValue(fmat); + return newMatrixObject(fmat, 4, 4, Py_NEW, NULL); +#else + PyObject *list = PyList_New(4); + PyObject *sublist; + int i; + + for(i=0; i < 4; i++) { + sublist = PyList_New(4); + PyList_SET_ITEM(sublist, 0, PyFloat_FromDouble(mat[i][0])); + PyList_SET_ITEM(sublist, 1, PyFloat_FromDouble(mat[i][1])); + PyList_SET_ITEM(sublist, 2, PyFloat_FromDouble(mat[i][2])); + PyList_SET_ITEM(sublist, 3, PyFloat_FromDouble(mat[i][3])); + PyList_SET_ITEM(list, i, sublist); + } + + return list; +#endif } PyObject* PyObjectFrom(const MT_Matrix3x3 &mat) { - return Py_BuildValue("[[fff][fff][fff]]", - mat[0][0], mat[0][1], mat[0][2], - mat[1][0], mat[1][1], mat[1][2], - mat[2][0], mat[2][1], mat[2][2]); +#ifdef USE_MATHUTILS + float fmat[9]; + mat.getValue3x3(fmat); + return newMatrixObject(fmat, 3, 3, Py_NEW, NULL); +#else + PyObject *list = PyList_New(3); + PyObject *sublist; + int i; + + for(i=0; i < 3; i++) { + sublist = PyList_New(3); + PyList_SET_ITEM(sublist, 0, PyFloat_FromDouble(mat[i][0])); + PyList_SET_ITEM(sublist, 1, PyFloat_FromDouble(mat[i][1])); + PyList_SET_ITEM(sublist, 2, PyFloat_FromDouble(mat[i][2])); + PyList_SET_ITEM(list, i, sublist); + } + + return list; +#endif } +#ifdef USE_MATHUTILS +PyObject* PyObjectFrom(const MT_Quaternion &qrot) +{ + /* NOTE, were re-ordering here for Mathutils compat */ + float fvec[4]= {qrot[3], qrot[0], qrot[1], qrot[2]}; + return newQuaternionObject(fvec, Py_NEW, NULL); +} +#endif + PyObject* PyObjectFrom(const MT_Tuple4 &vec) { - return Py_BuildValue("[ffff]", - vec[0], vec[1], vec[2], vec[3]); +#ifdef USE_MATHUTILS + float fvec[4]= {vec[0], vec[1], vec[2], vec[3]}; + return newVectorObject(fvec, 4, Py_NEW, NULL); +#else + PyObject *list = PyList_New(4); + PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); + PyList_SET_ITEM(list, 1, PyFloat_FromDouble(vec[1])); + PyList_SET_ITEM(list, 2, PyFloat_FromDouble(vec[2])); + PyList_SET_ITEM(list, 3, PyFloat_FromDouble(vec[3])); + return list; +#endif } PyObject* PyObjectFrom(const MT_Tuple3 &vec) { - return Py_BuildValue("[fff]", - vec[0], vec[1], vec[2]); +#ifdef USE_MATHUTILS + float fvec[3]= {vec[0], vec[1], vec[2]}; + return newVectorObject(fvec, 3, Py_NEW, NULL); +#else + PyObject *list = PyList_New(3); + PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); + PyList_SET_ITEM(list, 1, PyFloat_FromDouble(vec[1])); + PyList_SET_ITEM(list, 2, PyFloat_FromDouble(vec[2])); + return list; +#endif } PyObject* PyObjectFrom(const MT_Tuple2 &vec) { - return Py_BuildValue("[ff]", - vec[0], vec[1]); +#ifdef USE_MATHUTILS + float fvec[2]= {vec[0], vec[1]}; + return newVectorObject(fvec, 2, Py_NEW, NULL); +#else + PyObject *list = PyList_New(2); + PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); + PyList_SET_ITEM(list, 1, PyFloat_FromDouble(vec[1])); + return list; +#endif } diff --git a/source/gameengine/Ketsji/KX_PyMath.h b/source/gameengine/Ketsji/KX_PyMath.h index 4e383e9b3d4..17102905607 100644 --- a/source/gameengine/Ketsji/KX_PyMath.h +++ b/source/gameengine/Ketsji/KX_PyMath.h @@ -40,6 +40,13 @@ #include "MT_Matrix4x4.h" #include "KX_Python.h" +#include "PyObjectPlus.h" + +#ifdef USE_MATHUTILS +extern "C" { +#include "../../blender/python/generic/Mathutils.h" /* so we can have mathutils callbacks */ +} +#endif inline unsigned int Size(const MT_Matrix4x4&) { return 4; } inline unsigned int Size(const MT_Matrix3x3&) { return 3; } @@ -92,18 +99,82 @@ bool PyMatTo(PyObject* pymat, T& mat) } /** - * Converts a python list to a MT class. + * Converts a python sequence to a MT class. */ template<class T> bool PyVecTo(PyObject* pyval, T& vec) { - if (PySequence_Check(pyval)) +#ifdef USE_MATHUTILS + /* no need for BaseMath_ReadCallback() here, reading the sequences will do this */ + + if(VectorObject_Check(pyval)) { + VectorObject *pyvec= (VectorObject *)pyval; + BaseMath_ReadCallback(pyvec); + if (pyvec->size != Size(vec)) { + PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", pyvec->size, Size(vec)); + return false; + } + vec.setValue((float *) pyvec->vec); + return true; + } + else if(QuaternionObject_Check(pyval)) { + QuaternionObject *pyquat= (QuaternionObject *)pyval; + BaseMath_ReadCallback(pyquat); + if (4 != Size(vec)) { + PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", 4, Size(vec)); + return false; + } + /* xyzw -> wxyz reordering is done by PyQuatTo */ + vec.setValue((float *) pyquat->quat); + return true; + } + else if(EulerObject_Check(pyval)) { + EulerObject *pyeul= (EulerObject *)pyval; + BaseMath_ReadCallback(pyeul); + if (3 != Size(vec)) { + PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", 3, Size(vec)); + return false; + } + vec.setValue((float *) pyeul->eul); + return true; + } else +#endif + if(PyTuple_Check(pyval)) + { + unsigned int numitems = PyTuple_GET_SIZE(pyval); + if (numitems != Size(vec)) { + PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", numitems, Size(vec)); + return false; + } + + for (unsigned int x = 0; x < numitems; x++) + vec[x] = PyFloat_AsDouble(PyTuple_GET_ITEM(pyval, x)); /* borrow ref */ + + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_AttributeError, "one or more of the items in the sequence was not a float"); + return false; + } + + return true; + } + else if (PyObject_TypeCheck(pyval, &PyObjectPlus::Type)) + { /* note, include this check because PySequence_Check does too much introspection + * on the PyObject (like getting its __class__, on a BGE type this means searching up + * the parent list each time only to discover its not a sequence. + * GameObjects are often used as an alternative to vectors so this is a common case + * better to do a quick check for it, likely the error below will be ignored. + * + * This is not 'correct' since we have proxy type CListValues's which could + * contain floats/ints but there no cases of CValueLists being this way + */ + PyErr_Format(PyExc_AttributeError, "expected a sequence type"); + return false; + } + else if (PySequence_Check(pyval)) { unsigned int numitems = PySequence_Size(pyval); if (numitems != Size(vec)) { - char err[128]; - sprintf(err, "error setting vector, %d args, should be %d", numitems, Size(vec)); - PyErr_SetString(PyExc_AttributeError, err); + PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", numitems, Size(vec)); return false; } @@ -122,27 +193,16 @@ bool PyVecTo(PyObject* pyval, T& vec) return true; } else { - char err[128]; - sprintf(err, "not a sequence type, expected a sequence of numbers size %d", Size(vec)); - PyErr_SetString(PyExc_AttributeError, err); + PyErr_Format(PyExc_AttributeError, "not a sequence type, expected a sequence of numbers size %d", Size(vec)); } return false; } -/** - * Converts a python argument to an MT class. - * This paramater expects arguments as passed to a python method. - */ -template<class T> -bool PyVecArgTo(PyObject* args, T& vec) -{ - PyObject* pylist; - if (PyArg_ParseTuple(args,"O",&pylist)) - return PyVecTo(pylist, vec); - - return false; -} + +bool PyQuatTo(PyObject* pyval, MT_Quaternion &qrot); + +bool PyOrientationTo(PyObject* pyval, MT_Matrix3x3 &mat, const char *error_prefix); /** * Converts an MT_Matrix4x4 to a python object. @@ -164,15 +224,16 @@ PyObject* PyObjectFrom(const MT_Tuple2 &vec); */ PyObject* PyObjectFrom(const MT_Tuple3 &vec); +#ifdef USE_MATHUTILS /** - * Converts an MT_Tuple4 to a python object. + * Converts an MT_Quaternion to a python object. */ -PyObject* PyObjectFrom(const MT_Tuple4 &pos); +PyObject* PyObjectFrom(const MT_Quaternion &qrot); +#endif /** - * True if the given PyObject can be converted to an MT_Matrix - * @param rank = 3 (for MT_Matrix3x3) or 4 (for MT_Matrix4x4) + * Converts an MT_Tuple4 to a python object. */ -bool PyObject_IsMT_Matrix(PyObject *pymat, unsigned int rank); +PyObject* PyObjectFrom(const MT_Tuple4 &pos); #endif diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index a30d9f4022d..298d485aaaf 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -32,47 +32,61 @@ // directory header for py function getBlendFileList #include <stdlib.h> -#ifndef WIN32 - #include <dirent.h> -#else - #include "BLI_winstuff.h" -#endif #ifdef WIN32 #pragma warning (disable : 4786) #endif //WIN32 +extern "C" { + #include "bpy_internal_import.h" /* from the blender python api, but we want to import text too! */ + #include "Mathutils.h" // Blender.Mathutils module copied here so the blenderlayer can use. + #include "Geometry.h" // Blender.Geometry module copied here so the blenderlayer can use. + #include "BGL.h" +} + #include "KX_PythonInit.h" //python physics binding #include "KX_PyConstraintBinding.h" #include "KX_KetsjiEngine.h" +#include "KX_RadarSensor.h" +#include "KX_RaySensor.h" +#include "KX_SceneActuator.h" +#include "KX_GameActuator.h" +#include "KX_ParentActuator.h" +#include "KX_SCA_DynamicActuator.h" #include "SCA_IInputDevice.h" #include "SCA_PropertySensor.h" #include "SCA_RandomActuator.h" +#include "SCA_KeyboardSensor.h" /* IsPrintable, ToCharacter */ #include "KX_ConstraintActuator.h" #include "KX_IpoActuator.h" #include "KX_SoundActuator.h" +#include "KX_StateActuator.h" #include "BL_ActionActuator.h" #include "RAS_IRasterizer.h" #include "RAS_ICanvas.h" #include "RAS_BucketManager.h" +#include "RAS_2DFilterManager.h" #include "MT_Vector3.h" #include "MT_Point3.h" #include "ListValue.h" +#include "InputParser.h" #include "KX_Scene.h" -#include "SND_DeviceManager.h" #include "BL_Shader.h" #include "KX_PyMath.h" -#include "PyObjectPlus.h" +#include "PyObjectPlus.h" + +#include "KX_PythonInitTypes.h" + +/* we only need this to get a list of libraries from the main struct */ +#include "DNA_ID.h" +#include "DNA_scene_types.h" -extern "C" { - #include "Mathutils.h" // Blender.Mathutils module copied here so the blenderlayer can use. -} #include "marshal.h" /* python header for loading/saving dicts */ @@ -84,13 +98,20 @@ extern "C" { //#include "BPY_extern.h" #endif +#include "BKE_main.h" #include "BKE_utildefines.h" #include "BKE_global.h" #include "BLI_blenlib.h" #include "GPU_material.h" -static void setSandbox(TPythonSecurityLevel level); +#ifndef WIN32 + #include <dirent.h> +#else + #include "BLI_winstuff.h" +#endif +#include "NG_NetworkScene.h" //Needed for sendMessage() +static void setSandbox(TPythonSecurityLevel level); // 'local' copy of canvas ptr, for window height/width python scripts static RAS_ICanvas* gp_Canvas = NULL; @@ -98,6 +119,9 @@ static KX_Scene* gp_KetsjiScene = NULL; static KX_KetsjiEngine* gp_KetsjiEngine = NULL; static RAS_IRasterizer* gp_Rasterizer = NULL; static char gp_GamePythonPath[FILE_MAXDIR + FILE_MAXFILE] = ""; +static char gp_GamePythonPathOrig[FILE_MAXDIR + FILE_MAXFILE] = ""; // not super happy about this, but we need to remember the first loaded file for the global/dict load save +static PyObject *gp_OrigPythonSysPath= NULL; +static PyObject *gp_OrigPythonSysModules= NULL; void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color) { @@ -106,10 +130,10 @@ void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,cons } /* Macro for building the keyboard translation */ -//#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, PyInt_FromLong(SCA_IInputDevice::KX_##name)) -#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, PyInt_FromLong(name)) +//#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, PyLong_FromSsize_t(SCA_IInputDevice::KX_##name)) +#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, item=PyLong_FromSsize_t(name)); Py_DECREF(item) /* For the defines for types from logic bricks, we do stuff explicitly... */ -#define KX_MACRO_addTypesToDict(dict, name, name2) PyDict_SetItemString(dict, #name, PyInt_FromLong(name2)) +#define KX_MACRO_addTypesToDict(dict, name, name2) PyDict_SetItemString(dict, #name, item=PyLong_FromSsize_t(name2)); Py_DECREF(item) // temporarily python stuff, will be put in another place later ! @@ -118,17 +142,17 @@ void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,cons // List of methods defined in the module static PyObject* ErrorObject; -STR_String gPyGetRandomFloat_doc="getRandomFloat returns a random floating point value in the range [0..1)"; +static const char *gPyGetRandomFloat_doc="getRandomFloat returns a random floating point value in the range [0..1]"; static PyObject* gPyGetRandomFloat(PyObject*) { return PyFloat_FromDouble(MT_random()); } -static PyObject* gPySetGravity(PyObject*, PyObject* args) +static PyObject* gPySetGravity(PyObject*, PyObject* value) { - MT_Vector3 vec = MT_Vector3(0., 0., 0.); - if (!PyVecArgTo(args, vec)) + MT_Vector3 vec; + if (!PyVecTo(value, vec)) return NULL; if (gp_KetsjiScene) @@ -152,122 +176,124 @@ static PyObject* gPyExpandPath(PyObject*, PyObject* args) char expanded[FILE_MAXDIR + FILE_MAXFILE]; char* filename; - if (!PyArg_ParseTuple(args,"s",&filename)) + if (!PyArg_ParseTuple(args,"s:ExpandPath",&filename)) return NULL; BLI_strncpy(expanded, filename, FILE_MAXDIR + FILE_MAXFILE); BLI_convertstringcode(expanded, gp_GamePythonPath); - return PyString_FromString(expanded); + return PyUnicode_FromString(expanded); } +static char gPySendMessage_doc[] = +"sendMessage(subject, [body, to, from])\n\ +sends a message in same manner as a message actuator\ +subject = Subject of the message\ +body = Message body\ +to = Name of object to send the message to\ +from = Name of object to sned the string from"; + +static PyObject* gPySendMessage(PyObject*, PyObject* args) +{ + char* subject; + char* body = (char *)""; + char* to = (char *)""; + char* from = (char *)""; -static bool usedsp = false; + if (!PyArg_ParseTuple(args, "s|sss:sendMessage", &subject, &body, &to, &from)) + return NULL; + + gp_KetsjiScene->GetNetworkScene()->SendMessage(to, from, subject, body); + + Py_RETURN_NONE; +} // this gets a pointer to an array filled with floats static PyObject* gPyGetSpectrum(PyObject*) { - SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance(); - PyObject* resultlist = PyList_New(512); - if (audiodevice) - { - if (!usedsp) - { - audiodevice->StartUsingDSP(); - usedsp = true; - } - - float* spectrum = audiodevice->GetSpectrum(); - - for (int index = 0; index < 512; index++) - { - PyList_SetItem(resultlist, index, PyFloat_FromDouble(spectrum[index])); - } - } - else { - for (int index = 0; index < 512; index++) - { - PyList_SetItem(resultlist, index, PyFloat_FromDouble(0.0)); - } - } + for (int index = 0; index < 512; index++) + { + PyList_SET_ITEM(resultlist, index, PyFloat_FromDouble(0.0)); + } return resultlist; } - -static PyObject* gPyStartDSP(PyObject*, PyObject* args) +static PyObject* gPyStopDSP(PyObject*, PyObject* args) { - SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance(); + PyErr_SetString(PyExc_RuntimeError, "no audio device available"); + return NULL; + + Py_RETURN_NONE; +} - if (!audiodevice) { - PyErr_SetString(PyExc_RuntimeError, "no audio device available"); +static PyObject* gPySetLogicTicRate(PyObject*, PyObject* args) +{ + float ticrate; + if (!PyArg_ParseTuple(args, "f:setLogicTicRate", &ticrate)) return NULL; - } - - if (!usedsp) { - audiodevice->StartUsingDSP(); - usedsp = true; - } + KX_KetsjiEngine::SetTicRate(ticrate); Py_RETURN_NONE; } - - -static PyObject* gPyStopDSP(PyObject*, PyObject* args) +static PyObject* gPyGetLogicTicRate(PyObject*) { - SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance(); + return PyFloat_FromDouble(KX_KetsjiEngine::GetTicRate()); +} - if (!audiodevice) { - PyErr_SetString(PyExc_RuntimeError, "no audio device available"); +static PyObject* gPySetMaxLogicFrame(PyObject*, PyObject* args) +{ + int frame; + if (!PyArg_ParseTuple(args, "i:setMaxLogicFrame", &frame)) return NULL; - } - - if (usedsp) { - audiodevice->StopUsingDSP(); - usedsp = true; - } + KX_KetsjiEngine::SetMaxLogicFrame(frame); Py_RETURN_NONE; } -static PyObject* gPySetLogicTicRate(PyObject*, PyObject* args) +static PyObject* gPyGetMaxLogicFrame(PyObject*) { - float ticrate; - if (!PyArg_ParseTuple(args, "f", &ticrate)) + return PyLong_FromSsize_t(KX_KetsjiEngine::GetMaxLogicFrame()); +} + +static PyObject* gPySetMaxPhysicsFrame(PyObject*, PyObject* args) +{ + int frame; + if (!PyArg_ParseTuple(args, "i:setMaxPhysicsFrame", &frame)) return NULL; - KX_KetsjiEngine::SetTicRate(ticrate); + KX_KetsjiEngine::SetMaxPhysicsFrame(frame); Py_RETURN_NONE; } -static PyObject* gPyGetLogicTicRate(PyObject*) +static PyObject* gPyGetMaxPhysicsFrame(PyObject*) { - return PyFloat_FromDouble(KX_KetsjiEngine::GetTicRate()); + return PyLong_FromSsize_t(KX_KetsjiEngine::GetMaxPhysicsFrame()); } static PyObject* gPySetPhysicsTicRate(PyObject*, PyObject* args) { float ticrate; - if (!PyArg_ParseTuple(args, "f", &ticrate)) + if (!PyArg_ParseTuple(args, "f:setPhysicsTicRate", &ticrate)) return NULL; PHY_GetActiveEnvironment()->setFixedTimeStep(true,ticrate); Py_RETURN_NONE; } - +#if 0 // unused static PyObject* gPySetPhysicsDebug(PyObject*, PyObject* args) { int debugMode; - if (!PyArg_ParseTuple(args, "i", &debugMode)) + if (!PyArg_ParseTuple(args, "i:setPhysicsDebug", &debugMode)) return NULL; PHY_GetActiveEnvironment()->setDebugMode(debugMode); Py_RETURN_NONE; } - +#endif static PyObject* gPyGetPhysicsTicRate(PyObject*) @@ -289,7 +315,7 @@ static PyObject* gPyGetBlendFileList(PyObject*, PyObject* args) DIR *dp; struct dirent *dirp; - if (!PyArg_ParseTuple(args, "|s", &searchpath)) + if (!PyArg_ParseTuple(args, "|s:getBlendFileList", &searchpath)) return NULL; list = PyList_New(0); @@ -310,7 +336,7 @@ static PyObject* gPyGetBlendFileList(PyObject*, PyObject* args) while ((dirp = readdir(dp)) != NULL) { if (BLI_testextensie(dirp->d_name, ".blend")) { - value = PyString_FromString(dirp->d_name); + value = PyUnicode_FromString(dirp->d_name); PyList_Append(list, value); Py_DECREF(value); } @@ -320,13 +346,34 @@ static PyObject* gPyGetBlendFileList(PyObject*, PyObject* args) return list; } -static STR_String gPyGetCurrentScene_doc = +static const char *gPyGetCurrentScene_doc = "getCurrentScene()\n" "Gets a reference to the current scene.\n"; static PyObject* gPyGetCurrentScene(PyObject* self) { - Py_INCREF(gp_KetsjiScene); - return (PyObject*) gp_KetsjiScene; + return gp_KetsjiScene->GetProxy(); +} + +static const char *gPyGetSceneList_doc = +"getSceneList()\n" +"Return a list of converted scenes.\n"; +static PyObject* gPyGetSceneList(PyObject* self) +{ + KX_KetsjiEngine* m_engine = KX_GetActiveEngine(); + PyObject* list; + KX_SceneList* scenes = m_engine->CurrentScenes(); + int numScenes = scenes->size(); + int i; + + list = PyList_New(numScenes); + + for (i=0;i<numScenes;i++) + { + KX_Scene* scene = scenes->at(i); + PyList_SET_ITEM(list, i, scene->GetProxy()); + } + + return list; } static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *) @@ -402,40 +449,44 @@ static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *) static struct PyMethodDef game_methods[] = { - {"expandPath", (PyCFunction)gPyExpandPath, METH_VARARGS, (PY_METHODCHAR)gPyExpandPath_doc}, + {"expandPath", (PyCFunction)gPyExpandPath, METH_VARARGS, (const char *)gPyExpandPath_doc}, + {"sendMessage", (PyCFunction)gPySendMessage, METH_VARARGS, (const char *)gPySendMessage_doc}, {"getCurrentController", (PyCFunction) SCA_PythonController::sPyGetCurrentController, - METH_NOARGS, (PY_METHODCHAR)SCA_PythonController::sPyGetCurrentController__doc__}, + METH_NOARGS, SCA_PythonController::sPyGetCurrentController__doc__}, {"getCurrentScene", (PyCFunction) gPyGetCurrentScene, - METH_NOARGS, (PY_METHODCHAR)gPyGetCurrentScene_doc.Ptr()}, - {"addActiveActuator",(PyCFunction) SCA_PythonController::sPyAddActiveActuator, - METH_VARARGS, (PY_METHODCHAR)SCA_PythonController::sPyAddActiveActuator__doc__}, + METH_NOARGS, gPyGetCurrentScene_doc}, + {"getSceneList", (PyCFunction) gPyGetSceneList, + METH_NOARGS, (const char *)gPyGetSceneList_doc}, {"getRandomFloat",(PyCFunction) gPyGetRandomFloat, - METH_NOARGS, (PY_METHODCHAR)gPyGetRandomFloat_doc.Ptr()}, - {"setGravity",(PyCFunction) gPySetGravity, METH_VARARGS, (PY_METHODCHAR)"set Gravitation"}, - {"getSpectrum",(PyCFunction) gPyGetSpectrum, METH_NOARGS, (PY_METHODCHAR)"get audio spectrum"}, - {"stopDSP",(PyCFunction) gPyStopDSP, METH_VARARGS, (PY_METHODCHAR)"stop using the audio dsp (for performance reasons)"}, - {"getLogicTicRate", (PyCFunction) gPyGetLogicTicRate, METH_NOARGS, (PY_METHODCHAR)"Gets the logic tic rate"}, - {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, (PY_METHODCHAR)"Sets the logic tic rate"}, - {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_NOARGS, (PY_METHODCHAR)"Gets the physics tic rate"}, - {"setPhysicsTicRate", (PyCFunction) gPySetPhysicsTicRate, METH_VARARGS, (PY_METHODCHAR)"Sets the physics tic rate"}, - {"getAverageFrameRate", (PyCFunction) gPyGetAverageFrameRate, METH_NOARGS, (PY_METHODCHAR)"Gets the estimated average frame rate"}, - {"getBlendFileList", (PyCFunction)gPyGetBlendFileList, METH_VARARGS, (PY_METHODCHAR)"Gets a list of blend files in the same directory as the current blend file"}, - {"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, (PY_METHODCHAR)"Prints GL Extension Info"}, + METH_NOARGS, (const char *)gPyGetRandomFloat_doc}, + {"setGravity",(PyCFunction) gPySetGravity, METH_O, (const char *)"set Gravitation"}, + {"getSpectrum",(PyCFunction) gPyGetSpectrum, METH_NOARGS, (const char *)"get audio spectrum"}, + {"stopDSP",(PyCFunction) gPyStopDSP, METH_VARARGS, (const char *)"stop using the audio dsp (for performance reasons)"}, + {"getMaxLogicFrame", (PyCFunction) gPyGetMaxLogicFrame, METH_NOARGS, (const char *)"Gets the max number of logic frame per render frame"}, + {"setMaxLogicFrame", (PyCFunction) gPySetMaxLogicFrame, METH_VARARGS, (const char *)"Sets the max number of logic frame per render frame"}, + {"getMaxPhysicsFrame", (PyCFunction) gPyGetMaxPhysicsFrame, METH_NOARGS, (const char *)"Gets the max number of physics frame per render frame"}, + {"setMaxPhysicsFrame", (PyCFunction) gPySetMaxPhysicsFrame, METH_VARARGS, (const char *)"Sets the max number of physics farme per render frame"}, + {"getLogicTicRate", (PyCFunction) gPyGetLogicTicRate, METH_NOARGS, (const char *)"Gets the logic tic rate"}, + {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, (const char *)"Sets the logic tic rate"}, + {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_NOARGS, (const char *)"Gets the physics tic rate"}, + {"setPhysicsTicRate", (PyCFunction) gPySetPhysicsTicRate, METH_VARARGS, (const char *)"Sets the physics tic rate"}, + {"getAverageFrameRate", (PyCFunction) gPyGetAverageFrameRate, METH_NOARGS, (const char *)"Gets the estimated average frame rate"}, + {"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"}, {NULL, (PyCFunction) NULL, 0, NULL } }; - static PyObject* gPyGetWindowHeight(PyObject*, PyObject* args) { - return PyInt_FromLong((gp_Canvas ? gp_Canvas->GetHeight() : 0)); + return PyLong_FromSsize_t((gp_Canvas ? gp_Canvas->GetHeight() : 0)); } static PyObject* gPyGetWindowWidth(PyObject*, PyObject* args) { - return PyInt_FromLong((gp_Canvas ? gp_Canvas->GetWidth() : 0)); + return PyLong_FromSsize_t((gp_Canvas ? gp_Canvas->GetWidth() : 0)); } @@ -446,7 +497,7 @@ bool gUseVisibilityTemp = false; static PyObject* gPyEnableVisibility(PyObject*, PyObject* args) { int visible; - if (!PyArg_ParseTuple(args,"i",&visible)) + if (!PyArg_ParseTuple(args,"i:enableVisibility",&visible)) return NULL; gUseVisibilityTemp = (visible != 0); @@ -458,7 +509,7 @@ static PyObject* gPyEnableVisibility(PyObject*, PyObject* args) static PyObject* gPyShowMouse(PyObject*, PyObject* args) { int visible; - if (!PyArg_ParseTuple(args,"i",&visible)) + if (!PyArg_ParseTuple(args,"i:showMouse",&visible)) return NULL; if (visible) @@ -479,7 +530,7 @@ static PyObject* gPyShowMouse(PyObject*, PyObject* args) static PyObject* gPySetMousePosition(PyObject*, PyObject* args) { int x,y; - if (!PyArg_ParseTuple(args,"ii",&x,&y)) + if (!PyArg_ParseTuple(args,"ii:setMousePosition",&x,&y)) return NULL; if (gp_Canvas) @@ -491,11 +542,11 @@ static PyObject* gPySetMousePosition(PyObject*, PyObject* args) static PyObject* gPySetEyeSeparation(PyObject*, PyObject* args) { float sep; - if (!PyArg_ParseTuple(args, "f", &sep)) + if (!PyArg_ParseTuple(args, "f:setEyeSeparation", &sep)) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setEyeSeparation(float), Rasterizer not available"); return NULL; } @@ -504,10 +555,10 @@ static PyObject* gPySetEyeSeparation(PyObject*, PyObject* args) Py_RETURN_NONE; } -static PyObject* gPyGetEyeSeparation(PyObject*, PyObject*, PyObject*) +static PyObject* gPyGetEyeSeparation(PyObject*) { if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.getEyeSeparation(), Rasterizer not available"); return NULL; } @@ -517,11 +568,11 @@ static PyObject* gPyGetEyeSeparation(PyObject*, PyObject*, PyObject*) static PyObject* gPySetFocalLength(PyObject*, PyObject* args) { float focus; - if (!PyArg_ParseTuple(args, "f", &focus)) + if (!PyArg_ParseTuple(args, "f:setFocalLength", &focus)) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setFocalLength(float), Rasterizer not available"); return NULL; } @@ -533,7 +584,7 @@ static PyObject* gPySetFocalLength(PyObject*, PyObject* args) static PyObject* gPyGetFocalLength(PyObject*, PyObject*, PyObject*) { if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.getFocalLength(), Rasterizer not available"); return NULL; } @@ -542,11 +593,11 @@ static PyObject* gPyGetFocalLength(PyObject*, PyObject*, PyObject*) Py_RETURN_NONE; } -static PyObject* gPySetBackgroundColor(PyObject*, PyObject* args) +static PyObject* gPySetBackgroundColor(PyObject*, PyObject* value) { - MT_Vector4 vec = MT_Vector4(0., 0., 0.3, 0.); - if (!PyVecArgTo(args, vec)) + MT_Vector4 vec; + if (!PyVecTo(value, vec)) return NULL; if (gp_Canvas) @@ -558,15 +609,15 @@ static PyObject* gPySetBackgroundColor(PyObject*, PyObject* args) -static PyObject* gPySetMistColor(PyObject*, PyObject* args) +static PyObject* gPySetMistColor(PyObject*, PyObject* value) { - MT_Vector3 vec = MT_Vector3(0., 0., 0.); - if (!PyVecArgTo(args, vec)) + MT_Vector3 vec; + if (!PyVecTo(value, vec)) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistColor(color), Rasterizer not available"); return NULL; } gp_Rasterizer->SetFogColor(vec[0], vec[1], vec[2]); @@ -574,17 +625,28 @@ static PyObject* gPySetMistColor(PyObject*, PyObject* args) Py_RETURN_NONE; } +static PyObject* gPyDisableMist(PyObject*) +{ + + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistColor(color), Rasterizer not available"); + return NULL; + } + gp_Rasterizer->DisableFog(); + + Py_RETURN_NONE; +} static PyObject* gPySetMistStart(PyObject*, PyObject* args) { float miststart; - if (!PyArg_ParseTuple(args,"f",&miststart)) + if (!PyArg_ParseTuple(args,"f:setMistStart",&miststart)) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistStart(float), Rasterizer not available"); return NULL; } @@ -599,11 +661,11 @@ static PyObject* gPySetMistEnd(PyObject*, PyObject* args) { float mistend; - if (!PyArg_ParseTuple(args,"f",&mistend)) + if (!PyArg_ParseTuple(args,"f:setMistEnd",&mistend)) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistEnd(float), Rasterizer not available"); return NULL; } @@ -613,15 +675,15 @@ static PyObject* gPySetMistEnd(PyObject*, PyObject* args) } -static PyObject* gPySetAmbientColor(PyObject*, PyObject* args) +static PyObject* gPySetAmbientColor(PyObject*, PyObject* value) { - MT_Vector3 vec = MT_Vector3(0., 0., 0.); - if (!PyVecArgTo(args, vec)) + MT_Vector3 vec; + if (!PyVecTo(value, vec)) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setAmbientColor(color), Rasterizer not available"); return NULL; } gp_Rasterizer->SetAmbientColor(vec[0], vec[1], vec[2]); @@ -635,7 +697,7 @@ static PyObject* gPySetAmbientColor(PyObject*, PyObject* args) static PyObject* gPyMakeScreenshot(PyObject*, PyObject* args) { char* filename; - if (!PyArg_ParseTuple(args,"s",&filename)) + if (!PyArg_ParseTuple(args,"s:makeScreenshot",&filename)) return NULL; if (gp_Canvas) @@ -649,11 +711,11 @@ static PyObject* gPyMakeScreenshot(PyObject*, PyObject* args) static PyObject* gPyEnableMotionBlur(PyObject*, PyObject* args) { float motionblurvalue; - if (!PyArg_ParseTuple(args,"f",&motionblurvalue)) + if (!PyArg_ParseTuple(args,"f:enableMotionBlur",&motionblurvalue)) return NULL; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.enableMotionBlur(float), Rasterizer not available"); return NULL; } @@ -662,10 +724,10 @@ static PyObject* gPyEnableMotionBlur(PyObject*, PyObject* args) Py_RETURN_NONE; } -static PyObject* gPyDisableMotionBlur(PyObject*, PyObject* args) +static PyObject* gPyDisableMotionBlur(PyObject*) { if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.disableMotionBlur(), Rasterizer not available"); return NULL; } @@ -677,17 +739,17 @@ static PyObject* gPyDisableMotionBlur(PyObject*, PyObject* args) int getGLSLSettingFlag(char *setting) { if(strcmp(setting, "lights") == 0) - return G_FILE_GLSL_NO_LIGHTS; + return GAME_GLSL_NO_LIGHTS; else if(strcmp(setting, "shaders") == 0) - return G_FILE_GLSL_NO_SHADERS; + return GAME_GLSL_NO_SHADERS; else if(strcmp(setting, "shadows") == 0) - return G_FILE_GLSL_NO_SHADOWS; + return GAME_GLSL_NO_SHADOWS; else if(strcmp(setting, "ramps") == 0) - return G_FILE_GLSL_NO_RAMPS; + return GAME_GLSL_NO_RAMPS; else if(strcmp(setting, "nodes") == 0) - return G_FILE_GLSL_NO_NODES; + return GAME_GLSL_NO_NODES; else if(strcmp(setting, "extra_textures") == 0) - return G_FILE_GLSL_NO_EXTRA_TEX; + return GAME_GLSL_NO_EXTRA_TEX; else return -1; } @@ -696,38 +758,40 @@ static PyObject* gPySetGLSLMaterialSetting(PyObject*, PyObject* args, PyObject*) { + GameData *gm= &(gp_KetsjiScene->GetBlenderScene()->gm); char *setting; - int enable, flag, fileflags; + int enable, flag, sceneflag; - if (!PyArg_ParseTuple(args,"si",&setting,&enable)) + if (!PyArg_ParseTuple(args,"si:setGLSLMaterialSetting",&setting,&enable)) return NULL; flag = getGLSLSettingFlag(setting); if (flag==-1) { - PyErr_SetString(PyExc_ValueError, "glsl setting is not known"); + PyErr_SetString(PyExc_ValueError, "Rasterizer.setGLSLMaterialSetting(string): glsl setting is not known"); return NULL; } - fileflags = G.fileflags; + sceneflag= gm->flag; if (enable) - G.fileflags &= ~flag; + gm->flag &= ~flag; else - G.fileflags |= flag; + gm->flag |= flag; /* display lists and GLSL materials need to be remade */ - if(G.fileflags != fileflags) { + if(sceneflag != gm->flag) { + GPU_materials_free(); if(gp_KetsjiEngine) { KX_SceneList *scenes = gp_KetsjiEngine->CurrentScenes(); KX_SceneList::iterator it; for(it=scenes->begin(); it!=scenes->end(); it++) - if((*it)->GetBucketManager()) + if((*it)->GetBucketManager()) { (*it)->GetBucketManager()->ReleaseDisplayLists(); + (*it)->GetBucketManager()->ReleaseMaterials(); + } } - - GPU_materials_free(); } Py_RETURN_NONE; @@ -737,21 +801,22 @@ static PyObject* gPyGetGLSLMaterialSetting(PyObject*, PyObject* args, PyObject*) { + GameData *gm= &(gp_KetsjiScene->GetBlenderScene()->gm); char *setting; int enabled = 0, flag; - if (!PyArg_ParseTuple(args,"s",&setting)) + if (!PyArg_ParseTuple(args,"s:getGLSLMaterialSetting",&setting)) return NULL; flag = getGLSLSettingFlag(setting); if (flag==-1) { - PyErr_SetString(PyExc_ValueError, "glsl setting is not known"); + PyErr_SetString(PyExc_ValueError, "Rasterizer.getGLSLMaterialSetting(string): glsl setting is not known"); return NULL; } - enabled = ((G.fileflags & flag) != 0); - return PyInt_FromLong(enabled); + enabled = ((gm->flag & flag) != 0); + return PyLong_FromSsize_t(enabled); } #define KX_TEXFACE_MATERIAL 0 @@ -762,40 +827,39 @@ static PyObject* gPySetMaterialType(PyObject*, PyObject* args, PyObject*) { - int flag, type; + GameData *gm= &(gp_KetsjiScene->GetBlenderScene()->gm); + int type; - if (!PyArg_ParseTuple(args,"i",&type)) + if (!PyArg_ParseTuple(args,"i:setMaterialType",&type)) return NULL; if(type == KX_BLENDER_GLSL_MATERIAL) - flag = G_FILE_GAME_MAT|G_FILE_GAME_MAT_GLSL; + gm->matmode= GAME_MAT_GLSL; else if(type == KX_BLENDER_MULTITEX_MATERIAL) - flag = G_FILE_GAME_MAT; + gm->matmode= GAME_MAT_MULTITEX; else if(type == KX_TEXFACE_MATERIAL) - flag = 0; + gm->matmode= GAME_MAT_TEXFACE; else { - PyErr_SetString(PyExc_ValueError, "material type is not known"); + PyErr_SetString(PyExc_ValueError, "Rasterizer.setMaterialType(int): material type is not known"); return NULL; } - G.fileflags &= ~(G_FILE_GAME_MAT|G_FILE_GAME_MAT_GLSL); - G.fileflags |= flag; - Py_RETURN_NONE; } static PyObject* gPyGetMaterialType(PyObject*) { + GameData *gm= &(gp_KetsjiScene->GetBlenderScene()->gm); int flag; - if(G.fileflags & (G_FILE_GAME_MAT|G_FILE_GAME_MAT_GLSL)) + if(gm->matmode == GAME_MAT_GLSL) flag = KX_BLENDER_GLSL_MATERIAL; - else if(G.fileflags & G_FILE_GAME_MAT) + else if(gm->matmode == GAME_MAT_MULTITEX) flag = KX_BLENDER_MULTITEX_MATERIAL; else flag = KX_TEXFACE_MATERIAL; - return PyInt_FromLong(flag); + return PyLong_FromSsize_t(flag); } static PyObject* gPyDrawLine(PyObject*, PyObject* args) @@ -805,16 +869,16 @@ static PyObject* gPyDrawLine(PyObject*, PyObject* args) PyObject* ob_color; if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.drawLine(obFrom, obTo, color): Rasterizer not available"); return NULL; } - if (!PyArg_ParseTuple(args,"OOO",&ob_from,&ob_to,&ob_color)) + if (!PyArg_ParseTuple(args,"OOO:drawLine",&ob_from,&ob_to,&ob_color)) return NULL; - MT_Vector3 from(0., 0., 0.); - MT_Vector3 to(0., 0., 0.); - MT_Vector3 color(0., 0., 0.); + MT_Vector3 from; + MT_Vector3 to; + MT_Vector3 color; if (!PyVecTo(ob_from, from)) return NULL; if (!PyVecTo(ob_to, to)) @@ -840,17 +904,18 @@ static struct PyMethodDef rasterizer_methods[] = { METH_VARARGS, "showMouse(bool visible)"}, {"setMousePosition",(PyCFunction) gPySetMousePosition, METH_VARARGS, "setMousePosition(int x,int y)"}, - {"setBackgroundColor",(PyCFunction)gPySetBackgroundColor,METH_VARARGS,"set Background Color (rgb)"}, - {"setAmbientColor",(PyCFunction)gPySetAmbientColor,METH_VARARGS,"set Ambient Color (rgb)"}, - {"setMistColor",(PyCFunction)gPySetMistColor,METH_VARARGS,"set Mist Color (rgb)"}, + {"setBackgroundColor",(PyCFunction)gPySetBackgroundColor,METH_O,"set Background Color (rgb)"}, + {"setAmbientColor",(PyCFunction)gPySetAmbientColor,METH_O,"set Ambient Color (rgb)"}, + {"disableMist",(PyCFunction)gPyDisableMist,METH_NOARGS,"turn off mist"}, + {"setMistColor",(PyCFunction)gPySetMistColor,METH_O,"set Mist Color (rgb)"}, {"setMistStart",(PyCFunction)gPySetMistStart,METH_VARARGS,"set Mist Start(rgb)"}, {"setMistEnd",(PyCFunction)gPySetMistEnd,METH_VARARGS,"set Mist End(rgb)"}, {"enableMotionBlur",(PyCFunction)gPyEnableMotionBlur,METH_VARARGS,"enable motion blur"}, - {"disableMotionBlur",(PyCFunction)gPyDisableMotionBlur,METH_VARARGS,"disable motion blur"}, + {"disableMotionBlur",(PyCFunction)gPyDisableMotionBlur,METH_NOARGS,"disable motion blur"}, {"setEyeSeparation", (PyCFunction) gPySetEyeSeparation, METH_VARARGS, "set the eye separation for stereo mode"}, - {"getEyeSeparation", (PyCFunction) gPyGetEyeSeparation, METH_VARARGS, "get the eye separation for stereo mode"}, + {"getEyeSeparation", (PyCFunction) gPyGetEyeSeparation, METH_NOARGS, "get the eye separation for stereo mode"}, {"setFocalLength", (PyCFunction) gPySetFocalLength, METH_VARARGS, "set the focal length for stereo mode"}, {"getFocalLength", (PyCFunction) gPyGetFocalLength, METH_VARARGS, "get the focal length for stereo mode"}, {"setMaterialMode",(PyCFunction) gPySetMaterialType, @@ -876,32 +941,56 @@ static char Rasterizer_module_documentation[] = "This is the Python API for the game engine of Rasterizer" ; - +static struct PyModuleDef GameLogic_module_def = { + {}, /* m_base */ + "GameLogic", /* m_name */ + GameLogic_module_documentation, /* m_doc */ + 0, /* m_size */ + game_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack to get gravity hook { PyObject* m; PyObject* d; - + PyObject* item; /* temp PyObject* storage */ + gp_KetsjiEngine = engine; gp_KetsjiScene = scene; gUseVisibilityTemp=false; - - // Create the module and add the functions - m = Py_InitModule4("GameLogic", game_methods, - GameLogic_module_documentation, - (PyObject*)NULL,PYTHON_API_VERSION); - + + PyObjectPlus::ClearDeprecationWarning(); /* Not that nice to call here but makes sure warnings are reset between loading scenes */ + + /* Use existing module where possible + * be careful not to init any runtime vars after this */ + m = PyImport_ImportModule( "GameLogic" ); + if(m) { + Py_DECREF(m); + return m; + } + else { + PyErr_Clear(); + // Create the module and add the functions + m = PyModule_Create(&GameLogic_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), GameLogic_module_def.m_name, m); + } + // Add some symbolic constants to the module d = PyModule_GetDict(m); // can be overwritten later for gameEngine instances that can load new blend files and re-initialize this module // for now its safe to make sure it exists for other areas such as the web plugin - PyDict_SetItemString(d, "globalDict", PyDict_New()); + + PyDict_SetItemString(d, "globalDict", item=PyDict_New()); Py_DECREF(item); - ErrorObject = PyString_FromString("GameLogic.error"); + ErrorObject = PyUnicode_FromString("GameLogic.error"); PyDict_SetItemString(d, "error", ErrorObject); + Py_DECREF(ErrorObject); // XXXX Add constants here /* To use logic bricks, we need some sort of constants. Here, we associate */ @@ -934,6 +1023,12 @@ PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ORIX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIX); KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ORIY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIY); KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ORIZ, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIZ); + KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_FHPX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPX); + KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_FHPY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPY); + KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_FHPZ, KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPZ); + KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_FHNX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNX); + KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_FHNY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNY); + KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_FHNZ, KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNZ); /* 4. Ipo actuator, simple part */ KX_MACRO_addTypesToDict(d, KX_IPOACT_PLAY, KX_IpoActuator::KX_ACT_IPO_PLAY); @@ -941,6 +1036,7 @@ PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack KX_MACRO_addTypesToDict(d, KX_IPOACT_FLIPPER, KX_IpoActuator::KX_ACT_IPO_FLIPPER); KX_MACRO_addTypesToDict(d, KX_IPOACT_LOOPSTOP, KX_IpoActuator::KX_ACT_IPO_LOOPSTOP); KX_MACRO_addTypesToDict(d, KX_IPOACT_LOOPEND, KX_IpoActuator::KX_ACT_IPO_LOOPEND); + KX_MACRO_addTypesToDict(d, KX_IPOACT_FROM_PROP,KX_IpoActuator::KX_ACT_IPO_FROM_PROP); /* 5. Random distribution types */ KX_MACRO_addTypesToDict(d, KX_RANDOMACT_BOOL_CONST, SCA_RandomActuator::KX_RANDOMACT_BOOL_CONST); @@ -963,11 +1059,11 @@ PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack KX_MACRO_addTypesToDict(d, KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP, KX_SoundActuator::KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP); /* 7. Action actuator */ - KX_MACRO_addTypesToDict(d, KX_ACTIONACT_PLAY, BL_ActionActuator::KX_ACT_ACTION_PLAY); - KX_MACRO_addTypesToDict(d, KX_ACTIONACT_FLIPPER, BL_ActionActuator::KX_ACT_ACTION_FLIPPER); - KX_MACRO_addTypesToDict(d, KX_ACTIONACT_LOOPSTOP, BL_ActionActuator::KX_ACT_ACTION_LOOPSTOP); - KX_MACRO_addTypesToDict(d, KX_ACTIONACT_LOOPEND, BL_ActionActuator::KX_ACT_ACTION_LOOPEND); - KX_MACRO_addTypesToDict(d, KX_ACTIONACT_PROPERTY, BL_ActionActuator::KX_ACT_ACTION_PROPERTY); + KX_MACRO_addTypesToDict(d, KX_ACTIONACT_PLAY, ACT_ACTION_PLAY); + KX_MACRO_addTypesToDict(d, KX_ACTIONACT_FLIPPER, ACT_ACTION_FLIPPER); + KX_MACRO_addTypesToDict(d, KX_ACTIONACT_LOOPSTOP, ACT_ACTION_LOOP_STOP); + KX_MACRO_addTypesToDict(d, KX_ACTIONACT_LOOPEND, ACT_ACTION_LOOP_END); + KX_MACRO_addTypesToDict(d, KX_ACTIONACT_PROPERTY, ACT_ACTION_FROM_PROP); /*8. GL_BlendFunc */ KX_MACRO_addTypesToDict(d, BL_ZERO, GL_ZERO); @@ -1032,6 +1128,96 @@ PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack KX_MACRO_addTypesToDict(d, KX_STATE29, (1<<28)); KX_MACRO_addTypesToDict(d, KX_STATE30, (1<<29)); + /* Radar Sensor */ + KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_POS_X, KX_RadarSensor::KX_RADAR_AXIS_POS_X); + KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_POS_Y, KX_RadarSensor::KX_RADAR_AXIS_POS_Y); + KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_POS_Z, KX_RadarSensor::KX_RADAR_AXIS_POS_Z); + KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_NEG_X, KX_RadarSensor::KX_RADAR_AXIS_NEG_Y); + KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_NEG_Y, KX_RadarSensor::KX_RADAR_AXIS_NEG_X); + KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_NEG_Z, KX_RadarSensor::KX_RADAR_AXIS_NEG_Z); + + /* Ray Sensor */ + KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_POS_X, KX_RaySensor::KX_RAY_AXIS_POS_X); + KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_POS_Y, KX_RaySensor::KX_RAY_AXIS_POS_Y); + KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_POS_Z, KX_RaySensor::KX_RAY_AXIS_POS_Z); + KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_NEG_X, KX_RaySensor::KX_RAY_AXIS_NEG_Y); + KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_NEG_Y, KX_RaySensor::KX_RAY_AXIS_NEG_X); + KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_NEG_Z, KX_RaySensor::KX_RAY_AXIS_NEG_Z); + + /* Dynamic actuator */ + KX_MACRO_addTypesToDict(d, KX_DYN_RESTORE_DYNAMICS, KX_SCA_DynamicActuator::KX_DYN_RESTORE_DYNAMICS); + KX_MACRO_addTypesToDict(d, KX_DYN_DISABLE_DYNAMICS, KX_SCA_DynamicActuator::KX_DYN_DISABLE_DYNAMICS); + KX_MACRO_addTypesToDict(d, KX_DYN_ENABLE_RIGID_BODY, KX_SCA_DynamicActuator::KX_DYN_ENABLE_RIGID_BODY); + KX_MACRO_addTypesToDict(d, KX_DYN_DISABLE_RIGID_BODY, KX_SCA_DynamicActuator::KX_DYN_DISABLE_RIGID_BODY); + KX_MACRO_addTypesToDict(d, KX_DYN_SET_MASS, KX_SCA_DynamicActuator::KX_DYN_SET_MASS); + + /* Input & Mouse Sensor */ + KX_MACRO_addTypesToDict(d, KX_INPUT_NONE, SCA_InputEvent::KX_NO_INPUTSTATUS); + KX_MACRO_addTypesToDict(d, KX_INPUT_JUST_ACTIVATED, SCA_InputEvent::KX_JUSTACTIVATED); + KX_MACRO_addTypesToDict(d, KX_INPUT_ACTIVE, SCA_InputEvent::KX_ACTIVE); + KX_MACRO_addTypesToDict(d, KX_INPUT_JUST_RELEASED, SCA_InputEvent::KX_JUSTRELEASED); + + KX_MACRO_addTypesToDict(d, KX_MOUSE_BUT_LEFT, SCA_IInputDevice::KX_LEFTMOUSE); + KX_MACRO_addTypesToDict(d, KX_MOUSE_BUT_MIDDLE, SCA_IInputDevice::KX_MIDDLEMOUSE); + KX_MACRO_addTypesToDict(d, KX_MOUSE_BUT_RIGHT, SCA_IInputDevice::KX_RIGHTMOUSE); + + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_ENABLED, RAS_2DFilterManager::RAS_2DFILTER_ENABLED); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_DISABLED, RAS_2DFilterManager::RAS_2DFILTER_DISABLED); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_NOFILTER, RAS_2DFilterManager::RAS_2DFILTER_NOFILTER); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_MOTIONBLUR, RAS_2DFilterManager::RAS_2DFILTER_MOTIONBLUR); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_BLUR, RAS_2DFilterManager::RAS_2DFILTER_BLUR); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_SHARPEN, RAS_2DFilterManager::RAS_2DFILTER_SHARPEN); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_DILATION, RAS_2DFilterManager::RAS_2DFILTER_DILATION); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_EROSION, RAS_2DFilterManager::RAS_2DFILTER_EROSION); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_LAPLACIAN, RAS_2DFilterManager::RAS_2DFILTER_LAPLACIAN); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_SOBEL, RAS_2DFilterManager::RAS_2DFILTER_SOBEL); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_PREWITT, RAS_2DFilterManager::RAS_2DFILTER_PREWITT); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_GRAYSCALE, RAS_2DFilterManager::RAS_2DFILTER_GRAYSCALE); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_SEPIA, RAS_2DFilterManager::RAS_2DFILTER_SEPIA); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_INVERT, RAS_2DFilterManager::RAS_2DFILTER_INVERT); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_CUSTOMFILTER, RAS_2DFilterManager::RAS_2DFILTER_CUSTOMFILTER); + + KX_MACRO_addTypesToDict(d, KX_SOUNDACT_PLAYSTOP, KX_SoundActuator::KX_SOUNDACT_PLAYSTOP); + KX_MACRO_addTypesToDict(d, KX_SOUNDACT_PLAYEND, KX_SoundActuator::KX_SOUNDACT_PLAYEND); + KX_MACRO_addTypesToDict(d, KX_SOUNDACT_LOOPSTOP, KX_SoundActuator::KX_SOUNDACT_LOOPSTOP); + KX_MACRO_addTypesToDict(d, KX_SOUNDACT_LOOPEND, KX_SoundActuator:: KX_SOUNDACT_LOOPEND); + KX_MACRO_addTypesToDict(d, KX_SOUNDACT_LOOPBIDIRECTIONAL, KX_SoundActuator::KX_SOUNDACT_LOOPBIDIRECTIONAL); + KX_MACRO_addTypesToDict(d, KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP, KX_SoundActuator::KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP); + + KX_MACRO_addTypesToDict(d, KX_STATE_OP_CPY, KX_StateActuator::OP_CPY); + KX_MACRO_addTypesToDict(d, KX_STATE_OP_SET, KX_StateActuator::OP_SET); + KX_MACRO_addTypesToDict(d, KX_STATE_OP_CLR, KX_StateActuator::OP_CLR); + KX_MACRO_addTypesToDict(d, KX_STATE_OP_NEG, KX_StateActuator::OP_NEG); + + KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_NORMAL, KX_ConstraintActuator::KX_ACT_CONSTRAINT_NORMAL); + KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_MATERIAL, KX_ConstraintActuator::KX_ACT_CONSTRAINT_MATERIAL); + KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_PERMANENT, KX_ConstraintActuator::KX_ACT_CONSTRAINT_PERMANENT); + KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_DISTANCE, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DISTANCE); + KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_LOCAL, KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCAL); + KX_MACRO_addTypesToDict(d, KX_ACT_CONSTRAINT_DOROTFH, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DOROTFH); + + /* Game Actuator Modes */ + KX_MACRO_addTypesToDict(d, KX_GAME_LOAD, KX_GameActuator::KX_GAME_LOAD); + KX_MACRO_addTypesToDict(d, KX_GAME_START, KX_GameActuator::KX_GAME_START); + KX_MACRO_addTypesToDict(d, KX_GAME_RESTART, KX_GameActuator::KX_GAME_RESTART); + KX_MACRO_addTypesToDict(d, KX_GAME_QUIT, KX_GameActuator::KX_GAME_QUIT); + KX_MACRO_addTypesToDict(d, KX_GAME_SAVECFG, KX_GameActuator::KX_GAME_SAVECFG); + KX_MACRO_addTypesToDict(d, KX_GAME_LOADCFG, KX_GameActuator::KX_GAME_LOADCFG); + + /* Scene Actuator Modes */ + KX_MACRO_addTypesToDict(d, KX_SCENE_RESTART, KX_SceneActuator::KX_SCENE_RESTART); + KX_MACRO_addTypesToDict(d, KX_SCENE_SET_SCENE, KX_SceneActuator::KX_SCENE_SET_SCENE); + KX_MACRO_addTypesToDict(d, KX_SCENE_SET_CAMERA, KX_SceneActuator::KX_SCENE_SET_CAMERA); + KX_MACRO_addTypesToDict(d, KX_SCENE_ADD_FRONT_SCENE, KX_SceneActuator::KX_SCENE_ADD_FRONT_SCENE); + KX_MACRO_addTypesToDict(d, KX_SCENE_ADD_BACK_SCENE, KX_SceneActuator::KX_SCENE_ADD_BACK_SCENE); + KX_MACRO_addTypesToDict(d, KX_SCENE_REMOVE_SCENE, KX_SceneActuator::KX_SCENE_REMOVE_SCENE); + KX_MACRO_addTypesToDict(d, KX_SCENE_SUSPEND, KX_SceneActuator::KX_SCENE_SUSPEND); + KX_MACRO_addTypesToDict(d, KX_SCENE_RESUME, KX_SceneActuator::KX_SCENE_RESUME); + + /* Parent Actuator Modes */ + KX_MACRO_addTypesToDict(d, KX_PARENT_SET, KX_ParentActuator::KX_PARENT_SET); + KX_MACRO_addTypesToDict(d, KX_PARENT_REMOVE, KX_ParentActuator::KX_PARENT_REMOVE); + // Check for errors if (PyErr_Occurred()) { @@ -1050,11 +1236,6 @@ PyObject *KXpy_open(PyObject *self, PyObject *args) { return NULL; } -PyObject *KXpy_reload(PyObject *self, PyObject *args) { - PyErr_SetString(PyExc_RuntimeError, "Sandbox: reload() function disabled!\nGame Scripts should not use this function."); - return NULL; -} - PyObject *KXpy_file(PyObject *self, PyObject *args) { PyErr_SetString(PyExc_RuntimeError, "Sandbox: file() function disabled!\nGame Scripts should not use this function."); return NULL; @@ -1073,27 +1254,21 @@ PyObject *KXpy_compile(PyObject *self, PyObject *args) { PyObject *KXpy_import(PyObject *self, PyObject *args) { char *name; + int found; PyObject *globals = NULL; PyObject *locals = NULL; PyObject *fromlist = NULL; PyObject *l, *m, *n; - -#if (PY_VERSION_HEX >= 0x02060000) - int dummy_val; /* what does this do?*/ + int level; /* not used yet */ if (!PyArg_ParseTuple(args, "s|OOOi:m_import", - &name, &globals, &locals, &fromlist, &dummy_val)) - return NULL; -#else - if (!PyArg_ParseTuple(args, "s|OOO:m_import", - &name, &globals, &locals, &fromlist)) + &name, &globals, &locals, &fromlist, &level)) return NULL; -#endif /* check for builtin modules */ m = PyImport_AddModule("sys"); l = PyObject_GetAttrString(m, "builtin_module_names"); - n = PyString_FromString(name); + n = PyUnicode_FromString(name); if (PySequence_Contains(l, n)) { return PyImport_ImportModuleEx(name, globals, locals, fromlist); @@ -1102,16 +1277,47 @@ PyObject *KXpy_import(PyObject *self, PyObject *args) /* quick hack for GamePython modules TODO: register builtin modules properly by ExtendInittab */ if (!strcmp(name, "GameLogic") || !strcmp(name, "GameKeys") || !strcmp(name, "PhysicsConstraints") || - !strcmp(name, "Rasterizer") || !strcmp(name, "Mathutils")) { + !strcmp(name, "Rasterizer") || !strcmp(name, "Mathutils") || !strcmp(name, "BGL") || !strcmp(name, "Geometry")) { return PyImport_ImportModuleEx(name, globals, locals, fromlist); } - - PyErr_Format(PyExc_ImportError, - "Import of external Module %.20s not allowed.", name); + + /* Import blender texts as python modules */ + m= bpy_text_import(name, &found); + if (m) + return m; + + if(found==0) /* if its found but could not import then it has its own error */ + PyErr_Format(PyExc_ImportError, "Import of external Module %.20s not allowed.", name); + return NULL; } +PyObject *KXpy_reload(PyObject *self, PyObject *args) { + + /* Used to be sandboxed, bettet to allow importing of internal text only */ +#if 0 + PyErr_SetString(PyExc_RuntimeError, "Sandbox: reload() function disabled!\nGame Scripts should not use this function."); + return NULL; +#endif + int found; + PyObject *module = NULL; + PyObject *newmodule = NULL; + + /* check for a module arg */ + if( !PyArg_ParseTuple( args, "O:bpy_reload_meth", &module ) ) + return NULL; + + newmodule= bpy_text_reimport( module, &found ); + if (newmodule) + return newmodule; + + if (found==0) /* if its found but could not import then it has its own error */ + PyErr_SetString(PyExc_ImportError, "reload(module): failed to reload from blenders internal text"); + + return newmodule; +} + /* override python file type functions */ #if 0 static int @@ -1144,18 +1350,18 @@ void setSandbox(TPythonSecurityLevel level) { PyObject *m = PyImport_AddModule("__builtin__"); PyObject *d = PyModule_GetDict(m); - + PyObject *item; switch (level) { case psl_Highest: //if (!g_security) { //g_oldopen = PyDict_GetItemString(d, "open"); // functions we cant trust - PyDict_SetItemString(d, "open", PyCFunction_New(meth_open, NULL)); - PyDict_SetItemString(d, "reload", PyCFunction_New(meth_reload, NULL)); - PyDict_SetItemString(d, "file", PyCFunction_New(meth_file, NULL)); - PyDict_SetItemString(d, "execfile", PyCFunction_New(meth_execfile, NULL)); - PyDict_SetItemString(d, "compile", PyCFunction_New(meth_compile, NULL)); + PyDict_SetItemString(d, "open", item=PyCFunction_New(meth_open, NULL)); Py_DECREF(item); + PyDict_SetItemString(d, "reload", item=PyCFunction_New(meth_reload, NULL)); Py_DECREF(item); + PyDict_SetItemString(d, "file", item=PyCFunction_New(meth_file, NULL)); Py_DECREF(item); + PyDict_SetItemString(d, "execfile", item=PyCFunction_New(meth_execfile, NULL)); Py_DECREF(item); + PyDict_SetItemString(d, "compile", item=PyCFunction_New(meth_compile, NULL)); Py_DECREF(item); // our own import PyDict_SetItemString(d, "__import__", PyCFunction_New(meth_import, NULL)); @@ -1184,57 +1390,228 @@ void setSandbox(TPythonSecurityLevel level) } */ default: + /* Allow importing internal text, from bpy_internal_import.py */ + PyDict_SetItemString(d, "reload", item=PyCFunction_New(bpy_reload_meth, NULL)); Py_DECREF(item); + PyDict_SetItemString(d, "__import__", item=PyCFunction_New(bpy_import_meth, NULL)); Py_DECREF(item); break; } } +/* Explanation of + * + * - backupPySysObjects() : stores sys.path in gp_OrigPythonSysPath + * - initPySysObjects(main) : initializes the blendfile and library paths + * - restorePySysObjects() : restores sys.path from gp_OrigPythonSysPath + * + * These exist so the current blend dir "//" can always be used to import modules from. + * the reason we need a few functions for this is that python is not only used by the game engine + * so we cant just add to sys.path all the time, it would leave pythons state in a mess. + * It would also be incorrect since loading blend files for new levels etc would alwasy add to sys.path + * + * To play nice with blenders python, the sys.path is backed up and the current blendfile along + * with all its lib paths are added to the sys path. + * When loading a new blendfile, the original sys.path is restored and the new paths are added over the top. + */ + +/** + * So we can have external modules mixed with our blend files. + */ +static void backupPySysObjects(void) +{ + PyObject *sys_path= PySys_GetObject("path"); /* should never fail */ + PyObject *sys_mods= PySys_GetObject("modules"); /* should never fail */ + + /* paths */ + Py_XDECREF(gp_OrigPythonSysPath); /* just incase its set */ + gp_OrigPythonSysPath = PyList_GetSlice(sys_path, 0, INT_MAX); /* copy the list */ + + /* modules */ + Py_XDECREF(gp_OrigPythonSysModules); /* just incase its set */ + gp_OrigPythonSysModules = PyDict_Copy(sys_mods); /* copy the list */ + +} + +/* for initPySysObjects only, + * takes a blend path and adds a scripts dir from it + * + * "/home/me/foo.blend" -> "/home/me/scripts" + */ +static void initPySysObjects__append(PyObject *sys_path, char *filename) +{ + PyObject *item; + char expanded[FILE_MAXDIR + FILE_MAXFILE]; + + BLI_split_dirfile_basic(filename, expanded, NULL); /* get the dir part of filename only */ + BLI_convertstringcode(expanded, gp_GamePythonPath); /* filename from lib->filename is (always?) absolute, so this may not be needed but it wont hurt */ + BLI_cleanup_file(gp_GamePythonPath, expanded); /* Dont use BLI_cleanup_dir because it adds a slash - BREAKS WIN32 ONLY */ + item= PyUnicode_FromString(expanded); + +// printf("SysPath - '%s', '%s', '%s'\n", expanded, filename, gp_GamePythonPath); + + if(PySequence_Index(sys_path, item) == -1) { + PyErr_Clear(); /* PySequence_Index sets a ValueError */ + PyList_Insert(sys_path, 0, item); + } + + Py_DECREF(item); +} +static void initPySysObjects(Main *maggie) +{ + PyObject *sys_path= PySys_GetObject("path"); /* should never fail */ + + if (gp_OrigPythonSysPath==NULL) { + /* backup */ + backupPySysObjects(); + } + else { + /* get the original sys path when the BGE started */ + PyList_SetSlice(sys_path, 0, INT_MAX, gp_OrigPythonSysPath); + } + + Library *lib= (Library *)maggie->library.first; + + while(lib) { + /* lib->name wont work in some cases (on win32), + * even when expanding with gp_GamePythonPath, using lib->filename is less trouble */ + initPySysObjects__append(sys_path, lib->filename); + lib= (Library *)lib->id.next; + } + + initPySysObjects__append(sys_path, gp_GamePythonPath); + +// fprintf(stderr, "\nNew Path: %d ", PyList_Size(sys_path)); +// PyObject_Print(sys_path, stderr, 0); +} + +static void restorePySysObjects(void) +{ + if (gp_OrigPythonSysPath==NULL) + return; + + PyObject *sys_path= PySys_GetObject("path"); /* should never fail */ + PyObject *sys_mods= PySys_GetObject("modules"); /* should never fail */ + + /* paths */ + PyList_SetSlice(sys_path, 0, INT_MAX, gp_OrigPythonSysPath); + Py_DECREF(gp_OrigPythonSysPath); + gp_OrigPythonSysPath= NULL; + + /* modules */ + PyDict_Clear(sys_mods); + PyDict_Update(sys_mods, gp_OrigPythonSysModules); + Py_DECREF(gp_OrigPythonSysModules); + gp_OrigPythonSysModules= NULL; + + +// fprintf(stderr, "\nRestore Path: %d ", PyList_Size(sys_path)); +// PyObject_Print(sys_path, stderr, 0); +} + /** * Python is not initialised. */ -PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level) +PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level, Main *maggie, int argc, char** argv) { + /* Yet another gotcha in the py api + * Cant run PySys_SetArgv more then once because this adds the + * binary dir to the sys.path each time. + * Id have thaught python being totally restarted would make this ok but + * somehow it remembers the sys.path - Campbell + */ + static bool first_time = true; + +#if 0 // TODO - py3 STR_String pname = progname; Py_SetProgramName(pname.Ptr()); +#endif Py_NoSiteFlag=1; Py_FrozenFlag=1; Py_Initialize(); + + if(argv && first_time) { /* browser plugins dont currently set this */ + // Until python support ascii again, we use our own. + // PySys_SetArgv(argc, argv); + int i; + PyObject *py_argv= PyList_New(argc); - //importBlenderModules() + for (i=0; i<argc; i++) + PyList_SET_ITEM(py_argv, i, PyUnicode_FromString(argv[i])); + + PySys_SetObject("argv", py_argv); + Py_DECREF(py_argv); + } setSandbox(level); - + initPyTypes(); + + bpy_import_main_set(maggie); + + initPySysObjects(maggie); + + first_time = false; + + PyObjectPlus::ClearDeprecationWarning(); + PyObject* moduleobj = PyImport_AddModule("__main__"); return PyModule_GetDict(moduleobj); } void exitGamePlayerPythonScripting() -{ +{ + /* since python restarts we cant let the python backup of the sys.path hang around in a global pointer */ + restorePySysObjects(); /* get back the original sys.path and clear the backup */ + Py_Finalize(); + bpy_import_main_set(NULL); + PyObjectPlus::ClearDeprecationWarning(); } + + /** * Python is already initialized. */ -PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level) +PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level, Main *maggie) { +#if 0 // XXX TODO Py3 STR_String pname = progname; Py_SetProgramName(pname.Ptr()); +#endif Py_NoSiteFlag=1; Py_FrozenFlag=1; setSandbox(level); + initPyTypes(); + + bpy_import_main_set(maggie); + + initPySysObjects(maggie); + PyObjectPlus::NullDeprecationWarning(); + PyObject* moduleobj = PyImport_AddModule("__main__"); return PyModule_GetDict(moduleobj); } - - void exitGamePythonScripting() { -} - - + restorePySysObjects(); /* get back the original sys.path and clear the backup */ + bpy_import_main_set(NULL); + PyObjectPlus::ClearDeprecationWarning(); +} + + +static struct PyModuleDef Rasterizer_module_def = { + {}, /* m_base */ + "Rasterizer", /* m_name */ + Rasterizer_module_documentation, /* m_doc */ + 0, /* m_size */ + rasterizer_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; PyObject* initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas) { @@ -1244,16 +1621,28 @@ PyObject* initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas) PyObject* m; PyObject* d; - - // Create the module and add the functions - m = Py_InitModule4("Rasterizer", rasterizer_methods, - Rasterizer_module_documentation, - (PyObject*)NULL,PYTHON_API_VERSION); + PyObject* item; + + /* Use existing module where possible + * be careful not to init any runtime vars after this */ + m = PyImport_ImportModule( "Rasterizer" ); + if(m) { + Py_DECREF(m); + return m; + } + else { + PyErr_Clear(); + + // Create the module and add the functions + m = PyModule_Create(&Rasterizer_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), Rasterizer_module_def.m_name, m); + } // Add some symbolic constants to the module d = PyModule_GetDict(m); - ErrorObject = PyString_FromString("Rasterizer.error"); + ErrorObject = PyUnicode_FromString("Rasterizer.error"); PyDict_SetItemString(d, "error", ErrorObject); + Py_DECREF(ErrorObject); /* needed for get/setMaterialType */ KX_MACRO_addTypesToDict(d, KX_TEXFACE_MATERIAL, KX_TEXFACE_MATERIAL); @@ -1282,7 +1671,7 @@ static char GameKeys_module_documentation[] = ; static char gPyEventToString_doc[] = -"Take a valid event from the GameKeys module or Keyboard Sensor and return a name" +"EventToString(event) - Take a valid event from the GameKeys module or Keyboard Sensor and return a name" ; static PyObject* gPyEventToString(PyObject*, PyObject* value) @@ -1297,7 +1686,7 @@ static PyObject* gPyEventToString(PyObject*, PyObject* value) dict = PyModule_GetDict(mod); while (PyDict_Next(dict, &pos, &key, &val)) { - if (PyObject_Compare(value, val)==0) { + if (PyObject_RichCompareBool(value, val, Py_EQ)) { ret = key; break; } @@ -1305,28 +1694,70 @@ static PyObject* gPyEventToString(PyObject*, PyObject* value) PyErr_Clear(); // incase there was an error clearing Py_DECREF(mod); - if (!ret) PyErr_SetString(PyExc_ValueError, "expected a valid int keyboard event"); + if (!ret) PyErr_SetString(PyExc_ValueError, "GameKeys.EventToString(int): expected a valid int keyboard event"); else Py_INCREF(ret); return ret; } +static char gPyEventToCharacter_doc[] = +"EventToCharacter(event, is_shift) - Take a valid event from the GameKeys module or Keyboard Sensor and return a character" +; + +static PyObject* gPyEventToCharacter(PyObject*, PyObject* args) +{ + int event, shift; + if (!PyArg_ParseTuple(args,"ii:EventToCharacter", &event, &shift)) + return NULL; + + if(IsPrintable(event)) { + char ch[2] = {'\0', '\0'}; + ch[0] = ToCharacter(event, (bool)shift); + return PyUnicode_FromString(ch); + } + else { + return PyUnicode_FromString(""); + } +} + + static struct PyMethodDef gamekeys_methods[] = { - {"EventToString", (PyCFunction)gPyEventToString, METH_O, (PY_METHODCHAR)gPyEventToString_doc}, + {"EventToCharacter", (PyCFunction)gPyEventToCharacter, METH_VARARGS, (const char *)gPyEventToCharacter_doc}, + {"EventToString", (PyCFunction)gPyEventToString, METH_O, (const char *)gPyEventToString_doc}, { NULL, (PyCFunction) NULL, 0, NULL } }; - +static struct PyModuleDef GameKeys_module_def = { + {}, /* m_base */ + "GameKeys", /* m_name */ + GameKeys_module_documentation, /* m_doc */ + 0, /* m_size */ + gamekeys_methods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; PyObject* initGameKeys() { PyObject* m; PyObject* d; - - // Create the module and add the functions - m = Py_InitModule4("GameKeys", gamekeys_methods, - GameKeys_module_documentation, - (PyObject*)NULL,PYTHON_API_VERSION); + PyObject* item; + + /* Use existing module where possible */ + m = PyImport_ImportModule( "GameKeys" ); + if(m) { + Py_DECREF(m); + return m; + } + else { + PyErr_Clear(); + + // Create the module and add the functions + m = PyModule_Create(&GameKeys_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), GameKeys_module_def.m_name, m); + } // Add some symbolic constants to the module d = PyModule_GetDict(m); @@ -1446,7 +1877,6 @@ PyObject* initGameKeys() KX_MACRO_addTypesToDict(d, PAGEDOWNKEY, SCA_IInputDevice::KX_PAGEDOWNKEY); KX_MACRO_addTypesToDict(d, ENDKEY, SCA_IInputDevice::KX_ENDKEY); - // Check for errors if (PyErr_Occurred()) { @@ -1458,19 +1888,34 @@ PyObject* initGameKeys() PyObject* initMathutils() { - return Mathutils_Init("Mathutils"); // Use as a top level module in BGE + return Mathutils_Init(); +} + +PyObject* initGeometry() +{ + return Geometry_Init(); } -void PHY_SetActiveScene(class KX_Scene* scene) +PyObject* initBGL() +{ + return BGL_Init(); +} + +void KX_SetActiveScene(class KX_Scene* scene) { gp_KetsjiScene = scene; } -class KX_Scene* PHY_GetActiveScene() +class KX_Scene* KX_GetActiveScene() { return gp_KetsjiScene; } +class KX_KetsjiEngine* KX_GetActiveEngine() +{ + return gp_KetsjiEngine; +} + // utility function for loading and saving the globalDict int saveGamePythonConfig( char **marshal_buffer) { @@ -1487,11 +1932,12 @@ int saveGamePythonConfig( char **marshal_buffer) if (pyGlobalDictMarshal) { // for testing only // PyObject_Print(pyGlobalDictMarshal, stderr, 0); - - marshal_length= PyString_Size(pyGlobalDictMarshal); + char *marshal_cstring; + + marshal_cstring = PyBytes_AsString(pyGlobalDictMarshal); // py3 uses byte arrays + marshal_length= PyBytes_Size(pyGlobalDictMarshal); *marshal_buffer = new char[marshal_length + 1]; - memcpy(*marshal_buffer, PyString_AsString(pyGlobalDictMarshal), marshal_length); - + memcpy(*marshal_buffer, marshal_cstring, marshal_length); Py_DECREF(pyGlobalDictMarshal); } else { printf("Error, GameLogic.globalDict could not be marshal'd\n"); @@ -1542,9 +1988,9 @@ int loadGamePythonConfig(char *marshal_buffer, int marshal_length) void pathGamePythonConfig( char *path ) { - int len = strlen(gp_GamePythonPath); + int len = strlen(gp_GamePythonPathOrig); // Always use the first loaded blend filename - BLI_strncpy(path, gp_GamePythonPath, sizeof(gp_GamePythonPath)); + BLI_strncpy(path, gp_GamePythonPathOrig, sizeof(gp_GamePythonPathOrig)); /* replace extension */ if (BLI_testextensie(path, ".blend")) { @@ -1557,5 +2003,16 @@ void pathGamePythonConfig( char *path ) void setGamePythonPath(char *path) { BLI_strncpy(gp_GamePythonPath, path, sizeof(gp_GamePythonPath)); + BLI_cleanup_file(NULL, gp_GamePythonPath); /* not absolutely needed but makes resolving path problems less confusing later */ + + if (gp_GamePythonPathOrig[0] == '\0') + BLI_strncpy(gp_GamePythonPathOrig, path, sizeof(gp_GamePythonPathOrig)); } +// we need this so while blender is open (not blenderplayer) +// loading new blendfiles will reset this on starting the +// engine but loading blend files within the BGE wont overwrite gp_GamePythonPathOrig +void resetGamePythonPath() +{ + gp_GamePythonPathOrig[0] = '\0'; +} diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h index 36e3db6ec35..8f102d13a18 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.h +++ b/source/gameengine/Ketsji/KX_PythonInit.h @@ -43,19 +43,27 @@ extern bool gUseVisibilityTemp; PyObject* initGameLogic(class KX_KetsjiEngine *engine, class KX_Scene* ketsjiscene); PyObject* initGameKeys(); PyObject* initRasterizer(class RAS_IRasterizer* rasty,class RAS_ICanvas* canvas); -PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level); +PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level, struct Main *maggie, int argc, char** argv); PyObject* initMathutils(); +PyObject* initGeometry(); +PyObject* initBGL(); +PyObject* initVideoTexture(void); void exitGamePlayerPythonScripting(); -PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level); +PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level, struct Main *maggie); void exitGamePythonScripting(); void setGamePythonPath(char *path); +void resetGamePythonPath(); void pathGamePythonConfig( char *path ); int saveGamePythonConfig( char **marshal_buffer); int loadGamePythonConfig(char *marshal_buffer, int marshal_length); -void PHY_SetActiveScene(class KX_Scene* scene); -class KX_Scene* PHY_GetActiveScene(); +class KX_KetsjiEngine; +class KX_Scene; + +void KX_SetActiveScene(class KX_Scene* scene); +class KX_Scene* KX_GetActiveScene(); +class KX_KetsjiEngine* KX_GetActiveEngine(); #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_PythonInitTypes.cpp b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp new file mode 100644 index 00000000000..61e563791c3 --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp @@ -0,0 +1,226 @@ +/** + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + + + +#ifndef _adr_py_init_types_h_ // only process once, +#define _adr_py_init_types_h_ // even if multiply included + +/* Only for Class::Parents */ +#include "BL_BlenderShader.h" +#include "BL_ShapeActionActuator.h" +#include "KX_BlenderMaterial.h" +#include "KX_CameraActuator.h" +#include "KX_ConstraintActuator.h" +#include "KX_ConstraintWrapper.h" +#include "KX_GameActuator.h" +#include "KX_Light.h" +#include "KX_MeshProxy.h" +#include "KX_MouseFocusSensor.h" +#include "KX_NetworkMessageActuator.h" +#include "KX_NetworkMessageSensor.h" +#include "KX_ObjectActuator.h" +#include "KX_ParentActuator.h" +#include "KX_PhysicsObjectWrapper.h" +#include "KX_PolyProxy.h" +#include "KX_PolygonMaterial.h" +#include "KX_PythonSeq.h" +#include "KX_SCA_AddObjectActuator.h" +#include "KX_SCA_EndObjectActuator.h" +#include "KX_SCA_ReplaceMeshActuator.h" +#include "KX_SceneActuator.h" +#include "KX_StateActuator.h" +#include "KX_TrackToActuator.h" +#include "KX_VehicleWrapper.h" +#include "KX_VertexProxy.h" +#include "SCA_2DFilterActuator.h" +#include "SCA_ANDController.h" +#include "SCA_ActuatorSensor.h" +#include "SCA_AlwaysSensor.h" +#include "SCA_DelaySensor.h" +#include "SCA_JoystickSensor.h" +#include "SCA_KeyboardSensor.h" +#include "SCA_MouseSensor.h" +#include "SCA_NANDController.h" +#include "SCA_NORController.h" +#include "SCA_ORController.h" +#include "SCA_RandomSensor.h" +#include "SCA_XNORController.h" +#include "SCA_XORController.h" +#include "KX_IpoActuator.h" +#include "KX_NearSensor.h" +#include "KX_RadarSensor.h" +#include "KX_RaySensor.h" +#include "KX_SCA_DynamicActuator.h" +#include "KX_SoundActuator.h" +#include "KX_TouchSensor.h" +#include "KX_VisibilityActuator.h" +#include "SCA_PropertySensor.h" +#include "SCA_PythonController.h" +#include "SCA_RandomActuator.h" +#include "SCA_IController.h" + +static void PyType_Ready_ADD(PyObject *dict, PyTypeObject *tp, PyAttributeDef *attributes, int init_getset) +{ + PyAttributeDef *attr; + + if(init_getset) { + /* we need to do this for all types before calling PyType_Ready + * since they will call the parents PyType_Ready and those might not have initialized vars yet */ + + //if(tp->tp_base==NULL) + // printf("Debug: No Parents - '%s'\n" , tp->tp_name); + + if(tp->tp_getset==NULL && attributes->m_name) { + PyGetSetDef *attr_getset; + int attr_tot= 0; + + for(attr= attributes; attr->m_name; attr++, attr_tot++) {}; + + tp->tp_getset = attr_getset = reinterpret_cast<PyGetSetDef *>(PyMem_Malloc((attr_tot+1) * sizeof(PyGetSetDef))); // XXX - Todo, free + + + for(attr= attributes; attr->m_name; attr++, attr_getset++) { + attr_getset->name= (char *)attr->m_name; + attr_getset->doc= NULL; + + attr_getset->get= reinterpret_cast<getter>(PyObjectPlus::py_get_attrdef); + + if(attr->m_access==KX_PYATTRIBUTE_RO) + attr_getset->set= NULL; + else + attr_getset->set= reinterpret_cast<setter>(PyObjectPlus::py_set_attrdef); + + attr_getset->closure= reinterpret_cast<void *>(attr); + } + + memset(attr_getset, 0, sizeof(PyGetSetDef)); + } + } else { + PyType_Ready(tp); + PyDict_SetItemString(dict, tp->tp_name, reinterpret_cast<PyObject *>(tp)); + } + +} + + +#define PyType_Ready_Attr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, i) + +void initPyTypes(void) +{ + +/* + initPyObjectPlusType(BL_ActionActuator::Parents); + ..... +*/ + + /* For now just do PyType_Ready */ + PyObject *mod= PyModule_New("GameTypes"); + PyObject *dict= PyModule_GetDict(mod); + PyDict_SetItemString(PySys_GetObject((char *)"modules"), (char *)"GameTypes", mod); + Py_DECREF(mod); + + + for(int init_getset= 1; init_getset > -1; init_getset--) { /* run twice, once to init the getsets another to run PyType_Ready */ + PyType_Ready_Attr(dict, BL_ActionActuator, init_getset); + PyType_Ready_Attr(dict, BL_Shader, init_getset); + PyType_Ready_Attr(dict, BL_ShapeActionActuator, init_getset); + PyType_Ready_Attr(dict, CListValue, init_getset); + PyType_Ready_Attr(dict, CValue, init_getset); + PyType_Ready_Attr(dict, KX_BlenderMaterial, init_getset); + PyType_Ready_Attr(dict, KX_Camera, init_getset); + PyType_Ready_Attr(dict, KX_CameraActuator, init_getset); + PyType_Ready_Attr(dict, KX_ConstraintActuator, init_getset); + PyType_Ready_Attr(dict, KX_ConstraintWrapper, init_getset); + PyType_Ready_Attr(dict, KX_GameActuator, init_getset); + PyType_Ready_Attr(dict, KX_GameObject, init_getset); + PyType_Ready_Attr(dict, KX_IpoActuator, init_getset); + PyType_Ready_Attr(dict, KX_LightObject, init_getset); + PyType_Ready_Attr(dict, KX_MeshProxy, init_getset); + PyType_Ready_Attr(dict, KX_MouseFocusSensor, init_getset); + PyType_Ready_Attr(dict, KX_NearSensor, init_getset); + PyType_Ready_Attr(dict, KX_NetworkMessageActuator, init_getset); + PyType_Ready_Attr(dict, KX_NetworkMessageSensor, init_getset); + PyType_Ready_Attr(dict, KX_ObjectActuator, init_getset); + PyType_Ready_Attr(dict, KX_ParentActuator, init_getset); + PyType_Ready_Attr(dict, KX_PhysicsObjectWrapper, init_getset); + PyType_Ready_Attr(dict, KX_PolyProxy, init_getset); + PyType_Ready_Attr(dict, KX_PolygonMaterial, init_getset); + PyType_Ready_Attr(dict, KX_RadarSensor, init_getset); + PyType_Ready_Attr(dict, KX_RaySensor, init_getset); + PyType_Ready_Attr(dict, KX_SCA_AddObjectActuator, init_getset); + PyType_Ready_Attr(dict, KX_SCA_DynamicActuator, init_getset); + PyType_Ready_Attr(dict, KX_SCA_EndObjectActuator, init_getset); + PyType_Ready_Attr(dict, KX_SCA_ReplaceMeshActuator, init_getset); + PyType_Ready_Attr(dict, KX_Scene, init_getset); + PyType_Ready_Attr(dict, KX_SceneActuator, init_getset); + PyType_Ready_Attr(dict, KX_SoundActuator, init_getset); + PyType_Ready_Attr(dict, KX_StateActuator, init_getset); + PyType_Ready_Attr(dict, KX_TouchSensor, init_getset); + PyType_Ready_Attr(dict, KX_TrackToActuator, init_getset); + PyType_Ready_Attr(dict, KX_VehicleWrapper, init_getset); + PyType_Ready_Attr(dict, KX_VertexProxy, init_getset); + PyType_Ready_Attr(dict, KX_VisibilityActuator, init_getset); + PyType_Ready_Attr(dict, PyObjectPlus, init_getset); + PyType_Ready_Attr(dict, SCA_2DFilterActuator, init_getset); + PyType_Ready_Attr(dict, SCA_ANDController, init_getset); + PyType_Ready_Attr(dict, SCA_ActuatorSensor, init_getset); + PyType_Ready_Attr(dict, SCA_AlwaysSensor, init_getset); + PyType_Ready_Attr(dict, SCA_DelaySensor, init_getset); + PyType_Ready_Attr(dict, SCA_ILogicBrick, init_getset); + PyType_Ready_Attr(dict, SCA_IObject, init_getset); + PyType_Ready_Attr(dict, SCA_ISensor, init_getset); + PyType_Ready_Attr(dict, SCA_JoystickSensor, init_getset); + PyType_Ready_Attr(dict, SCA_KeyboardSensor, init_getset); + PyType_Ready_Attr(dict, SCA_MouseSensor, init_getset); + PyType_Ready_Attr(dict, SCA_NANDController, init_getset); + PyType_Ready_Attr(dict, SCA_NORController, init_getset); + PyType_Ready_Attr(dict, SCA_ORController, init_getset); + PyType_Ready_Attr(dict, SCA_PropertyActuator, init_getset); + PyType_Ready_Attr(dict, SCA_PropertySensor, init_getset); + PyType_Ready_Attr(dict, SCA_PythonController, init_getset); + PyType_Ready_Attr(dict, SCA_RandomActuator, init_getset); + PyType_Ready_Attr(dict, SCA_RandomSensor, init_getset); + PyType_Ready_Attr(dict, SCA_XNORController, init_getset); + PyType_Ready_Attr(dict, SCA_XORController, init_getset); + PyType_Ready_Attr(dict, SCA_IController, init_getset); + } + + + /* Normal python type */ + PyType_Ready(&KX_PythonSeq_Type); + +#ifdef USE_MATHUTILS + /* Init mathutils callbacks */ + KX_GameObject_Mathutils_Callback_Init(); + KX_ObjectActuator_Mathutils_Callback_Init(); +#endif +} + +#endif diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.h b/source/gameengine/Ketsji/KX_PythonInitTypes.h new file mode 100644 index 00000000000..6da79be9301 --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonInitTypes.h @@ -0,0 +1,35 @@ +/** + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef _adr_py_init_types_h_ // only process once, +#define _adr_py_init_types_h_ // even if multiply included + +void initPyTypes(void); + +#endif diff --git a/source/gameengine/Ketsji/KX_PythonSeq.cpp b/source/gameengine/Ketsji/KX_PythonSeq.cpp new file mode 100644 index 00000000000..75a7c9b8aeb --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonSeq.cpp @@ -0,0 +1,474 @@ +/** + * $Id: + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: none of this file. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + * Readonly sequence wrapper for lookups on logic bricks + */ + + +#include "KX_PythonSeq.h" +#include "KX_GameObject.h" +#include "SCA_ISensor.h" +#include "SCA_IController.h" +#include "SCA_IActuator.h" + + +PyObject *KX_PythonSeq_CreatePyObject( PyObject *base, short type ) +{ + KX_PythonSeq *seq = PyObject_NEW( KX_PythonSeq, &KX_PythonSeq_Type); + seq->base = base; + Py_INCREF(base); /* so we can always access to check if its valid */ + seq->type = type; + seq->iter = -1; /* init */ + return (PyObject *)seq; + } + + static void KX_PythonSeq_dealloc( KX_PythonSeq * self ) +{ + Py_DECREF(self->base); + PyObject_DEL( self ); +} + +static Py_ssize_t KX_PythonSeq_len( PyObject * self ) +{ + PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base); + + if(self_plus==NULL) { + PyErr_SetString(PyExc_SystemError, "len(seq): "BGE_PROXY_ERROR_MSG); + return -1; + } + + switch(((KX_PythonSeq *)self)->type) { + case KX_PYGENSEQ_CONT_TYPE_SENSORS: + return ((SCA_IController *)self_plus)->GetLinkedSensors().size(); + case KX_PYGENSEQ_CONT_TYPE_ACTUATORS: + return ((SCA_IController *)self_plus)->GetLinkedActuators().size(); + case KX_PYGENSEQ_OB_TYPE_SENSORS: + return ((KX_GameObject *)self_plus)->GetSensors().size(); + case KX_PYGENSEQ_OB_TYPE_CONTROLLERS: + return ((KX_GameObject *)self_plus)->GetControllers().size(); + case KX_PYGENSEQ_OB_TYPE_ACTUATORS: + return ((KX_GameObject *)self_plus)->GetActuators().size(); + default: + /* Should never happen */ + PyErr_SetString(PyExc_SystemError, "invalid type, internal error"); + return -1; + } +} + +static PyObject *KX_PythonSeq_getIndex(PyObject* self, int index) +{ + PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base); + + if(self_plus==NULL) { + PyErr_SetString(PyExc_SystemError, "val = seq[i]: "BGE_PROXY_ERROR_MSG); + return NULL; + } + + switch(((KX_PythonSeq *)self)->type) { + case KX_PYGENSEQ_CONT_TYPE_SENSORS: + { + vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors(); + if(index<0) index += linkedsensors.size(); + if(index<0 || index>= linkedsensors.size()) { + PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range"); + return NULL; + } + return linkedsensors[index]->GetProxy(); + } + case KX_PYGENSEQ_CONT_TYPE_ACTUATORS: + { + vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators(); + if(index<0) index += linkedactuators.size(); + if(index<0 || index>= linkedactuators.size()) { + PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range"); + return NULL; + } + return linkedactuators[index]->GetProxy(); + } + case KX_PYGENSEQ_OB_TYPE_SENSORS: + { + SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors(); + if(index<0) index += linkedsensors.size(); + if(index<0 || index>= linkedsensors.size()) { + PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range"); + return NULL; + } + return linkedsensors[index]->GetProxy(); + } + case KX_PYGENSEQ_OB_TYPE_CONTROLLERS: + { + SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers(); + if(index<0) index += linkedcontrollers.size(); + if(index<0 || index>= linkedcontrollers.size()) { + PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range"); + return NULL; + } + return linkedcontrollers[index]->GetProxy(); + } + case KX_PYGENSEQ_OB_TYPE_ACTUATORS: + { + SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators(); + if(index<0) index += linkedactuators.size(); + if(index<0 || index>= linkedactuators.size()) { + PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range"); + return NULL; + } + return linkedactuators[index]->GetProxy(); + } + } + + PyErr_SetString(PyExc_SystemError, "invalid sequence type, this is a bug"); + return NULL; +} + +static PyObjectPlus * KX_PythonSeq_subscript__internal(PyObject *self, char *key) +{ + PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base); + + switch(((KX_PythonSeq *)self)->type) { + case KX_PYGENSEQ_CONT_TYPE_SENSORS: + { + vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors(); + SCA_ISensor* sensor; + for (unsigned int index=0;index<linkedsensors.size();index++) { + sensor = linkedsensors[index]; + if (sensor->GetName() == key) + return static_cast<PyObjectPlus *>(sensor); + + } + break; + } + case KX_PYGENSEQ_CONT_TYPE_ACTUATORS: + { + vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators(); + SCA_IActuator* actuator; + for (unsigned int index=0;index<linkedactuators.size();index++) { + actuator = linkedactuators[index]; + if (actuator->GetName() == key) + return static_cast<PyObjectPlus *>(actuator); + } + break; + } + case KX_PYGENSEQ_OB_TYPE_SENSORS: + { + SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors(); + SCA_ISensor *sensor; + for (unsigned int index=0;index<linkedsensors.size();index++) { + sensor= linkedsensors[index]; + if (sensor->GetName() == key) + return static_cast<PyObjectPlus *>(sensor); + } + break; + } + case KX_PYGENSEQ_OB_TYPE_CONTROLLERS: + { + SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers(); + SCA_IController *controller; + for (unsigned int index=0;index<linkedcontrollers.size();index++) { + controller= linkedcontrollers[index]; + if (controller->GetName() == key) + return static_cast<PyObjectPlus *>(controller); + } + break; + } + case KX_PYGENSEQ_OB_TYPE_ACTUATORS: + { + SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators(); + SCA_IActuator *actuator; + for (unsigned int index=0;index<linkedactuators.size();index++) { + actuator= linkedactuators[index]; + if (actuator->GetName() == key) + return static_cast<PyObjectPlus *>(actuator); + } + break; + } + } + + return NULL; +} + + +static PyObject * KX_PythonSeq_subscript(PyObject * self, PyObject *key) +{ + PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base); + + if(self_plus==NULL) { + PyErr_SetString(PyExc_SystemError, "val = seq[key], KX_PythonSeq: "BGE_PROXY_ERROR_MSG); + return NULL; + } + + if (PyLong_Check(key)) { + return KX_PythonSeq_getIndex(self, PyLong_AsSsize_t( key )); + } + else if ( PyUnicode_Check(key) ) { + char *name = _PyUnicode_AsString(key); + PyObjectPlus *ret = KX_PythonSeq_subscript__internal(self, name); + + if(ret) { + return ret->GetProxy(); + } else { + PyErr_Format( PyExc_KeyError, "requested item \"%s\" does not exist", name); + return NULL; + } + } + else { + PyErr_SetString( PyExc_TypeError, "expected a string or an index" ); + return NULL; + } +} + + +static int KX_PythonSeq_contains(PyObject *self, PyObject *key) +{ + PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base); + + if(self_plus==NULL) { + PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: "BGE_PROXY_ERROR_MSG); + return -1; + } + if(!PyUnicode_Check(key)) { + PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: key must be a string"); + return -1; + } + + if(KX_PythonSeq_subscript__internal(self, _PyUnicode_AsString(key))) + return 1; + + return 0; +} + +/* Matches python dict.get(key, [default]) */ +PyObject* KX_PythonSeq_get(PyObject * self, PyObject *args) +{ + char *key; + PyObject* def = Py_None; + PyObjectPlus* ret_plus; + + if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) + return NULL; + + if((ret_plus = KX_PythonSeq_subscript__internal(self, key))) + return ret_plus->GetProxy(); + + Py_INCREF(def); + return def; +} + +PySequenceMethods KX_PythonSeq_as_sequence = { + NULL, /* Cant set the len otherwise it can evaluate as false */ + NULL, /* sq_concat */ + NULL, /* sq_repeat */ + NULL, /* sq_item */ + NULL, /* sq_slice */ + NULL, /* sq_ass_item */ + NULL, /* sq_ass_slice */ + (objobjproc)KX_PythonSeq_contains, /* sq_contains */ +}; + +static PyMappingMethods KX_PythonSeq_as_mapping = { + KX_PythonSeq_len, /* mp_length */ + KX_PythonSeq_subscript, /* mp_subscript */ + 0, /* mp_ass_subscript */ +}; + +PyMethodDef KX_PythonSeq_methods[] = { + // dict style access for props + {"get",(PyCFunction) KX_PythonSeq_get, METH_VARARGS}, + {NULL,NULL} //Sentinel +}; + +/* + * Initialize the interator index + */ + +static PyObject *KX_PythonSeq_getIter(KX_PythonSeq *self) +{ + if(BGE_PROXY_REF(self->base)==NULL) { + PyErr_SetString(PyExc_SystemError, "for i in seq: "BGE_PROXY_ERROR_MSG); + return NULL; + } + + /* create a new iterator if were alredy using this one */ + if (self->iter == -1) { + self->iter = 0; + Py_INCREF(self); + return (PyObject *)self; + } else { + return KX_PythonSeq_CreatePyObject(self->base, self->type); + } + } + + +/* + * Return next KX_PythonSeq iter. + */ + +static PyObject *KX_PythonSeq_nextIter(KX_PythonSeq *self) +{ + PyObject *object = KX_PythonSeq_getIndex((PyObject *)self, self->iter); + + self->iter++; + if( object==NULL ) { + self->iter= -1; /* for reuse */ + PyErr_SetString(PyExc_StopIteration, "iterator at end"); + } + return object; /* can be NULL for end of iterator */ +} + + +static int KX_PythonSeq_compare( KX_PythonSeq * a, KX_PythonSeq * b ) +{ + return ( a->type == b->type && a->base == b->base) ? 0 : -1; +} + +static PyObject *KX_PythonSeq_richcmp(PyObject *a, PyObject *b, int op) +{ + PyObject *res; + int ok= -1; /* zero is true */ + + if(BPy_KX_PythonSeq_Check(a) && BPy_KX_PythonSeq_Check(b)) + ok= KX_PythonSeq_compare((KX_PythonSeq *)a, (KX_PythonSeq *)b); + + switch (op) { + case Py_NE: + ok = !ok; /* pass through */ + case Py_EQ: + res = ok ? Py_False : Py_True; + break; + + case Py_LT: + case Py_LE: + case Py_GT: + case Py_GE: + res = Py_NotImplemented; + break; + default: + PyErr_BadArgument(); + return NULL; + } + + Py_INCREF(res); + return res; +} + + +/* + * repr function + * convert to a list and get its string value + */ +static PyObject *KX_PythonSeq_repr( KX_PythonSeq * self ) +{ + PyObject *list = PySequence_List((PyObject *)self); + PyObject *repr = PyObject_Repr(list); + Py_DECREF(list); + return repr; +} + + +/*****************************************************************************/ +/* Python KX_PythonSeq_Type structure definition: */ +/*****************************************************************************/ +PyTypeObject KX_PythonSeq_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + /* For printing, in format "<module>.<name>" */ + "KX_PythonSeq", /* char *tp_name; */ + sizeof( KX_PythonSeq ), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + ( destructor ) KX_PythonSeq_dealloc, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + ( reprfunc ) KX_PythonSeq_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + &KX_PythonSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + &KX_PythonSeq_as_mapping, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + (richcmpfunc)KX_PythonSeq_richcmp, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + ( getiterfunc) KX_PythonSeq_getIter, /* getiterfunc tp_iter; */ + ( iternextfunc ) KX_PythonSeq_nextIter, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + KX_PythonSeq_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; diff --git a/source/gameengine/Ketsji/KX_PythonSeq.h b/source/gameengine/Ketsji/KX_PythonSeq.h new file mode 100644 index 00000000000..15a016224a9 --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonSeq.h @@ -0,0 +1,60 @@ +/** + * $Id: + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + * Readonly sequence wrapper for lookups on logic bricks + */ + +#ifndef _adr_py_seq_h_ // only process once, +#define _adr_py_seq_h_ // even if multiply included + +#include "PyObjectPlus.h" + +// ------------------------- +enum KX_PYGENSEQ_TYPE { + KX_PYGENSEQ_CONT_TYPE_SENSORS, + KX_PYGENSEQ_CONT_TYPE_ACTUATORS, + KX_PYGENSEQ_OB_TYPE_SENSORS, + KX_PYGENSEQ_OB_TYPE_CONTROLLERS, + KX_PYGENSEQ_OB_TYPE_ACTUATORS +}; + +/* The Main PyType Object defined in Main.c */ +extern PyTypeObject KX_PythonSeq_Type; + +#define BPy_KX_PythonSeq_Check(v) \ + ((v)->ob_type == &KX_PythonSeq_Type) + +typedef struct { + PyObject_VAR_HEAD + PyObject *base; + short type; + short iter; +} KX_PythonSeq; + +PyObject *KX_PythonSeq_CreatePyObject(PyObject *base, short type); + +#endif // _adr_py_seq_h_ diff --git a/source/gameengine/Ketsji/KX_RadarSensor.cpp b/source/gameengine/Ketsji/KX_RadarSensor.cpp index 244e9b75d8e..eb127be8044 100644 --- a/source/gameengine/Ketsji/KX_RadarSensor.cpp +++ b/source/gameengine/Ketsji/KX_RadarSensor.cpp @@ -28,7 +28,9 @@ #include "KX_RadarSensor.h" #include "KX_GameObject.h" +#include "KX_PyMath.h" #include "PHY_IPhysicsController.h" +#include "PHY_IMotionState.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -46,9 +48,7 @@ KX_RadarSensor::KX_RadarSensor(SCA_EventManager* eventmgr, double margin, double resetmargin, bool bFindMaterial, - const STR_String& touchedpropname, - class KX_Scene* kxscene, - PyTypeObject* T) + const STR_String& touchedpropname) : KX_NearSensor( eventmgr, @@ -58,14 +58,13 @@ KX_RadarSensor::KX_RadarSensor(SCA_EventManager* eventmgr, resetmargin, bFindMaterial, touchedpropname, - kxscene, - physCtrl, - T), + physCtrl), + m_coneradius(coneradius), m_coneheight(coneheight), m_axis(axis) { - m_client_info->m_type = KX_ClientObjectInfo::RADAR; + m_client_info->m_type = KX_ClientObjectInfo::SENSOR; //m_client_info->m_clientobject = gameobj; //m_client_info->m_auxilary_info = NULL; //sumoObj->setClientObject(&m_client_info); @@ -79,34 +78,10 @@ KX_RadarSensor::~KX_RadarSensor() CValue* KX_RadarSensor::GetReplica() { KX_RadarSensor* replica = new KX_RadarSensor(*this); - replica->m_colliders = new CListValue(); - replica->Init(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - - replica->m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::RADAR); - - if (replica->m_physCtrl) - { - replica->m_physCtrl = replica->m_physCtrl->GetReplica(); - if (replica->m_physCtrl) - { - replica->m_physCtrl->setNewClientInfo(replica->m_client_info); - } - } - - //todo: make sure replication works fine! - //>m_sumoObj = new SM_Object(DT_NewCone(m_coneradius, m_coneheight),NULL,NULL,NULL); - //replica->m_sumoObj->setMargin(m_Margin); - //replica->m_sumoObj->setClientObject(replica->m_client_info); - - ((KX_GameObject*)replica->GetParent())->GetSGNode()->ComputeWorldTransforms(NULL); - replica->SynchronizeTransform(); - + replica->ProcessReplica(); return replica; } - /** * Transforms the collision object. A cone is not correctly centered * for usage. */ @@ -170,110 +145,74 @@ void KX_RadarSensor::SynchronizeTransform() { } } - m_cone_origin = trans.getOrigin(); - m_cone_target = trans(MT_Point3(0, -m_coneheight/2.0 ,0)); + + //Using a temp variable to translate MT_Point3 to float[3]. + //float[3] works better for the Python interface. + MT_Point3 temp = trans.getOrigin(); + m_cone_origin[0] = temp[0]; + m_cone_origin[1] = temp[1]; + m_cone_origin[2] = temp[2]; + + temp = trans(MT_Point3(0, -m_coneheight/2.0 ,0)); + m_cone_target[0] = temp[0]; + m_cone_target[1] = temp[1]; + m_cone_target[2] = temp[2]; if (m_physCtrl) { - MT_Quaternion orn = trans.getRotation(); - MT_Point3 pos = trans.getOrigin(); - m_physCtrl->setPosition(pos[0],pos[1],pos[2]); - m_physCtrl->setOrientation(orn[0],orn[1],orn[2],orn[3]); - m_physCtrl->calcXform(); + PHY_IMotionState* motionState = m_physCtrl->GetMotionState(); + const MT_Point3& pos = trans.getOrigin(); + float ori[12]; + trans.getBasis().getValue(ori); + motionState->setWorldPosition(pos[0], pos[1], pos[2]); + motionState->setWorldOrientation(ori); + m_physCtrl->WriteMotionStateToDynamics(true); } } /* ------------------------------------------------------------------------- */ -/* Python functions */ +/* Python Functions */ /* ------------------------------------------------------------------------- */ -/* Integration hooks ------------------------------------------------------- */ +/* none */ + +/* ------------------------------------------------------------------------- */ +/* Python Integration Hooks */ +/* ------------------------------------------------------------------------- */ PyTypeObject KX_RadarSensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_RadarSensor", - sizeof(KX_RadarSensor), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_RadarSensor::Parents[] = { - &KX_RadarSensor::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &KX_NearSensor::Type, - &KX_TouchSensor::Type, - &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_RadarSensor::Methods[] = { - {"getConeOrigin", (PyCFunction) KX_RadarSensor::sPyGetConeOrigin, - METH_VARARGS, (PY_METHODCHAR)GetConeOrigin_doc}, - {"getConeTarget", (PyCFunction) KX_RadarSensor::sPyGetConeTarget, - METH_VARARGS, (PY_METHODCHAR)GetConeTarget_doc}, - {"getConeHeight", (PyCFunction) KX_RadarSensor::sPyGetConeHeight, - METH_VARARGS, (PY_METHODCHAR)GetConeHeight_doc}, - {NULL,NULL,NULL,NULL} //Sentinel + {NULL} //Sentinel }; -PyObject* KX_RadarSensor::_getattr(const STR_String& attr) { - _getattr_up(KX_TouchSensor); -} - -/* getConeOrigin */ -const char KX_RadarSensor::GetConeOrigin_doc[] = -"getConeOrigin()\n" -"\tReturns the origin of the cone with which to test. The origin\n" -"\tis in the middle of the cone."; -PyObject* KX_RadarSensor::PyGetConeOrigin(PyObject* self, - PyObject* args, - PyObject* kwds) { - PyObject *retVal = PyList_New(3); - - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_cone_origin[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_cone_origin[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_cone_origin[2])); - - return retVal; -} - -/* getConeOrigin */ -const char KX_RadarSensor::GetConeTarget_doc[] = -"getConeTarget()\n" -"\tReturns the center of the bottom face of the cone with which to test.\n"; -PyObject* KX_RadarSensor::PyGetConeTarget(PyObject* self, - PyObject* args, - PyObject* kwds) { - PyObject *retVal = PyList_New(3); - - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_cone_target[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_cone_target[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_cone_target[2])); - - return retVal; -} - -/* getConeOrigin */ -const char KX_RadarSensor::GetConeHeight_doc[] = -"getConeHeight()\n" -"\tReturns the height of the cone with which to test.\n"; -PyObject* KX_RadarSensor::PyGetConeHeight(PyObject* self, - PyObject* args, - PyObject* kwds) { - return PyFloat_FromDouble(m_coneheight); -} - +PyAttributeDef KX_RadarSensor::Attributes[] = { + KX_PYATTRIBUTE_FLOAT_ARRAY_RO("coneOrigin", KX_RadarSensor, m_cone_origin, 3), + KX_PYATTRIBUTE_FLOAT_ARRAY_RO("coneTarget", KX_RadarSensor, m_cone_target, 3), + KX_PYATTRIBUTE_FLOAT_RO("distance", KX_RadarSensor, m_coneheight), + KX_PYATTRIBUTE_FLOAT_RW("angle", 0, 360, KX_RadarSensor, m_coneradius), + KX_PYATTRIBUTE_INT_RW("axis", 0, 5, true, KX_RadarSensor, m_axis), + {NULL} //Sentinel +}; diff --git a/source/gameengine/Ketsji/KX_RadarSensor.h b/source/gameengine/Ketsji/KX_RadarSensor.h index 7272b219e37..487e9f1aaa7 100644 --- a/source/gameengine/Ketsji/KX_RadarSensor.h +++ b/source/gameengine/Ketsji/KX_RadarSensor.h @@ -40,23 +40,23 @@ class KX_RadarSensor : public KX_NearSensor protected: Py_Header; - MT_Scalar m_coneradius; + float m_coneradius; /** * Height of the cone. */ - MT_Scalar m_coneheight; + float m_coneheight; int m_axis; /** * The previous position of the origin of the cone. */ - MT_Point3 m_cone_origin; + float m_cone_origin[3]; /** * The previous direction of the cone (origin to bottom plane). */ - MT_Point3 m_cone_target; + float m_cone_target[3]; public: @@ -69,9 +69,7 @@ public: double margin, double resetmargin, bool bFindMaterial, - const STR_String& touchedpropname, - class KX_Scene* kxscene, - PyTypeObject* T = &Type); + const STR_String& touchedpropname); KX_RadarSensor(); virtual ~KX_RadarSensor(); virtual void SynchronizeTransform(); @@ -80,12 +78,17 @@ public: /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); + enum RadarAxis { + KX_RADAR_AXIS_POS_X = 0, + KX_RADAR_AXIS_POS_Y, + KX_RADAR_AXIS_POS_Z, + KX_RADAR_AXIS_NEG_X, + KX_RADAR_AXIS_NEG_Y, + KX_RADAR_AXIS_NEG_Z + }; - KX_PYMETHOD_DOC(KX_RadarSensor,GetConeOrigin); - KX_PYMETHOD_DOC(KX_RadarSensor,GetConeTarget); - KX_PYMETHOD_DOC(KX_RadarSensor,GetConeHeight); + /* python */ + virtual sensortype GetSensorType() { return ST_RADAR; } }; diff --git a/source/gameengine/Ketsji/KX_RayCast.cpp b/source/gameengine/Ketsji/KX_RayCast.cpp index 974d4b992a6..8c7612bf663 100644 --- a/source/gameengine/Ketsji/KX_RayCast.cpp +++ b/source/gameengine/Ketsji/KX_RayCast.cpp @@ -56,12 +56,15 @@ void KX_RayCast::reportHit(PHY_RayCastResult* result) bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, KX_RayCast& callback) { + if(physics_environment==NULL) return false; /* prevents crashing in some cases */ + // Loops over all physics objects between frompoint and topoint, // calling callback.RayHit for each one. // // callback.RayHit should return true to stop looking, or false to continue. // // returns true if an object was found, false if not. + MT_Point3 frompoint(_frompoint); const MT_Vector3 todir( (topoint - frompoint).safe_normalized() ); MT_Point3 prevpoint(_frompoint+todir*(-1.f)); diff --git a/source/gameengine/Ketsji/KX_RayCast.h b/source/gameengine/Ketsji/KX_RayCast.h index c3084c997a1..cdafc894f6c 100644 --- a/source/gameengine/Ketsji/KX_RayCast.h +++ b/source/gameengine/Ketsji/KX_RayCast.h @@ -89,6 +89,12 @@ public: const MT_Point3& topoint, KX_RayCast& callback); + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_RayCast"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; template<class T> class KX_RayCast::Callback : public KX_RayCast @@ -121,7 +127,13 @@ public: } return self->NeedRayCast(info); } - + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_RayCast::Callback"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; diff --git a/source/gameengine/Ketsji/KX_RayEventManager.cpp b/source/gameengine/Ketsji/KX_RayEventManager.cpp index 1af29151adf..50fa4f5e310 100644 --- a/source/gameengine/Ketsji/KX_RayEventManager.cpp +++ b/source/gameengine/Ketsji/KX_RayEventManager.cpp @@ -44,9 +44,10 @@ using namespace std; void KX_RayEventManager::NextFrame() { - for (set<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++) + SG_DList::iterator<SCA_ISensor> it(m_sensors); + for (it.begin();!it.end();++it) { - (*i)->Activate(m_logicmgr, NULL); + (*it)->Activate(m_logicmgr); } } diff --git a/source/gameengine/Ketsji/KX_RayEventManager.h b/source/gameengine/Ketsji/KX_RayEventManager.h index b816d4d5250..27c9be14d1f 100644 --- a/source/gameengine/Ketsji/KX_RayEventManager.h +++ b/source/gameengine/Ketsji/KX_RayEventManager.h @@ -45,6 +45,13 @@ public: m_logicmgr(logicmgr) {} virtual void NextFrame(); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_RayEventManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_RAYEVENTMGR diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp index e24fb773eac..1f36945ccaa 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.cpp +++ b/source/gameengine/Ketsji/KX_RaySensor.cpp @@ -38,6 +38,7 @@ #include "KX_GameObject.h" #include "KX_Scene.h" #include "KX_RayCast.h" +#include "KX_PyMath.h" #include "PHY_IPhysicsEnvironment.h" #include "KX_IPhysicsController.h" #include "PHY_IPhysicsController.h" @@ -54,9 +55,8 @@ KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr, bool bXRay, double distance, int axis, - KX_Scene* ketsjiScene, - PyTypeObject* T) - : SCA_ISensor(gameobj,eventmgr, T), + KX_Scene* ketsjiScene) + : SCA_ISensor(gameobj,eventmgr), m_propertyname(propname), m_bFindMaterial(bFindMaterial), m_bXRay(bXRay), @@ -87,8 +87,7 @@ KX_RaySensor::~KX_RaySensor() CValue* KX_RaySensor::GetReplica() { KX_RaySensor* replica = new KX_RaySensor(*this); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); replica->Init(); return replica; @@ -135,8 +134,13 @@ bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void { m_rayHit = true; m_hitObject = hitKXObj; - m_hitPosition = result->m_hitPoint; - m_hitNormal = result->m_hitNormal; + m_hitPosition[0] = result->m_hitPoint[0]; + m_hitPosition[1] = result->m_hitPoint[1]; + m_hitPosition[2] = result->m_hitPoint[2]; + + m_hitNormal[0] = result->m_hitNormal[0]; + m_hitNormal[1] = result->m_hitNormal[1]; + m_hitNormal[2] = result->m_hitNormal[2]; } // no multi-hit search yet @@ -173,14 +177,19 @@ bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo* client) return true; } -bool KX_RaySensor::Evaluate(CValue* event) +bool KX_RaySensor::Evaluate() { bool result = false; bool reset = m_reset && m_level; m_rayHit = false; m_hitObject = NULL; - m_hitPosition = MT_Vector3(0,0,0); - m_hitNormal = MT_Vector3(1,0,0); + m_hitPosition[0] = 0; + m_hitPosition[1] = 0; + m_hitPosition[2] = 0; + + m_hitNormal[0] = 1; + m_hitNormal[1] = 0; + m_hitNormal[2] = 0; KX_GameObject* obj = (KX_GameObject*)GetParent(); MT_Point3 frompoint = obj->NodeGetWorldPosition(); @@ -235,7 +244,9 @@ bool KX_RaySensor::Evaluate(CValue* event) } } todir.normalize(); - m_rayDirection = todir; + m_rayDirection[0] = todir[0]; + m_rayDirection[1] = todir[1]; + m_rayDirection[2] = todir[2]; MT_Point3 topoint = frompoint + (m_distance) * todir; PHY_IPhysicsEnvironment* pe = m_scene->GetPhysicsEnvironment(); @@ -308,116 +319,50 @@ bool KX_RaySensor::Evaluate(CValue* event) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_RaySensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_RaySensor", - sizeof(KX_RaySensor), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_RaySensor::Parents[] = { - &KX_RaySensor::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new + }; PyMethodDef KX_RaySensor::Methods[] = { - {"getHitObject",(PyCFunction) KX_RaySensor::sPyGetHitObject,METH_VARARGS, (PY_METHODCHAR)GetHitObject_doc}, - {"getHitPosition",(PyCFunction) KX_RaySensor::sPyGetHitPosition,METH_VARARGS, (PY_METHODCHAR)GetHitPosition_doc}, - {"getHitNormal",(PyCFunction) KX_RaySensor::sPyGetHitNormal,METH_VARARGS, (PY_METHODCHAR)GetHitNormal_doc}, - {"getRayDirection",(PyCFunction) KX_RaySensor::sPyGetRayDirection,METH_VARARGS, (PY_METHODCHAR)GetRayDirection_doc}, {NULL,NULL} //Sentinel }; -const char KX_RaySensor::GetHitObject_doc[] = -"getHitObject()\n" -"\tReturns the name of the object that was hit by this ray.\n"; -PyObject* KX_RaySensor::PyGetHitObject(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - if (m_hitObject) - { - return m_hitObject->AddRef(); - } - Py_Return; -} - - -const char KX_RaySensor::GetHitPosition_doc[] = -"getHitPosition()\n" -"\tReturns the position (in worldcoordinates) where the object was hit by this ray.\n"; -PyObject* KX_RaySensor::PyGetHitPosition(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - - MT_Point3 pos = m_hitPosition; - - PyObject* resultlist = PyList_New(3); - int index; - for (index=0;index<3;index++) - { - PyList_SetItem(resultlist,index,PyFloat_FromDouble(pos[index])); - } - return resultlist; - -} - -const char KX_RaySensor::GetRayDirection_doc[] = -"getRayDirection()\n" -"\tReturns the direction from the ray (in worldcoordinates) .\n"; -PyObject* KX_RaySensor::PyGetRayDirection(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - - MT_Vector3 dir = m_rayDirection; - - PyObject* resultlist = PyList_New(3); - int index; - for (index=0;index<3;index++) - { - PyList_SetItem(resultlist,index,PyFloat_FromDouble(dir[index])); - } - return resultlist; - -} +PyAttributeDef KX_RaySensor::Attributes[] = { + KX_PYATTRIBUTE_BOOL_RW("useMaterial", KX_RaySensor, m_bFindMaterial), + KX_PYATTRIBUTE_BOOL_RW("useXRay", KX_RaySensor, m_bXRay), + KX_PYATTRIBUTE_FLOAT_RW("range", 0, 10000, KX_RaySensor, m_distance), + KX_PYATTRIBUTE_STRING_RW("propName", 0, 100, false, KX_RaySensor, m_propertyname), + KX_PYATTRIBUTE_INT_RW("axis", 0, 5, true, KX_RaySensor, m_axis), + KX_PYATTRIBUTE_FLOAT_ARRAY_RO("hitPosition", KX_RaySensor, m_hitPosition, 3), + KX_PYATTRIBUTE_FLOAT_ARRAY_RO("rayDirection", KX_RaySensor, m_rayDirection, 3), + KX_PYATTRIBUTE_FLOAT_ARRAY_RO("hitNormal", KX_RaySensor, m_hitNormal, 3), + KX_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_RaySensor, pyattr_get_hitobject), + { NULL } //Sentinel +}; -const char KX_RaySensor::GetHitNormal_doc[] = -"getHitNormal()\n" -"\tReturns the normal (in worldcoordinates) of the object at the location where the object was hit by this ray.\n"; -PyObject* KX_RaySensor::PyGetHitNormal(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_RaySensor::pyattr_get_hitobject(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - MT_Vector3 pos = m_hitNormal; - - PyObject* resultlist = PyList_New(3); - int index; - for (index=0;index<3;index++) - { - PyList_SetItem(resultlist,index,PyFloat_FromDouble(pos[index])); - } - return resultlist; - -} - - + KX_RaySensor* self = static_cast<KX_RaySensor*>(self_v); + if (self->m_hitObject) + return self->m_hitObject->GetProxy(); -PyObject* KX_RaySensor::_getattr(const STR_String& attr) { - _getattr_up(SCA_ISensor); + Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h index 02a755fedc1..d3e92a14214 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.h +++ b/source/gameengine/Ketsji/KX_RaySensor.h @@ -44,15 +44,15 @@ class KX_RaySensor : public SCA_ISensor STR_String m_propertyname; bool m_bFindMaterial; bool m_bXRay; - double m_distance; + float m_distance; class KX_Scene* m_scene; bool m_bTriggered; int m_axis; bool m_rayHit; - MT_Point3 m_hitPosition; + float m_hitPosition[3]; SCA_IObject* m_hitObject; - MT_Vector3 m_hitNormal; - MT_Vector3 m_rayDirection; + float m_hitNormal[3]; + float m_rayDirection[3]; public: KX_RaySensor(class SCA_EventManager* eventmgr, @@ -62,24 +62,31 @@ public: bool bXRay, double distance, int axis, - class KX_Scene* ketsjiScene, - PyTypeObject* T = &Type); + class KX_Scene* ketsjiScene); virtual ~KX_RaySensor(); virtual CValue* GetReplica(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void Init(); bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); bool NeedRayCast(KX_ClientObjectInfo* client); + + + //Python Interface + enum RayAxis { + KX_RAY_AXIS_POS_Y = 0, + KX_RAY_AXIS_POS_X, + KX_RAY_AXIS_POS_Z, + KX_RAY_AXIS_NEG_X, + KX_RAY_AXIS_NEG_Y, + KX_RAY_AXIS_NEG_Z + }; - KX_PYMETHOD_DOC(KX_RaySensor,GetHitObject); - KX_PYMETHOD_DOC(KX_RaySensor,GetHitPosition); - KX_PYMETHOD_DOC(KX_RaySensor,GetHitNormal); - KX_PYMETHOD_DOC(KX_RaySensor,GetRayDirection); - virtual PyObject* _getattr(const STR_String& attr); + /* Attributes */ + static PyObject* pyattr_get_hitobject(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); }; diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp index 5777f54b799..099403fc28d 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp @@ -38,7 +38,6 @@ #include "SCA_IScene.h" #include "KX_GameObject.h" #include "KX_IPhysicsController.h" - #include "PyObjectPlus.h" #ifdef HAVE_CONFIG_H @@ -53,22 +52,25 @@ KX_SCA_AddObjectActuator::KX_SCA_AddObjectActuator(SCA_IObject *gameobj, SCA_IObject *original, int time, SCA_IScene* scene, - const MT_Vector3& linvel, + const float *linvel, bool linv_local, - const MT_Vector3& angvel, - bool angv_local, - PyTypeObject* T) + const float *angvel, + bool angv_local) : - SCA_IActuator(gameobj, T), + SCA_IActuator(gameobj), m_OriginalObject(original), m_scene(scene), - m_linear_velocity(linvel), m_localLinvFlag(linv_local), - - m_angular_velocity(angvel), m_localAngvFlag(angv_local) { + m_linear_velocity[0] = linvel[0]; + m_linear_velocity[1] = linvel[1]; + m_linear_velocity[2] = linvel[2]; + m_angular_velocity[0] = angvel[0]; + m_angular_velocity[1] = angvel[1]; + m_angular_velocity[2] = angvel[2]; + if (m_OriginalObject) m_OriginalObject->RegisterActuator(this); @@ -83,7 +85,7 @@ KX_SCA_AddObjectActuator::~KX_SCA_AddObjectActuator() if (m_OriginalObject) m_OriginalObject->UnregisterActuator(this); if (m_lastCreatedObject) - m_lastCreatedObject->Release(); + m_lastCreatedObject->UnregisterActuator(this); } @@ -121,7 +123,6 @@ CValue* KX_SCA_AddObjectActuator::GetReplica() // this will copy properties and so on... replica->ProcessReplica(); - CValue::AddDataToReplica(replica); return replica; } @@ -142,6 +143,12 @@ bool KX_SCA_AddObjectActuator::UnlinkObject(SCA_IObject* clientobj) m_OriginalObject = NULL; return true; } + if (clientobj == m_lastCreatedObject) + { + // this object is being deleted, we cannot continue to track it. + m_lastCreatedObject = NULL; + return true; + } return false; } @@ -163,212 +170,79 @@ void KX_SCA_AddObjectActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_SCA_AddObjectActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_SCA_AddObjectActuator", - sizeof(KX_SCA_AddObjectActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, - __repr, 0, 0, 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, 0, - 0 -}; - -PyParentObject KX_SCA_AddObjectActuator::Parents[] = { &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; + PyMethodDef KX_SCA_AddObjectActuator::Methods[] = { - {"setObject", (PyCFunction) KX_SCA_AddObjectActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc}, - {"setTime", (PyCFunction) KX_SCA_AddObjectActuator::sPySetTime, METH_O, (PY_METHODCHAR)SetTime_doc}, - {"getObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc}, - {"getTime", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetTime, METH_NOARGS, (PY_METHODCHAR)GetTime_doc}, - {"getLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLinearVelocity, METH_NOARGS, (PY_METHODCHAR)GetLinearVelocity_doc}, - {"setLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPySetLinearVelocity, METH_VARARGS, (PY_METHODCHAR)SetLinearVelocity_doc}, - {"getAngularVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetAngularVelocity, METH_NOARGS, (PY_METHODCHAR)GetAngularVelocity_doc}, - {"setAngularVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPySetAngularVelocity, METH_VARARGS, (PY_METHODCHAR)SetAngularVelocity_doc}, - {"getLastCreatedObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLastCreatedObject, METH_NOARGS,"getLastCreatedObject() : get the object handle to the last created object\n"}, {"instantAddObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyInstantAddObject, METH_NOARGS,"instantAddObject() : immediately add object without delay\n"}, - {NULL,NULL} //Sentinel }; +PyAttributeDef KX_SCA_AddObjectActuator::Attributes[] = { + KX_PYATTRIBUTE_RW_FUNCTION("object",KX_SCA_AddObjectActuator,pyattr_get_object,pyattr_set_object), + KX_PYATTRIBUTE_RO_FUNCTION("objectLastCreated",KX_SCA_AddObjectActuator,pyattr_get_objectLastCreated), + KX_PYATTRIBUTE_INT_RW("time",0,2000,true,KX_SCA_AddObjectActuator,m_timeProp), + KX_PYATTRIBUTE_FLOAT_ARRAY_RW("linearVelocity",-FLT_MAX,FLT_MAX,KX_SCA_AddObjectActuator,m_linear_velocity,3), + KX_PYATTRIBUTE_FLOAT_ARRAY_RW("angularVelocity",-FLT_MAX,FLT_MAX,KX_SCA_AddObjectActuator,m_angular_velocity,3), + { NULL } //Sentinel +}; -PyObject* KX_SCA_AddObjectActuator::_getattr(const STR_String& attr) +PyObject* KX_SCA_AddObjectActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) { - _getattr_up(SCA_IActuator); + KX_SCA_AddObjectActuator* actuator = static_cast<KX_SCA_AddObjectActuator*>(self); + if (!actuator->m_OriginalObject) + Py_RETURN_NONE; + else + return actuator->m_OriginalObject->GetProxy(); } -/* 1. setObject */ -const char KX_SCA_AddObjectActuator::SetObject_doc[] = -"setObject(object)\n" -"\t- object: KX_GameObject, string or None\n" -"\tSets the object that will be added. There has to be an object\n" -"\tof this name. If not, this function does nothing.\n"; -PyObject* KX_SCA_AddObjectActuator::PySetObject(PyObject* self, PyObject* value) +int KX_SCA_AddObjectActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { + KX_SCA_AddObjectActuator* actuator = static_cast<KX_SCA_AddObjectActuator*>(self); KX_GameObject *gameobj; - - if (!ConvertPythonToGameObject(value, &gameobj, true)) - return NULL; // ConvertPythonToGameObject sets the error - - if (m_OriginalObject != NULL) - m_OriginalObject->UnregisterActuator(this); - - m_OriginalObject = (SCA_IObject*)gameobj; - if (m_OriginalObject) - m_OriginalObject->RegisterActuator(this); - - Py_RETURN_NONE; -} - - - -/* 2. setTime */ -const char KX_SCA_AddObjectActuator::SetTime_doc[] = -"setTime(duration)\n" -"\t- duration: integer\n" -"\tSets the lifetime of the object that will be added, in frames. \n" -"\tIf the duration is negative, it is set to 0.\n"; - - -PyObject* KX_SCA_AddObjectActuator::PySetTime(PyObject* self, PyObject* value) -{ - int deltatime = PyInt_AsLong(value); - if (deltatime==-1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "expected an int"); - return NULL; - } - - m_timeProp = deltatime; - if (m_timeProp < 0) m_timeProp = 0; - - Py_RETURN_NONE; -} - - - -/* 3. getTime */ -const char KX_SCA_AddObjectActuator::GetTime_doc[] = -"GetTime()\n" -"\tReturns the lifetime of the object that will be added.\n"; - + + if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_SCA_AddObjectActuator")) + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + + if (actuator->m_OriginalObject != NULL) + actuator->m_OriginalObject->UnregisterActuator(actuator); -PyObject* KX_SCA_AddObjectActuator::PyGetTime(PyObject* self) -{ - return PyInt_FromLong(m_timeProp); + actuator->m_OriginalObject = (SCA_IObject*)gameobj; + + if (actuator->m_OriginalObject) + actuator->m_OriginalObject->RegisterActuator(actuator); + + return PY_SET_ATTR_SUCCESS; } - -/* 4. getObject */ -const char KX_SCA_AddObjectActuator::GetObject_doc[] = -"getObject(name_only = 1)\n" -"name_only - optional arg, when true will return the KX_GameObject rather then its name\n" -"\tReturns the name of the object that will be added.\n"; -PyObject* KX_SCA_AddObjectActuator::PyGetObject(PyObject* self, PyObject* args) +PyObject* KX_SCA_AddObjectActuator::pyattr_get_objectLastCreated(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) { - int ret_name_only = 1; - if (!PyArg_ParseTuple(args, "|i", &ret_name_only)) - return NULL; - - if (!m_OriginalObject) + KX_SCA_AddObjectActuator* actuator = static_cast<KX_SCA_AddObjectActuator*>(self); + if (!actuator->m_lastCreatedObject) Py_RETURN_NONE; - - if (ret_name_only) - return PyString_FromString(m_OriginalObject->GetName()); else - return m_OriginalObject->AddRef(); -} - - - -/* 5. getLinearVelocity */ -const char KX_SCA_AddObjectActuator::GetLinearVelocity_doc[] = -"GetLinearVelocity()\n" -"\tReturns the linear velocity that will be assigned to \n" -"\tthe created object.\n"; - -PyObject* KX_SCA_AddObjectActuator::PyGetLinearVelocity(PyObject* self) -{ - PyObject *retVal = PyList_New(3); - - PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0])); - PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1])); - PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2])); - - return retVal; -} - - - -/* 6. setLinearVelocity */ -const char KX_SCA_AddObjectActuator::SetLinearVelocity_doc[] = -"setLinearVelocity(vx, vy, vz)\n" -"\t- vx: float\n" -"\t- vy: float\n" -"\t- vz: float\n" -"\t- local: bool\n" -"\tAssign this velocity to the created object. \n"; - -PyObject* KX_SCA_AddObjectActuator::PySetLinearVelocity(PyObject* self, PyObject* args) -{ - - float vecArg[3]; - if (!PyArg_ParseTuple(args, "fff", &vecArg[0], &vecArg[1], &vecArg[2])) - return NULL; - - m_linear_velocity.setValue(vecArg); - Py_RETURN_NONE; -} - -/* 7. getAngularVelocity */ -const char KX_SCA_AddObjectActuator::GetAngularVelocity_doc[] = -"GetAngularVelocity()\n" -"\tReturns the angular velocity that will be assigned to \n" -"\tthe created object.\n"; - -PyObject* KX_SCA_AddObjectActuator::PyGetAngularVelocity(PyObject* self) -{ - PyObject *retVal = PyList_New(3); - - PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_angular_velocity[0])); - PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_angular_velocity[1])); - PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_angular_velocity[2])); - - return retVal; + return actuator->m_lastCreatedObject->GetProxy(); } - -/* 8. setAngularVelocity */ -const char KX_SCA_AddObjectActuator::SetAngularVelocity_doc[] = -"setAngularVelocity(vx, vy, vz)\n" -"\t- vx: float\n" -"\t- vy: float\n" -"\t- vz: float\n" -"\t- local: bool\n" -"\tAssign this angular velocity to the created object. \n"; - -PyObject* KX_SCA_AddObjectActuator::PySetAngularVelocity(PyObject* self, PyObject* args) -{ - - float vecArg[3]; - if (!PyArg_ParseTuple(args, "fff", &vecArg[0], &vecArg[1], &vecArg[2])) - return NULL; - - m_angular_velocity.setValue(vecArg); - Py_RETURN_NONE; -} - void KX_SCA_AddObjectActuator::InstantAddObject() { if (m_OriginalObject) @@ -377,51 +251,36 @@ void KX_SCA_AddObjectActuator::InstantAddObject() // Now it needs to be added to the current scene. SCA_IObject* replica = m_scene->AddReplicaObject(m_OriginalObject,GetParent(),m_timeProp ); KX_GameObject * game_obj = static_cast<KX_GameObject *>(replica); - game_obj->setLinearVelocity(m_linear_velocity,m_localLinvFlag); + game_obj->setLinearVelocity(m_linear_velocity ,m_localLinvFlag); game_obj->setAngularVelocity(m_angular_velocity,m_localAngvFlag); game_obj->ResolveCombinedVelocities(m_linear_velocity, m_angular_velocity, m_localLinvFlag, m_localAngvFlag); // keep a copy of the last object, to allow python scripters to change it if (m_lastCreatedObject) { - //careful with destruction, it might still have outstanding collision callbacks - m_scene->DelayedReleaseObject(m_lastCreatedObject); - m_lastCreatedObject->Release(); + //Let's not keep a reference to the object: it's bad, if the object is deleted + //this will force to keep a "zombie" in the game for no good reason. + //m_scene->DelayedReleaseObject(m_lastCreatedObject); + //m_lastCreatedObject->Release(); + + //Instead we use the registration mechanism + m_lastCreatedObject->UnregisterActuator(this); + m_lastCreatedObject = NULL; } m_lastCreatedObject = replica; - m_lastCreatedObject->AddRef(); + // no reference + //m_lastCreatedObject->AddRef(); + // but registration + m_lastCreatedObject->RegisterActuator(this); // finished using replica? then release it replica->Release(); } } -PyObject* KX_SCA_AddObjectActuator::PyInstantAddObject(PyObject* self) +PyObject* KX_SCA_AddObjectActuator::PyInstantAddObject() { InstantAddObject(); Py_RETURN_NONE; } - - - -/* 7. GetLastCreatedObject */ -const char KX_SCA_AddObjectActuator::GetLastCreatedObject_doc[] = -"getLastCreatedObject()\n" -"\tReturn the last created object. \n"; - - -PyObject* KX_SCA_AddObjectActuator::PyGetLastCreatedObject(PyObject* self) -{ - SCA_IObject* result = this->GetLastCreatedObject(); - - // if result->GetSGNode() is NULL - // it means the object has ended, The BGE python api crashes in many places if the object is returned. - if (result && (static_cast<KX_GameObject *>(result))->GetSGNode()) - { - result->AddRef(); - return result; - } - // don't return NULL to python anymore, it gives trouble in the scripts - Py_RETURN_NONE; -} diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h index 278d4180284..7137ba5209e 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h @@ -59,14 +59,17 @@ class KX_SCA_AddObjectActuator : public SCA_IActuator SCA_IScene* m_scene; /// Linear velocity upon creation of the object. - MT_Vector3 m_linear_velocity; + float m_linear_velocity[3]; + /// Apply the velocity locally + bool m_localLinvFlag; /// Angular velocity upon creation of the object. - MT_Vector3 m_angular_velocity; - + float m_angular_velocity[3]; /// Apply the velocity locally - bool m_localLinvFlag; - bool m_localAngvFlag; + bool m_localAngvFlag; + + + SCA_IObject* m_lastCreatedObject; @@ -82,11 +85,10 @@ public: SCA_IObject *original, int time, SCA_IScene* scene, - const MT_Vector3& linvel, + const float *linvel, bool linv_local, - const MT_Vector3& angvel, - bool angv_local, - PyTypeObject* T=&Type + const float *angvel, + bool angv_local ); ~KX_SCA_AddObjectActuator(void); @@ -107,38 +109,17 @@ public: virtual bool Update(); - virtual PyObject* - _getattr( - const STR_String& attr - ); - SCA_IObject* GetLastCreatedObject( ) const ; void InstantAddObject(); - /* 1. setObject */ - KX_PYMETHOD_DOC_O(KX_SCA_AddObjectActuator,SetObject); - /* 2. setTime */ - KX_PYMETHOD_DOC_O(KX_SCA_AddObjectActuator,SetTime); - /* 3. getTime */ - KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetTime); - /* 4. getObject */ - KX_PYMETHOD_DOC_VARARGS(KX_SCA_AddObjectActuator,GetObject); - /* 5. getLinearVelocity */ - KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetLinearVelocity); - /* 6. setLinearVelocity */ - KX_PYMETHOD_DOC_VARARGS(KX_SCA_AddObjectActuator,SetLinearVelocity); - /* 7. getAngularVelocity */ - KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetAngularVelocity); - /* 8. setAngularVelocity */ - KX_PYMETHOD_DOC_VARARGS(KX_SCA_AddObjectActuator,SetAngularVelocity); - /* 9. getLastCreatedObject */ - KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetLastCreatedObject); - /* 10. instantAddObject*/ KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,InstantAddObject); + static PyObject* pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_objectLastCreated(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); }; /* end of class KX_SCA_AddObjectActuator : public KX_EditObjectActuator */ diff --git a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp index d44ab477749..646cfb7219f 100644 --- a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp @@ -47,85 +47,37 @@ /* Integration hooks ------------------------------------------------------- */ - PyTypeObject - -KX_SCA_DynamicActuator:: - -Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, +PyTypeObject KX_SCA_DynamicActuator::Type = { + PyVarObject_HEAD_INIT(NULL, 0) "KX_SCA_DynamicActuator", - sizeof(KX_SCA_DynamicActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, - __repr, - 0, 0, 0, 0, - 0 -}; - -PyParentObject KX_SCA_DynamicActuator::Parents[] = { - &KX_SCA_DynamicActuator::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; - PyMethodDef KX_SCA_DynamicActuator::Methods[] = { - KX_PYMETHODTABLE(KX_SCA_DynamicActuator, setOperation), - KX_PYMETHODTABLE(KX_SCA_DynamicActuator, getOperation), {NULL,NULL} //Sentinel }; - - -PyObject* KX_SCA_DynamicActuator::_getattr(const STR_String& attr) -{ - _getattr_up(SCA_IActuator); -} - - - -/* 1. setOperation */ -KX_PYMETHODDEF_DOC(KX_SCA_DynamicActuator, setOperation, -"setOperation(operation?)\n" -"\t - operation? : type of dynamic operation\n" -"\t 0 = restore dynamics\n" -"\t 1 = disable dynamics\n" -"\t 2 = enable rigid body\n" -"\t 3 = disable rigid body\n" -"Change the dynamic status of the parent object.\n") -{ - int dyn_operation; - - if (!PyArg_ParseTuple(args, "i", &dyn_operation)) - { - return NULL; - } - if (dyn_operation <0 || dyn_operation>3) { - PyErr_SetString(PyExc_IndexError, "Dynamic Actuator's setOperation() range must be between 0 and 3"); - return NULL; - } - m_dyn_operation= dyn_operation; - Py_Return; -} - -KX_PYMETHODDEF_DOC(KX_SCA_DynamicActuator, getOperation, -"getOperation() -> integer\n" -"Returns the operation type of this actuator.\n" -) -{ - return PyInt_FromLong((long)m_dyn_operation); -} - +PyAttributeDef KX_SCA_DynamicActuator::Attributes[] = { + KX_PYATTRIBUTE_SHORT_RW("mode",0,4,false,KX_SCA_DynamicActuator,m_dyn_operation), + KX_PYATTRIBUTE_FLOAT_RW("mass",0.0,FLT_MAX,KX_SCA_DynamicActuator,m_setmass), + { NULL } //Sentinel +}; /* ------------------------------------------------------------------------- */ /* Native functions */ @@ -133,10 +85,11 @@ KX_PYMETHODDEF_DOC(KX_SCA_DynamicActuator, getOperation, KX_SCA_DynamicActuator::KX_SCA_DynamicActuator(SCA_IObject *gameobj, short dyn_operation, - PyTypeObject* T) : + float setmass) : - SCA_IActuator(gameobj, T), - m_dyn_operation(dyn_operation) + SCA_IActuator(gameobj), + m_dyn_operation(dyn_operation), + m_setmass(setmass) { } /* End of constructor */ @@ -179,6 +132,9 @@ bool KX_SCA_DynamicActuator::Update() case 3: controller->setRigidBody(false); break; + case 4: + controller->SetMass(m_setmass); + break; } return false; @@ -195,10 +151,6 @@ CValue* KX_SCA_DynamicActuator::GetReplica() return NULL; replica->ProcessReplica(); - - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - return replica; }; diff --git a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h index b47c3a511d9..58b28654eca 100644 --- a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h @@ -45,11 +45,12 @@ class KX_SCA_DynamicActuator : public SCA_IActuator // dynamics operation to apply to the game object short m_dyn_operation; + float m_setmass; public: KX_SCA_DynamicActuator( SCA_IObject* gameobj, short dyn_operation, - PyTypeObject* T=&Type + float setmass ); ~KX_SCA_DynamicActuator( @@ -62,15 +63,14 @@ class KX_SCA_DynamicActuator : public SCA_IActuator virtual bool Update(); - virtual PyObject* - _getattr( - const STR_String& attr - ); - - /* 1. setOperation */ - KX_PYMETHOD_DOC(KX_SCA_DynamicActuator,setOperation); - KX_PYMETHOD_DOC(KX_SCA_DynamicActuator,getOperation); - + //Python Interface + enum DynamicOperation { + KX_DYN_RESTORE_DYNAMICS = 0, + KX_DYN_DISABLE_DYNAMICS, + KX_DYN_ENABLE_RIGID_BODY, + KX_DYN_DISABLE_RIGID_BODY, + KX_DYN_SET_MASS, + }; }; #endif diff --git a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp index ec29448907f..dd9d8015724 100644 --- a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp @@ -43,9 +43,8 @@ #endif KX_SCA_EndObjectActuator::KX_SCA_EndObjectActuator(SCA_IObject *gameobj, - SCA_IScene* scene, - PyTypeObject* T): - SCA_IActuator(gameobj, T), + SCA_IScene* scene): + SCA_IActuator(gameobj), m_scene(scene) { // intentionally empty @@ -82,8 +81,6 @@ CValue* KX_SCA_EndObjectActuator::GetReplica() if (replica == NULL) return NULL; replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; }; @@ -94,43 +91,33 @@ CValue* KX_SCA_EndObjectActuator::GetReplica() /* ------------------------------------------------------------------------- */ PyTypeObject KX_SCA_EndObjectActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_SCA_EndObjectActuator", - sizeof(KX_SCA_EndObjectActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - - -PyParentObject KX_SCA_EndObjectActuator::Parents[] = { - &KX_SCA_EndObjectActuator::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; - - PyMethodDef KX_SCA_EndObjectActuator::Methods[] = { {NULL,NULL} //Sentinel }; - -PyObject* KX_SCA_EndObjectActuator::_getattr(const STR_String& attr) -{ - _getattr_up(SCA_IActuator); -} +PyAttributeDef KX_SCA_EndObjectActuator::Attributes[] = { + { NULL } //Sentinel +}; /* eof */ diff --git a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h index add9c05b000..782a24b1ef1 100644 --- a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h @@ -47,8 +47,7 @@ class KX_SCA_EndObjectActuator : public SCA_IActuator public: KX_SCA_EndObjectActuator( SCA_IObject* gameobj, - SCA_IScene* scene, - PyTypeObject* T=&Type + SCA_IScene* scene ); ~KX_SCA_EndObjectActuator(); @@ -63,11 +62,6 @@ class KX_SCA_EndObjectActuator : public SCA_IActuator /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - virtual PyObject* - _getattr( - const STR_String& attr - ); }; /* end of class KX_EditObjectActuator : public SCA_PropertyActuator */ diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp index 261d9ec8f0c..e85b8a32798 100644 --- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp @@ -36,6 +36,7 @@ // Please look here for revision history. #include "KX_SCA_ReplaceMeshActuator.h" +#include "KX_MeshProxy.h" #include "PyObjectPlus.h" @@ -49,95 +50,61 @@ /* Integration hooks ------------------------------------------------------- */ - PyTypeObject - -KX_SCA_ReplaceMeshActuator:: - -Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, +PyTypeObject KX_SCA_ReplaceMeshActuator::Type = { + PyVarObject_HEAD_INIT(NULL, 0) "KX_SCA_ReplaceMeshActuator", - sizeof(KX_SCA_ReplaceMeshActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, - __repr, - 0, 0, 0, 0, - 0 -}; - -PyParentObject KX_SCA_ReplaceMeshActuator::Parents[] = { + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; - - PyMethodDef KX_SCA_ReplaceMeshActuator::Methods[] = { - {"setMesh", (PyCFunction) KX_SCA_ReplaceMeshActuator::sPySetMesh, METH_O, (PY_METHODCHAR)SetMesh_doc}, - KX_PYMETHODTABLE(KX_SCA_ReplaceMeshActuator, instantReplaceMesh), - KX_PYMETHODTABLE(KX_SCA_ReplaceMeshActuator, getMesh), {NULL,NULL} //Sentinel }; +PyAttributeDef KX_SCA_ReplaceMeshActuator::Attributes[] = { + KX_PYATTRIBUTE_RW_FUNCTION("mesh", KX_SCA_ReplaceMeshActuator, pyattr_get_mesh, pyattr_set_mesh), + KX_PYATTRIBUTE_BOOL_RW ("useDisplayMesh", KX_SCA_ReplaceMeshActuator, m_use_gfx), + KX_PYATTRIBUTE_BOOL_RW ("usePhysicsMesh", KX_SCA_ReplaceMeshActuator, m_use_phys), + { NULL } //Sentinel +}; - -PyObject* KX_SCA_ReplaceMeshActuator::_getattr(const STR_String& attr) +PyObject* KX_SCA_ReplaceMeshActuator::pyattr_get_mesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) { - _getattr_up(SCA_IActuator); + KX_SCA_ReplaceMeshActuator* actuator = static_cast<KX_SCA_ReplaceMeshActuator*>(self); + if (!actuator->m_mesh) + Py_RETURN_NONE; + KX_MeshProxy* meshproxy = new KX_MeshProxy(actuator->m_mesh); + return meshproxy->NewProxy(true); } - - -/* 1. setMesh */ -const char KX_SCA_ReplaceMeshActuator::SetMesh_doc[] = - "setMesh(name)\n" - "\t- name: string or None\n" - "\tSet the mesh that will be substituted for the current one.\n"; - -PyObject* KX_SCA_ReplaceMeshActuator::PySetMesh(PyObject* self, PyObject* value) +int KX_SCA_ReplaceMeshActuator::pyattr_set_mesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - if (value == Py_None) { - m_mesh = NULL; - } else { - char* meshname = PyString_AsString(value); - if (!meshname) { - PyErr_SetString(PyExc_ValueError, "Expected the name of a mesh or None"); - return NULL; - } - void* mesh = SCA_ILogicBrick::m_sCurrentLogicManager->GetMeshByName(STR_String(meshname)); - - if (mesh==NULL) { - PyErr_SetString(PyExc_ValueError, "The mesh name given does not exist"); - return NULL; - } - m_mesh= (class RAS_MeshObject*)mesh; - } + KX_SCA_ReplaceMeshActuator* actuator = static_cast<KX_SCA_ReplaceMeshActuator*>(self); + RAS_MeshObject* new_mesh; - Py_RETURN_NONE; -} - -KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, getMesh, -"getMesh() -> string\n" -"Returns the name of the mesh to be substituted.\n" -) -{ - if (!m_mesh) - Py_RETURN_NONE; - - return PyString_FromString(const_cast<char *>(m_mesh->GetName().ReadPtr())); + if (!ConvertPythonToMesh(value, &new_mesh, true, "actuator.mesh = value: KX_SCA_ReplaceMeshActuator")) + return PY_SET_ATTR_FAIL; + + actuator->m_mesh = new_mesh; + return PY_SET_ATTR_SUCCESS; } - KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, instantReplaceMesh, "instantReplaceMesh() : immediately replace mesh without delay\n") { @@ -152,11 +119,14 @@ KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, instantReplaceMesh, KX_SCA_ReplaceMeshActuator::KX_SCA_ReplaceMeshActuator(SCA_IObject *gameobj, class RAS_MeshObject *mesh, SCA_IScene* scene, - PyTypeObject* T) : + bool use_gfx, + bool use_phys) : - SCA_IActuator(gameobj, T), + SCA_IActuator(gameobj), m_mesh(mesh), - m_scene(scene) + m_scene(scene), + m_use_gfx(use_gfx), + m_use_phys(use_phys) { } /* End of constructor */ @@ -178,7 +148,8 @@ bool KX_SCA_ReplaceMeshActuator::Update() if (bNegativeEvent) return false; // do nothing on negative events - if (m_mesh) m_scene->ReplaceMesh(GetParent(),m_mesh); + if (m_mesh || m_use_phys) /* NULL mesh is ok if were updating physics */ + m_scene->ReplaceMesh(GetParent(),m_mesh, m_use_gfx, m_use_phys); return false; } @@ -195,15 +166,12 @@ CValue* KX_SCA_ReplaceMeshActuator::GetReplica() replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - return replica; }; void KX_SCA_ReplaceMeshActuator::InstantReplaceMesh() { - if (m_mesh) m_scene->ReplaceMesh(GetParent(),m_mesh); + if (m_mesh) m_scene->ReplaceMesh(GetParent(),m_mesh, m_use_gfx, m_use_phys); } /* eof */ diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h index 1da154cc222..e5482c29aa7 100644 --- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h @@ -50,13 +50,16 @@ class KX_SCA_ReplaceMeshActuator : public SCA_IActuator // mesh reference (mesh to replace) RAS_MeshObject* m_mesh; SCA_IScene* m_scene; + bool m_use_gfx; + bool m_use_phys; public: KX_SCA_ReplaceMeshActuator( SCA_IObject* gameobj, RAS_MeshObject *mesh, SCA_IScene* scene, - PyTypeObject* T=&Type + bool use_gfx, + bool use_phys ); ~KX_SCA_ReplaceMeshActuator( @@ -69,15 +72,15 @@ class KX_SCA_ReplaceMeshActuator : public SCA_IActuator virtual bool Update(); - virtual PyObject* - _getattr( - const STR_String& attr - ); void InstantReplaceMesh(); - /* 1. setMesh */ - KX_PYMETHOD_DOC_O(KX_SCA_ReplaceMeshActuator,SetMesh); - KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,getMesh); + /* --------------------------------------------------------------------- */ + /* Python interface ---------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + + static PyObject* pyattr_get_mesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_mesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,instantReplaceMesh); }; diff --git a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp index d651373869a..cb933419c57 100644 --- a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp +++ b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp @@ -57,7 +57,8 @@ New(Bone* bone KX_BoneParentRelation:: UpdateChildCoordinates( SG_Spatial * child, - const SG_Spatial * parent + const SG_Spatial * parent, + bool& parentUpdated ){ MT_assert(child != NULL); @@ -67,6 +68,8 @@ UpdateChildCoordinates( const MT_Vector3 & child_scale = child->GetLocalScale(); const MT_Point3 & child_pos = child->GetLocalPosition(); const MT_Matrix3x3 & child_rotation = child->GetLocalOrientation(); + // we don't know if the armature has been updated or not, assume yes + parentUpdated = true; // the childs world locations which we will update. @@ -97,11 +100,11 @@ UpdateChildCoordinates( child_transform = parent_matrix * child_transform; // Recompute the child transform components from the transform. - child_w_scale = MT_Vector3( + child_w_scale.setValue( MT_Vector3(child_transform[0][0], child_transform[0][1], child_transform[0][2]).length(), MT_Vector3(child_transform[1][0], child_transform[1][1], child_transform[1][2]).length(), MT_Vector3(child_transform[2][0], child_transform[2][1], child_transform[2][2]).length()); - child_w_rotation = MT_Matrix3x3(child_transform[0][0], child_transform[0][1], child_transform[0][2], + child_w_rotation.setValue(child_transform[0][0], child_transform[0][1], child_transform[0][2], child_transform[1][0], child_transform[1][1], child_transform[1][2], child_transform[2][0], child_transform[2][1], child_transform[2][2]); child_w_rotation.scale(1.0/child_w_scale[0], 1.0/child_w_scale[1], 1.0/child_w_scale[2]); @@ -113,17 +116,18 @@ UpdateChildCoordinates( } } - if (!valid_parent_transform) + if (valid_parent_transform) { - child_w_scale = child_scale; - child_w_pos = child_pos; - child_w_rotation = child_rotation; + child->SetWorldScale(child_w_scale); + child->SetWorldPosition(child_w_pos); + child->SetWorldOrientation(child_w_rotation); } - - child->SetWorldScale(child_w_scale); - child->SetWorldPosition(child_w_pos); - child->SetWorldOrientation(child_w_rotation); - + else { + child->SetWorldFromLocalTransform(); + } + child->ClearModified(); + // this node must always be updated, so reschedule it for next time + child->ActivateRecheduleUpdateCallback(); return valid_parent_transform; } diff --git a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h index 2a19d8a1784..dd4419543a2 100644 --- a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h +++ b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h @@ -59,7 +59,6 @@ class KX_BoneParentRelation : public SG_ParentRelation { public : - /** * Allocate and construct a new KX_SG_BoneParentRelation * on the heap. @@ -82,7 +81,8 @@ public : bool UpdateChildCoordinates( SG_Spatial * child, - const SG_Spatial * parent + const SG_Spatial * parent, + bool& parentUpdated ); /** @@ -100,6 +100,12 @@ private : KX_BoneParentRelation(Bone* bone ); + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_BoneParentRelation"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp b/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp index 0c8e7e28771..c49b6d671a7 100644 --- a/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp +++ b/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp @@ -51,47 +51,33 @@ New( KX_NormalParentRelation:: UpdateChildCoordinates( SG_Spatial * child, - const SG_Spatial * parent + const SG_Spatial * parent, + bool& parentUpdated ){ MT_assert(child != NULL); - // This way of accessing child coordinates is a bit cumbersome - // be nice to have non constant reference access to these values. + if (!parentUpdated && !child->IsModified()) + return false; - const MT_Vector3 & child_scale = child->GetLocalScale(); - const MT_Point3 & child_pos = child->GetLocalPosition(); - const MT_Matrix3x3 & child_rotation = child->GetLocalOrientation(); - - // the childs world locations which we will update. - - MT_Vector3 child_w_scale; - MT_Point3 child_w_pos; - MT_Matrix3x3 child_w_rotation; - - if (parent) { + parentUpdated = true; + if (parent==NULL) { /* Simple case */ + child->SetWorldFromLocalTransform(); + child->ClearModified(); + return true; //false; + } + else { + // the childs world locations which we will update. const MT_Vector3 & p_world_scale = parent->GetWorldScaling(); const MT_Point3 & p_world_pos = parent->GetWorldPosition(); const MT_Matrix3x3 & p_world_rotation = parent->GetWorldOrientation(); - child_w_scale = p_world_scale * child_scale; - child_w_rotation = p_world_rotation * child_rotation; - - child_w_pos = p_world_pos + p_world_scale * - (p_world_rotation * child_pos); - - } else { - - child_w_scale = child_scale; - child_w_pos = child_pos; - child_w_rotation = child_rotation; + child->SetWorldScale(p_world_scale * child->GetLocalScale()); + child->SetWorldOrientation(p_world_rotation * child->GetLocalOrientation()); + child->SetWorldPosition(p_world_pos + p_world_scale * (p_world_rotation * child->GetLocalPosition())); + child->ClearModified(); + return true; } - - child->SetWorldScale(child_w_scale); - child->SetWorldPosition(child_w_pos); - child->SetWorldOrientation(child_w_rotation); - - return parent != NULL; } SG_ParentRelation * @@ -134,45 +120,25 @@ New( KX_VertexParentRelation:: UpdateChildCoordinates( SG_Spatial * child, - const SG_Spatial * parent + const SG_Spatial * parent, + bool& parentUpdated ){ MT_assert(child != NULL); - const MT_Vector3 & child_scale = child->GetLocalScale(); - const MT_Point3 & child_pos = child->GetLocalPosition(); - const MT_Matrix3x3 & child_rotation = child->GetLocalOrientation(); + if (!parentUpdated && !child->IsModified()) + return false; - // the childs world locations which we will update. + child->SetWorldScale(child->GetLocalScale()); - MT_Vector3 child_w_scale; - MT_Point3 child_w_pos; - MT_Matrix3x3 child_w_rotation; - - if (parent) { - - // This is a vertex parent so we do not inherit orientation - // information. - - // const MT_Vector3 & p_world_scale = parent->GetWorldScaling(); /*unused*/ - const MT_Point3 & p_world_pos = parent->GetWorldPosition(); - // const MT_Matrix3x3 & p_world_rotation = parent->GetWorldOrientation(); /*unused*/ - - child_w_scale = child_scale; - child_w_rotation = child_rotation; - child_w_pos = p_world_pos + child_pos; - } else { - - child_w_scale = child_scale; - child_w_pos = child_pos; - child_w_rotation = child_rotation; - } - - child->SetWorldScale(child_w_scale); - child->SetWorldPosition(child_w_pos); - child->SetWorldOrientation(child_w_rotation); + if (parent) + child->SetWorldPosition(child->GetLocalPosition()+parent->GetWorldPosition()); + else + child->SetWorldPosition(child->GetLocalPosition()); - return parent != NULL; + child->SetWorldOrientation(child->GetLocalOrientation()); + child->ClearModified(); + return true; //parent != NULL; } /** @@ -220,10 +186,14 @@ New( KX_SlowParentRelation:: UpdateChildCoordinates( SG_Spatial * child, - const SG_Spatial * parent + const SG_Spatial * parent, + bool& parentUpdated ){ MT_assert(child != NULL); + // the child will move even if the parent is not + parentUpdated = true; + const MT_Vector3 & child_scale = child->GetLocalScale(); const MT_Point3 & child_pos = child->GetLocalPosition(); const MT_Matrix3x3 & child_rotation = child->GetLocalOrientation(); @@ -265,23 +235,12 @@ UpdateChildCoordinates( // now 'interpolate' the normal coordinates with the last // world coordinates to get the new world coordinates. - // problem 1: - // The child world scale needs to be initialized in some way for this - // to make sense - // problem 2: - // This is way of doing interpolation is nonsense - - int i; - MT_Scalar weight = MT_Scalar(1)/(m_relax + 1); - for (i=0;i <3 ;i++) { - child_w_scale[i] = (m_relax * child_w_scale[i] + child_n_scale[i]) * weight; - child_w_pos[i] = (m_relax * child_w_pos[i] + child_n_pos[i]) * weight; - child_w_rotation[0][i] = (m_relax * child_w_rotation[0][i] + child_n_rotation[0][i]) * weight; - child_w_rotation[1][i] = (m_relax * child_w_rotation[1][i] + child_n_rotation[1][i]) * weight; - child_w_rotation[2][i] = (m_relax * child_w_rotation[2][i] + child_n_rotation[2][i]) * weight; - } - + child_w_scale = (m_relax * child_w_scale + child_n_scale) * weight; + child_w_pos = (m_relax * child_w_pos + child_n_pos) * weight; + // for rotation we must go through quaternion + MT_Quaternion child_w_quat = child_w_rotation.getRotation().slerp(child_n_rotation.getRotation(), weight); + child_w_rotation.setRotation(child_w_quat); //FIXME: update physics controller. } else { child_w_scale = child_n_scale; @@ -300,8 +259,11 @@ UpdateChildCoordinates( child->SetWorldScale(child_w_scale); child->SetWorldPosition(child_w_pos); child->SetWorldOrientation(child_w_rotation); + child->ClearModified(); + // this node must always be updated, so reschedule it for next time + child->ActivateRecheduleUpdateCallback(); - return parent != NULL; + return true; //parent != NULL; } /** diff --git a/source/gameengine/Ketsji/KX_SG_NodeRelationships.h b/source/gameengine/Ketsji/KX_SG_NodeRelationships.h index faa650106c8..c1640f3e0a0 100644 --- a/source/gameengine/Ketsji/KX_SG_NodeRelationships.h +++ b/source/gameengine/Ketsji/KX_SG_NodeRelationships.h @@ -53,7 +53,6 @@ class KX_NormalParentRelation : public SG_ParentRelation { public : - /** * Allocate and construct a new KX_NormalParentRelation * on the heap. @@ -71,7 +70,8 @@ public : bool UpdateChildCoordinates( SG_Spatial * child, - const SG_Spatial * parent + const SG_Spatial * parent, + bool& parentUpdated ); /** @@ -90,6 +90,12 @@ private : KX_NormalParentRelation( ); + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_NormalParentRelation"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; @@ -115,7 +121,8 @@ public : bool UpdateChildCoordinates( SG_Spatial * child, - const SG_Spatial * parent + const SG_Spatial * parent, + bool& parentUpdated ); /** @@ -140,6 +147,12 @@ private : KX_VertexParentRelation( ); + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_VertexParentRelation"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; @@ -166,7 +179,8 @@ public : bool UpdateChildCoordinates( SG_Spatial * child, - const SG_Spatial * parent + const SG_Spatial * parent, + bool& parentUpdated ); /** @@ -216,6 +230,12 @@ private : bool m_initialized; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_SlowParentRelation"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Ketsji/KX_ScalarInterpolator.h b/source/gameengine/Ketsji/KX_ScalarInterpolator.h index 8835c98c184..ca011ab5db0 100644 --- a/source/gameengine/Ketsji/KX_ScalarInterpolator.h +++ b/source/gameengine/Ketsji/KX_ScalarInterpolator.h @@ -55,6 +55,13 @@ public: private: MT_Scalar* m_target; KX_IScalarInterpolator *m_ipo; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_ScalarInterpolator"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Ketsji/KX_ScalingInterpolator.h b/source/gameengine/Ketsji/KX_ScalingInterpolator.h index a7b5d7e559a..460563d4135 100644 --- a/source/gameengine/Ketsji/KX_ScalingInterpolator.h +++ b/source/gameengine/Ketsji/KX_ScalingInterpolator.h @@ -50,6 +50,13 @@ public: private: MT_Vector3& m_target; KX_IScalarInterpolator *m_ipos[3]; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_ScalingInterpolator"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index caa71441b1d..3483496c3a6 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -32,10 +32,8 @@ #pragma warning (disable : 4786) #endif //WIN32 - #include "KX_Scene.h" #include "MT_assert.h" - #include "KX_KetsjiEngine.h" #include "KX_BlenderMaterial.h" #include "RAS_IPolygonMaterial.h" @@ -77,8 +75,11 @@ #include "NG_NetworkScene.h" #include "PHY_IPhysicsEnvironment.h" #include "KX_IPhysicsController.h" +#include "PHY_IGraphicController.h" #include "KX_BlenderSceneConverter.h" +#include "KX_MotionState.h" +#include "BL_ModifierDeformer.h" #include "BL_ShapeDeformer.h" #include "BL_DeformableGameObject.h" @@ -90,6 +91,8 @@ #include "CcdPhysicsController.h" #endif +#include "KX_Light.h" + void* KX_SceneReplicationFunc(SG_IObject* node,void* gameobj,void* scene) { KX_GameObject* replica = ((KX_Scene*)scene)->AddNodeReplicaObject(node,(KX_GameObject*)gameobj); @@ -107,7 +110,22 @@ void* KX_SceneDestructionFunc(SG_IObject* node,void* gameobj,void* scene) return NULL; }; -SG_Callbacks KX_Scene::m_callbacks = SG_Callbacks(KX_SceneReplicationFunc,KX_SceneDestructionFunc,KX_GameObject::UpdateTransformFunc); +bool KX_Scene::KX_ScenegraphUpdateFunc(SG_IObject* node,void* gameobj,void* scene) +{ + return ((SG_Node*)node)->Schedule(((KX_Scene*)scene)->m_sghead); +} + +bool KX_Scene::KX_ScenegraphRescheduleFunc(SG_IObject* node,void* gameobj,void* scene) +{ + return ((SG_Node*)node)->Reschedule(((KX_Scene*)scene)->m_sghead); +} + +SG_Callbacks KX_Scene::m_callbacks = SG_Callbacks( + KX_SceneReplicationFunc, + KX_SceneDestructionFunc, + KX_GameObject::UpdateTransformFunc, + KX_Scene::KX_ScenegraphUpdateFunc, + KX_Scene::KX_ScenegraphRescheduleFunc); // temporarily var until there is a button in the userinterface // (defined in KX_PythonInit.cpp) @@ -116,16 +134,14 @@ extern bool gUseVisibilityTemp; KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, class SCA_IInputDevice* mousedevice, class NG_NetworkDeviceInterface *ndi, - class SND_IAudioDevice* adi, const STR_String& sceneName, Scene *scene): - PyObjectPlus(&KX_Scene::Type), + PyObjectPlus(), m_keyboardmgr(NULL), m_mousemgr(NULL), m_sceneConverter(NULL), m_physicsEnvironment(0), m_sceneName(sceneName), - m_adi(adi), m_networkDeviceInterface(ndi), m_active_camera(NULL), m_ueberExecutionPriority(0), @@ -134,6 +150,8 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_suspendedtime = 0.0; m_suspendeddelta = 0.0; + m_dbvt_culling = false; + m_dbvt_occlusion_res = 0; m_activity_culling = false; m_suspend = false; m_isclearingZbuffer = true; @@ -143,7 +161,6 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_lightlist= new CListValue(); m_inactivelist = new CListValue(); m_euthanasyobjects = new CListValue(); - m_delayReleaseObjects = new CListValue(); m_logicmgr = new SCA_LogicManager(); @@ -180,18 +197,14 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_logicmgr->RegisterEventManager(joymgr); } - m_soundScene = new SND_Scene(adi); MT_assert (m_networkDeviceInterface != NULL); m_networkScene = new NG_NetworkScene(m_networkDeviceInterface); m_rootnode = NULL; m_bucketmanager=new RAS_BucketManager(); - - m_canvasDesignWidth = 0; - m_canvasDesignHeight = 0; - m_attrlist = PyDict_New(); /* new ref */ + m_attr_dict = PyDict_New(); /* new ref */ } @@ -226,8 +239,6 @@ KX_Scene::~KX_Scene() if (m_euthanasyobjects) m_euthanasyobjects->Release(); - if (m_delayReleaseObjects) - m_delayReleaseObjects->Release(); if (m_logicmgr) delete m_logicmgr; @@ -235,9 +246,6 @@ KX_Scene::~KX_Scene() if (m_physicsEnvironment) delete m_physicsEnvironment; - if (m_soundScene) - delete m_soundScene; - if (m_networkScene) delete m_networkScene; @@ -245,16 +253,10 @@ KX_Scene::~KX_Scene() { delete m_bucketmanager; } - //Py_DECREF(m_attrlist); -} - -void KX_Scene::SetProjectionMatrix(MT_CmMatrix4x4& pmat) -{ - m_projectionmat = pmat; + PyDict_Clear(m_attr_dict); + Py_DECREF(m_attr_dict); } - - RAS_BucketManager* KX_Scene::GetBucketManager() { return m_bucketmanager; @@ -355,12 +357,6 @@ class KX_WorldInfo* KX_Scene::GetWorldInfo() } - -SND_Scene* KX_Scene::GetSoundScene() -{ - return m_soundScene; -} - const STR_String& KX_Scene::GetName() { return m_sceneName; @@ -402,12 +398,19 @@ void KX_Scene::RemoveNodeDestructObject(class SG_IObject* node,class CValue* gam KX_GameObject* orgobj = (KX_GameObject*)gameobj; if (NewRemoveObject(orgobj) != 0) { - // object is not yet deleted (this can happen when it hangs in an add object actuator - // last object created reference. It's a bad situation, don't know how to fix it exactly - // The least I can do, is remove the reference to the node in the object as the node - // will in any case be deleted. This ensures that the object will not try to use the node - // when it is finally deleted (see KX_GameObject destructor) + // object is not yet deleted because a reference is hanging somewhere. + // This should not happen anymore since we use proxy object for Python + // confident enough to put an assert? + //assert(false); + printf("Zombie object! name=%s\n", orgobj->GetName().ReadPtr()); orgobj->SetSGNode(NULL); + PHY_IGraphicController* ctrl = orgobj->GetGraphicController(); + if (ctrl) + { + // a graphic controller is set, we must delete it as the node will be deleted + delete ctrl; + orgobj->SetGraphicController(NULL); + } } if (node) delete node; @@ -464,6 +467,8 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal // this is the list of object that are send to the graphics pipeline m_objectlist->Add(newobj->AddRef()); + if (newobj->IsLight()) + m_lightlist->Add(newobj->AddRef()); newobj->AddMeshUser(); // logic cannot be replicated, until the whole hierarchy is replicated. @@ -486,7 +491,14 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal replicanode->AddSGController(replicacontroller); } } - + // replicate graphic controller + if (orgobj->GetGraphicController()) + { + PHY_IMotionState* motionstate = new KX_MotionState(newobj->GetSGNode()); + PHY_IGraphicController* newctrl = orgobj->GetGraphicController()->GetReplica(motionstate); + newctrl->setNewClientInfo(newobj->getClientInfo()); + newobj->SetGraphicController(newctrl); + } return newobj; } @@ -517,8 +529,9 @@ void KX_Scene::ReplicateLogic(KX_GameObject* newobj) vector<SCA_IActuator*> linkedactuators = cont->GetLinkedActuators(); // disconnect the sensors and actuators - cont->UnlinkAllSensors(); - cont->UnlinkAllActuators(); + // do it directly on the list at this controller is not connected to anything at this stage + cont->GetLinkedSensors().clear(); + cont->GetLinkedActuators().clear(); // now relink each sensor for (vector<SCA_ISensor*>::iterator its = linkedsensors.begin();!(its==linkedsensors.end());its++) @@ -696,16 +709,20 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) // set the replica's relative scale with the rootnode's scale replica->NodeSetRelativeScale(newscale); - MT_Matrix3x3 newori = groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldOrientation(); - replica->NodeSetLocalOrientation(newori); - + MT_Point3 offset(group->dupli_ofs); MT_Point3 newpos = groupobj->NodeGetWorldPosition() + - newscale*(groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldPosition()); + newscale*(groupobj->NodeGetWorldOrientation() * (gameobj->NodeGetWorldPosition()-offset)); replica->NodeSetLocalPosition(newpos); - + // set the orientation after position for softbody! + MT_Matrix3x3 newori = groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldOrientation(); + replica->NodeSetLocalOrientation(newori); + // update scenegraph for entire tree of children replica->GetSGNode()->UpdateWorldData(0); replica->GetSGNode()->SetBBox(gameobj->GetSGNode()->BBox()); replica->GetSGNode()->SetRadius(gameobj->GetSGNode()->Radius()); + // we can now add the graphic controller to the physic engine + replica->ActivateGraphicController(true); + // done with replica replica->Release(); } @@ -725,6 +742,12 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) (*git)->Relink(&m_map_gameobject_to_replica); // add the object in the layer of the parent (*git)->SetLayer(groupobj->GetLayer()); + // If the object was a light, we need to update it's RAS_LightObject as well + if ((*git)->IsLight()) + { + KX_LightObject* lightobj = static_cast<KX_LightObject*>(*git); + lightobj->GetLightData()->m_layer = groupobj->GetLayer(); + } } // replicate crosslinks etc. between logic bricks @@ -793,6 +816,26 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, replica->GetSGNode()->AddChild(childreplicanode); } + // At this stage all the objects in the hierarchy have been duplicated, + // we can update the scenegraph, we need it for the duplication of logic + MT_Point3 newpos = ((KX_GameObject*) parentobject)->NodeGetWorldPosition(); + replica->NodeSetLocalPosition(newpos); + + MT_Matrix3x3 newori = ((KX_GameObject*) parentobject)->NodeGetWorldOrientation(); + replica->NodeSetLocalOrientation(newori); + + // get the rootnode's scale + MT_Vector3 newscale = parentobj->GetSGNode()->GetRootSGParent()->GetLocalScale(); + + // set the replica's relative scale with the rootnode's scale + replica->NodeSetRelativeScale(newscale); + + replica->GetSGNode()->UpdateWorldData(0); + replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox()); + replica->GetSGNode()->SetRadius(originalobj->GetSGNode()->Radius()); + // the size is correct, we can add the graphic controller to the physic engine + replica->ActivateGraphicController(true); + // now replicate logic vector<KX_GameObject*>::iterator git; for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) @@ -807,6 +850,12 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, (*git)->Relink(&m_map_gameobject_to_replica); // add the object in the layer of the parent (*git)->SetLayer(parentobj->GetLayer()); + // If the object was a light, we need to update it's RAS_LightObject as well + if ((*git)->IsLight()) + { + KX_LightObject* lightobj = static_cast<KX_LightObject*>(*git); + lightobj->GetLightData()->m_layer = parentobj->GetLayer(); + } } // replicate crosslinks etc. between logic bricks @@ -815,21 +864,6 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, ReplicateLogic((*git)); } - MT_Point3 newpos = ((KX_GameObject*) parentobject)->NodeGetWorldPosition(); - replica->NodeSetLocalPosition(newpos); - - MT_Matrix3x3 newori = ((KX_GameObject*) parentobject)->NodeGetWorldOrientation(); - replica->NodeSetLocalOrientation(newori); - - // get the rootnode's scale - MT_Vector3 newscale = parentobj->GetSGNode()->GetRootSGParent()->GetLocalScale(); - - // set the replica's relative scale with the rootnode's scale - replica->NodeSetRelativeScale(newscale); - - replica->GetSGNode()->UpdateWorldData(0); - replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox()); - replica->GetSGNode()->SetRadius(originalobj->GetSGNode()->Radius()); // check if there are objects with dupligroup in the hierarchy vector<KX_GameObject*> duplilist; for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) @@ -854,7 +888,7 @@ void KX_Scene::RemoveObject(class CValue* gameobj) { KX_GameObject* newobj = (KX_GameObject*) gameobj; - // first disconnect child from parent + // disconnect child from parent SG_Node* node = newobj->GetSGNode(); if (node) @@ -868,12 +902,6 @@ void KX_Scene::RemoveObject(class CValue* gameobj) //newobj->SetSGNode(0); } -void KX_Scene::DelayedReleaseObject(CValue* gameobj) -{ - m_delayReleaseObjects->Add(gameobj->AddRef()); -} - - void KX_Scene::DelayedRemoveObject(class CValue* gameobj) { //KX_GameObject* newobj = (KX_GameObject*) gameobj; @@ -890,6 +918,13 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) int ret; KX_GameObject* newobj = (KX_GameObject*) gameobj; + /* Invalidate the python reference, since the object may exist in script lists + * its possible that it wont be automatically invalidated, so do it manually here, + * + * if for some reason the object is added back into the scene python can always get a new Proxy + */ + newobj->InvalidateProxy(); + // keep the blender->game object association up to date // note that all the replicas of an object will have the same // blender object, that's why we need to check the game object @@ -919,7 +954,7 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) for (SCA_ActuatorList::iterator ita = actuators.begin(); !(ita==actuators.end());ita++) { - m_logicmgr->RemoveDestroyedActuator(*ita); + m_logicmgr->RemoveActuator(*ita); } // the sensors/controllers/actuators must also be released, this is done in ~SCA_IObject @@ -937,7 +972,7 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) newobj->RemoveMeshes(); ret = 1; - if (m_lightlist->RemoveValue(newobj)) // TODO - use newobj->IsLight() test when its merged in from apricot. - Campbell + if (newobj->IsLight() && m_lightlist->RemoveValue(newobj)) ret = newobj->Release(); if (m_objectlist->RemoveValue(newobj)) ret = newobj->Release(); @@ -960,25 +995,31 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) // in case this is a camera m_cameras.remove((KX_Camera*)newobj); + /* currently does nothing, keep incase we need to Unregister something */ +#if 0 if (m_sceneConverter) m_sceneConverter->UnregisterGameObject(newobj); +#endif + // return value will be 0 if the object is actually deleted (all reference gone) + return ret; } -void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) +void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool use_phys) { KX_GameObject* gameobj = static_cast<KX_GameObject*>(obj); RAS_MeshObject* mesh = static_cast<RAS_MeshObject*>(meshobj); - if(!gameobj || !mesh) - { - std::cout << "warning: invalid object, mesh will not be replaced" << std::endl; + if(!gameobj) { + std::cout << "KX_Scene::ReplaceMesh Warning: invalid object, doing nothing" << std::endl; return; } + if(use_gfx && mesh != NULL) + { gameobj->RemoveMeshes(); gameobj->AddMesh(mesh); @@ -1002,6 +1043,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) Object* oldblendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(mesh->GetName())); Mesh* blendmesh = mesh->GetMesh(); + bool bHasModifier = BL_ModifierDeformer::HasCompatibleDeformer(blendobj); bool bHasShapeKey = blendmesh->key != NULL && blendmesh->key->type==KEY_RELATIVE; bool bHasDvert = blendmesh->dvert != NULL; bool bHasArmature = @@ -1014,7 +1056,42 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) blendmesh->dvert!=NULL; // mesh has vertex group bool releaseParent = true; - if (bHasShapeKey) + + if (oldblendobj==NULL) { + std::cout << "warning: ReplaceMesh() new mesh is not used in an object from the current scene, you will get incorrect behavior" << std::endl; + bHasShapeKey= bHasDvert= bHasArmature=bHasModifier= false; + } + + if (bHasModifier) + { + BL_ModifierDeformer* modifierDeformer; + if (bHasShapeKey || bHasArmature) + { + modifierDeformer = new BL_ModifierDeformer( + newobj, + m_blenderScene, + oldblendobj, blendobj, + static_cast<BL_SkinMeshObject*>(mesh), + true, + static_cast<BL_ArmatureObject*>( parentobj ) + ); + releaseParent= false; + modifierDeformer->LoadShapeDrivers(blendobj->parent); + } + else + { + modifierDeformer = new BL_ModifierDeformer( + newobj, + m_blenderScene, + oldblendobj, blendobj, + static_cast<BL_SkinMeshObject*>(mesh), + false, + NULL + ); + } + newobj->SetDeformer(modifierDeformer); + } + else if (bHasShapeKey) { BL_ShapeDeformer* shapeDeformer; if (bHasArmature) @@ -1024,6 +1101,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) oldblendobj, blendobj, static_cast<BL_SkinMeshObject*>(mesh), true, + true, static_cast<BL_ArmatureObject*>( parentobj ) ); releaseParent= false; @@ -1036,6 +1114,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) oldblendobj, blendobj, static_cast<BL_SkinMeshObject*>(mesh), false, + true, NULL ); } @@ -1048,6 +1127,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) oldblendobj, blendobj, static_cast<BL_SkinMeshObject*>(mesh), true, + true, static_cast<BL_ArmatureObject*>( parentobj ) ); releaseParent= false; @@ -1068,26 +1148,13 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) } gameobj->AddMeshUser(); + } + + if(use_phys) { /* update the new assigned mesh with the physics mesh */ + KX_ReInstanceBulletShapeFromMesh(gameobj, NULL, use_gfx?NULL:mesh); + } } - - -MT_CmMatrix4x4& KX_Scene::GetViewMatrix() -{ - MT_Scalar cammat[16]; - m_active_camera->GetWorldToCamera().getValue(cammat); - m_viewmat = cammat; - return m_viewmat; -} - - - -MT_CmMatrix4x4& KX_Scene::GetProjectionMatrix() -{ - return m_projectionmat; -} - - KX_Camera* KX_Scene::FindCamera(KX_Camera* cam) { list<KX_Camera*>::iterator it = m_cameras.begin(); @@ -1158,7 +1225,6 @@ void KX_Scene::UpdateMeshTransformations() { KX_GameObject* gameobj = (KX_GameObject*)m_objectlist->GetValue(i); gameobj->GetOpenGLMatrix(); -// gameobj->UpdateNonDynas(); } } @@ -1249,7 +1315,7 @@ void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Cam // If the camera is inside this node, then the object is visible. if (!vis) { - vis = gameobj->GetSGNode()->inside( GetActiveCamera()->GetCameraLocation() ); + vis = gameobj->GetSGNode()->inside( cam->GetCameraLocation() ); } // Test the object's bound sphere against the view frustum. @@ -1293,21 +1359,47 @@ void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Cam } } +void KX_Scene::PhysicsCullingCallback(KX_ClientObjectInfo* objectInfo, void* cullingInfo) +{ + KX_GameObject* gameobj = objectInfo->m_gameobject; + if (!gameobj->GetVisible()) + // ideally, invisible objects should be removed from the culling tree temporarily + return; + if(((CullingInfo*)cullingInfo)->m_layer && !(gameobj->GetLayer() & ((CullingInfo*)cullingInfo)->m_layer)) + // used for shadow: object is not in shadow layer + return; + + // make object visible + gameobj->SetCulled(false); + gameobj->UpdateBuckets(false); +} + void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int layer) { -// FIXME: When tree is operational -#if 1 - // do this incrementally in the future - for (int i = 0; i < m_objectlist->GetCount(); i++) + bool dbvt_culling = false; + if (m_dbvt_culling) { - MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam, layer); + // test culling through Bullet + PHY__Vector4 planes[6]; + // get the clip planes + MT_Vector4* cplanes = cam->GetNormalizedClipPlanes(); + // and convert + planes[0].setValue(cplanes[4].getValue()); // near + planes[1].setValue(cplanes[5].getValue()); // far + planes[2].setValue(cplanes[0].getValue()); // left + planes[3].setValue(cplanes[1].getValue()); // right + planes[4].setValue(cplanes[2].getValue()); // top + planes[5].setValue(cplanes[3].getValue()); // bottom + CullingInfo info(layer); + dbvt_culling = m_physicsEnvironment->cullingTest(PhysicsCullingCallback,&info,planes,5,m_dbvt_occlusion_res); + } + if (!dbvt_culling) { + // the physics engine couldn't help us, do it the hard way + for (int i = 0; i < m_objectlist->GetCount(); i++) + { + MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam, layer); + } } -#else - if (cam->GetFrustumCulling()) - MarkVisible(m_objecttree, rasty, cam, layer); - else - MarkSubTreeVisible(m_objecttree, rasty, true, cam, layer); -#endif } // logic stuff @@ -1356,24 +1448,17 @@ void KX_Scene::LogicEndFrame() { m_logicmgr->EndFrame(); int numobj = m_euthanasyobjects->GetCount(); - int i; - for (i = numobj - 1; i >= 0; i--) - { - KX_GameObject* gameobj = (KX_GameObject*)m_euthanasyobjects->GetValue(i); - // KX_Scene::RemoveObject will also remove the object from this list - // that's why we start from the end - this->RemoveObject(gameobj); - } - numobj= m_delayReleaseObjects->GetCount(); - for (i = numobj-1;i>=0;i--) + KX_GameObject* obj; + + while ((numobj = m_euthanasyobjects->GetCount()) > 0) { - KX_GameObject* gameobj = (KX_GameObject*)m_delayReleaseObjects->GetValue(i); - // This list is not for object removal, but just object release - gameobj->Release(); + // remove the object from this list to make sure we will not hit it again + obj = (KX_GameObject*)m_euthanasyobjects->GetValue(numobj-1); + m_euthanasyobjects->Remove(numobj-1); + obj->Release(); + RemoveObject(obj); } - // empty the list as we have removed all references - m_delayReleaseObjects->Resize(0); } @@ -1383,15 +1468,28 @@ void KX_Scene::LogicEndFrame() */ void KX_Scene::UpdateParents(double curtime) { -// int numrootobjects = GetRootParentList()->GetCount(); + // we use the SG dynamic list + SG_Node* node; - for (int i=0; i<GetRootParentList()->GetCount(); i++) + while ((node = SG_Node::GetNextScheduled(m_sghead)) != NULL) { - KX_GameObject* parentobj = (KX_GameObject*)GetRootParentList()->GetValue(i); - parentobj->NodeUpdateGS(curtime,true); + node->UpdateWorldData(curtime); } -} + //for (int i=0; i<GetRootParentList()->GetCount(); i++) + //{ + // KX_GameObject* parentobj = (KX_GameObject*)GetRootParentList()->GetValue(i); + // parentobj->NodeUpdateGS(curtime); + //} + + // the list must be empty here + assert(m_sghead.Empty()); + // some nodes may be ready for reschedule, move them to schedule list for next time + while ((node = SG_Node::GetNextRescheduled(m_sghead)) != NULL) + { + node->Schedule(m_sghead); + } +} RAS_MaterialBucket* KX_Scene::FindBucket(class RAS_IPolyMaterial* polymat, bool &bucketCreated) @@ -1472,11 +1570,6 @@ void KX_Scene::SetGravity(const MT_Vector3& gravity) GetPhysicsEnvironment()->setGravity(gravity[0],gravity[1],gravity[2]); } -void KX_Scene::SetNodeTree(SG_Tree* root) -{ - m_objecttree = root; -} - void KX_Scene::SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter) { m_sceneConverter = sceneConverter; @@ -1511,107 +1604,263 @@ double KX_Scene::getSuspendedDelta() //---------------------------------------------------------------------------- //Python -PyMethodDef KX_Scene::Methods[] = { - KX_PYMETHODTABLE(KX_Scene, getLightList), - KX_PYMETHODTABLE(KX_Scene, getObjectList), - KX_PYMETHODTABLE(KX_Scene, getName), - - {NULL,NULL} //Sentinel -}; - PyTypeObject KX_Scene::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_Scene", - sizeof(KX_Scene), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0, 0, 0, 0, 0, 0 + PyVarObject_HEAD_INIT(NULL, 0) + "KX_Scene", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, + &Sequence, + &Mapping, + 0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &CValue::Type, + 0,0,0,0,0,0, + py_base_new }; -PyParentObject KX_Scene::Parents[] = { - &KX_Scene::Type, - &CValue::Type, - NULL +PyMethodDef KX_Scene::Methods[] = { + KX_PYMETHODTABLE(KX_Scene, addObject), + + /* dict style access */ + KX_PYMETHODTABLE(KX_Scene, get), + + {NULL,NULL} //Sentinel }; - -PyObject* KX_Scene::_getattr(const STR_String& attr) +static PyObject *Map_GetItem(PyObject *self_v, PyObject *item) { - if (attr == "name") - return PyString_FromString(GetName()); + KX_Scene* self= static_cast<KX_Scene*>BGE_PROXY_REF(self_v); + const char *attr_str= _PyUnicode_AsString(item); + PyObject* pyconvert; - if (attr == "active_camera") - { - KX_Camera *camera = GetActiveCamera(); - camera->AddRef(); - return (PyObject*) camera; + if (self==NULL) { + PyErr_SetString(PyExc_SystemError, "val = scene[key]: KX_Scene, "BGE_PROXY_ERROR_MSG); + return NULL; } - if (attr == "suspended") - return PyInt_FromLong(m_suspend); + if (self->m_attr_dict && (pyconvert=PyDict_GetItem(self->m_attr_dict, item))) { + + if (attr_str) + PyErr_Clear(); + Py_INCREF(pyconvert); + return pyconvert; + } + else { + if(attr_str) PyErr_Format(PyExc_KeyError, "value = scene[key]: KX_Scene, key \"%s\" does not exist", attr_str); + else PyErr_SetString(PyExc_KeyError, "value = scene[key]: KX_Scene, key does not exist"); + return NULL; + } + +} + +static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) +{ + KX_Scene* self= static_cast<KX_Scene*>BGE_PROXY_REF(self_v); + const char *attr_str= _PyUnicode_AsString(key); + if(attr_str==NULL) + PyErr_Clear(); - if (attr == "activity_culling") - return PyInt_FromLong(m_activity_culling); + if (self==NULL) { + PyErr_SetString(PyExc_SystemError, "scene[key] = value: KX_Scene, "BGE_PROXY_ERROR_MSG); + return -1; + } - if (attr == "activity_culling_radius") - return PyFloat_FromDouble(m_activity_box_radius); + if (val==NULL) { /* del ob["key"] */ + int del= 0; + + if(self->m_attr_dict) + del |= (PyDict_DelItem(self->m_attr_dict, key)==0) ? 1:0; + + if (del==0) { + if(attr_str) PyErr_Format(PyExc_KeyError, "scene[key] = value: KX_Scene, key \"%s\" could not be set", attr_str); + else PyErr_SetString(PyExc_KeyError, "del scene[key]: KX_Scene, key could not be deleted"); + return -1; + } + else if (self->m_attr_dict) { + PyErr_Clear(); /* PyDict_DelItem sets an error when it fails */ + } + } + else { /* ob["key"] = value */ + int set = 0; + + if (self->m_attr_dict==NULL) /* lazy init */ + self->m_attr_dict= PyDict_New(); + + + if(PyDict_SetItem(self->m_attr_dict, key, val)==0) + set= 1; + else + PyErr_SetString(PyExc_KeyError, "scene[key] = value: KX_Scene, key not be added to internal dictionary"); - PyObject* value = PyDict_GetItemString(m_attrlist, const_cast<char *>(attr.ReadPtr())); - if (value) - { - Py_INCREF(value); - return value; + if(set==0) + return -1; /* pythons error value */ + } - _getattr_up(PyObjectPlus); + return 0; /* success */ } -int KX_Scene::_delattr(const STR_String &attr) +static int Seq_Contains(PyObject *self_v, PyObject *value) { - PyDict_DelItemString(m_attrlist, const_cast<char *>(attr.ReadPtr())); + KX_Scene* self= static_cast<KX_Scene*>BGE_PROXY_REF(self_v); + + if (self==NULL) { + PyErr_SetString(PyExc_SystemError, "val in scene: KX_Scene, "BGE_PROXY_ERROR_MSG); + return -1; + } + + if (self->m_attr_dict && PyDict_GetItem(self->m_attr_dict, value)) + return 1; + return 0; } -int KX_Scene::_setattr(const STR_String &attr, PyObject *pyvalue) +PyMappingMethods KX_Scene::Mapping = { + (lenfunc)NULL , /*inquiry mp_length */ + (binaryfunc)Map_GetItem, /*binaryfunc mp_subscript */ + (objobjargproc)Map_SetItem, /*objobjargproc mp_ass_subscript */ +}; + +PySequenceMethods KX_Scene::Sequence = { + NULL, /* Cant set the len otherwise it can evaluate as false */ + NULL, /* sq_concat */ + NULL, /* sq_repeat */ + NULL, /* sq_item */ + NULL, /* sq_slice */ + NULL, /* sq_ass_item */ + NULL, /* sq_ass_slice */ + (objobjproc)Seq_Contains, /* sq_contains */ +}; + +PyObject* KX_Scene::pyattr_get_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { + KX_Scene* self= static_cast<KX_Scene*>(self_v); + return PyUnicode_FromString(self->GetName().ReadPtr()); +} - if (!PyDict_SetItemString(m_attrlist, const_cast<char *>(attr.ReadPtr()), pyvalue)) - return 0; +PyObject* KX_Scene::pyattr_get_objects(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene* self= static_cast<KX_Scene*>(self_v); + return self->GetObjectList()->GetProxy(); +} - return PyObjectPlus::_setattr(attr, pyvalue); +PyObject* KX_Scene::pyattr_get_objects_inactive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene* self= static_cast<KX_Scene*>(self_v); + return self->GetInactiveList()->GetProxy(); } -KX_PYMETHODDEF_DOC(KX_Scene, getLightList, -"getLightList() -> list [KX_Light]\n" -"Returns a list of all lights in the scene.\n" -) +PyObject* KX_Scene::pyattr_get_lights(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - m_lightlist->AddRef(); - return (PyObject*) m_lightlist; + KX_Scene* self= static_cast<KX_Scene*>(self_v); + return self->GetLightList()->GetProxy(); } -KX_PYMETHODDEF_DOC(KX_Scene, getObjectList, -"getObjectList() -> list [KX_GameObject]\n" -"Returns a list of all game objects in the scene.\n" -) +PyObject* KX_Scene::pyattr_get_cameras(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - m_objectlist->AddRef(); - return (PyObject*) m_objectlist; + /* With refcounts in this case... + * the new CListValue is owned by python, so its possible python holds onto it longer then the BGE + * however this is the same with "scene.objects + []", when you make a copy by adding lists. + */ + + KX_Scene* self= static_cast<KX_Scene*>(self_v); + CListValue* clist = new CListValue(); + + /* return self->GetCameras()->GetProxy(); */ + + list<KX_Camera*>::iterator it = self->GetCameras()->begin(); + while (it != self->GetCameras()->end()) { + clist->Add((*it)->AddRef()); + it++; + } + + return clist->NewProxy(true); +} + +PyObject* KX_Scene::pyattr_get_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene* self= static_cast<KX_Scene*>(self_v); + return self->GetActiveCamera()->GetProxy(); +} + + +int KX_Scene::pyattr_set_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Scene* self= static_cast<KX_Scene*>(self_v); + KX_Camera *camOb; + + if (!ConvertPythonToCamera(value, &camOb, false, "scene.active_camera = value: KX_Scene")) + return PY_SET_ATTR_FAIL; + + self->SetActiveCamera(camOb); + return PY_SET_ATTR_SUCCESS; +} + + +PyAttributeDef KX_Scene::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("name", KX_Scene, pyattr_get_name), + KX_PYATTRIBUTE_RO_FUNCTION("objects", KX_Scene, pyattr_get_objects), + KX_PYATTRIBUTE_RO_FUNCTION("objectsInactive", KX_Scene, pyattr_get_objects_inactive), KX_PYATTRIBUTE_RO_FUNCTION("lights", KX_Scene, pyattr_get_lights), + KX_PYATTRIBUTE_RO_FUNCTION("cameras", KX_Scene, pyattr_get_cameras), + KX_PYATTRIBUTE_RO_FUNCTION("lights", KX_Scene, pyattr_get_lights), + KX_PYATTRIBUTE_RW_FUNCTION("active_camera", KX_Scene, pyattr_get_active_camera, pyattr_set_active_camera), + KX_PYATTRIBUTE_BOOL_RO("suspended", KX_Scene, m_suspend), + KX_PYATTRIBUTE_BOOL_RO("activity_culling", KX_Scene, m_activity_culling), + KX_PYATTRIBUTE_FLOAT_RW("activity_culling_radius", 0.5f, FLT_MAX, KX_Scene, m_activity_box_radius), + KX_PYATTRIBUTE_BOOL_RO("dbvt_culling", KX_Scene, m_dbvt_culling), + { NULL } //Sentinel +}; + +KX_PYMETHODDEF_DOC(KX_Scene, addObject, +"addObject(object, other, time=0)\n" +"Returns the added object.\n") +{ + PyObject *pyob, *pyother; + KX_GameObject *ob, *other; + + int time = 0; + + if (!PyArg_ParseTuple(args, "OO|i:addObject", &pyob, &pyother, &time)) + return NULL; + + if ( !ConvertPythonToGameObject(pyob, &ob, false, "scene.addObject(object, other, time): KX_Scene (first argument)") || + !ConvertPythonToGameObject(pyother, &other, false, "scene.addObject(object, other, time): KX_Scene (second argument)") ) + return NULL; + + + SCA_IObject* replica = AddReplicaObject((SCA_IObject*)ob, other, time); + + // release here because AddReplicaObject AddRef's + // the object is added to the scene so we dont want python to own a reference + replica->Release(); + return replica->GetProxy(); } -KX_PYMETHODDEF_DOC(KX_Scene, getName, -"getName() -> string\n" -"Returns the name of the scene.\n" -) +/* Matches python dict.get(key, [default]) */ +KX_PYMETHODDEF_DOC(KX_Scene, get, "") { - return PyString_FromString(GetName()); + PyObject *key; + PyObject* def = Py_None; + PyObject* ret; + + if (!PyArg_ParseTuple(args, "O|O:get", &key, &def)) + return NULL; + + if (m_attr_dict && (ret=PyDict_GetItem(m_attr_dict, key))) { + Py_INCREF(ret); + return ret; + } + + Py_INCREF(def); + return def; } diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index 5f7e1167e27..3e0dc303d72 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -32,8 +32,6 @@ #include "KX_PhysicsEngineEnums.h" -#include "MT_CmMatrix4x4.h" - #include <vector> #include <set> #include <list> @@ -43,7 +41,7 @@ #include "SG_IObject.h" #include "SCA_IScene.h" #include "MT_Transform.h" -#include "SND_Scene.h" + #include "RAS_FramingManager.h" #include "RAS_Rect.h" @@ -65,8 +63,6 @@ class SCA_TimeEventManager; class SCA_MouseManager; class SCA_ISystem; class SCA_IInputDevice; -class SND_Scene; -class SND_IAudioDevice; class NG_NetworkDeviceInterface; class NG_NetworkScene; class SG_IObject; @@ -85,6 +81,8 @@ class RAS_IRenderTools; class SCA_JoystickManager; class btCollisionShape; class KX_BlenderSceneConverter; +struct KX_ClientObjectInfo; + /** * The KX_Scene holds all data for an independent scene. It relates * KX_Objects to the specific objects in the modules. @@ -92,6 +90,13 @@ class KX_BlenderSceneConverter; class KX_Scene : public PyObjectPlus, public SCA_IScene { Py_Header; + PyObject* m_attr_dict; + + struct CullingInfo { + int m_layer; + CullingInfo(int layer) : m_layer(layer) {} + }; + protected: RAS_BucketManager* m_bucketmanager; CListValue* m_tempObjectList; @@ -102,21 +107,17 @@ protected: * LogicEndFrame() via a call to RemoveObject(). */ CListValue* m_euthanasyobjects; - /** - * The list of objects that couldn't be released during logic update. - * for example, AddObject actuator sometimes releases an object that was cached from previous frame - */ - CListValue* m_delayReleaseObjects; CListValue* m_objectlist; CListValue* m_parentlist; // all 'root' parents CListValue* m_lightlist; CListValue* m_inactivelist; // all objects that are not in the active layer + + SG_QList m_sghead; // list of nodes that needs scenegraph update + // the Dlist is not object that must be updated + // the Qlist is for objects that needs to be rescheduled + // for updates after udpate is over (slow parent, bone parent) - /** - * The tree of objects in the scene. - */ - SG_Tree* m_objecttree; /** * The set of cameras for this scene @@ -158,14 +159,7 @@ protected: * @section Different scenes, linked to ketsji scene */ - /** - * Sound scenes - */ - SND_Scene* m_soundScene; - SND_IAudioDevice* m_adi; - - /** * Network scene. */ NG_NetworkDeviceInterface* m_networkDeviceInterface; @@ -183,20 +177,6 @@ protected: */ KX_Camera* m_active_camera; - /** - * The projection and view matrices of this scene - * The projection matrix is computed externally by KX_Engine - * The view mat is stored as a side effect of GetViewMatrix() - * and is totally unnessary. - */ - MT_CmMatrix4x4 m_projectionmat; - MT_CmMatrix4x4 m_viewmat; - - /** Desired canvas width set at design time. */ - unsigned int m_canvasDesignWidth; - /** Desired canvas height set at design time. */ - unsigned int m_canvasDesignHeight; - /** * Another temporary variable outstaying its welcome * used in AddReplicaObject to map game objects to their @@ -252,6 +232,16 @@ protected: bool m_activity_culling; /** + * Toggle to enable or disable culling via DBVT broadphase of Bullet. + */ + bool m_dbvt_culling; + + /** + * Occlusion culling resolution + */ + int m_dbvt_occlusion_res; + + /** * The framing settings used by this scene */ @@ -269,22 +259,17 @@ protected: void MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera*cam,int layer=0); void MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible, KX_Camera*cam,int layer=0); void MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj, KX_Camera*cam, int layer=0); + static void PhysicsCullingCallback(KX_ClientObjectInfo* objectInfo, void* cullingInfo); double m_suspendedtime; double m_suspendeddelta; - - /** - * This stores anything from python - */ - PyObject* m_attrlist; struct Scene* m_blenderScene; -public: +public: KX_Scene(class SCA_IInputDevice* keyboarddevice, class SCA_IInputDevice* mousedevice, class NG_NetworkDeviceInterface* ndi, - class SND_IAudioDevice* adi, const STR_String& scenename, struct Scene* scene); @@ -299,6 +284,8 @@ public: /** * Update all transforms according to the scenegraph. */ + static bool KX_ScenegraphUpdateFunc(SG_IObject* node,void* gameobj,void* scene); + static bool KX_ScenegraphRescheduleFunc(SG_IObject* node,void* gameobj,void* scene); void UpdateParents(double curtime); void DupliGroupRecurse(CValue* gameobj, int level); bool IsObjectInGroup(CValue* gameobj) @@ -316,11 +303,9 @@ public: void RemoveObject(CValue* gameobj); void DelayedRemoveObject(CValue* gameobj); - void DelayedReleaseObject(CValue* gameobj); - int NewRemoveObject(CValue* gameobj); void ReplaceMesh(CValue* gameobj, - void* meshobj); + void* meshob, bool use_gfx, bool use_phys); /** * @section Logic stuff * Initiate an update of the logic system. @@ -403,25 +388,6 @@ public: class KX_Camera* ); - /** Return the viewmatrix as used by the last frame. */ - MT_CmMatrix4x4& - GetViewMatrix( - ); - - /** - * Return the projectionmatrix as used by the last frame. This is - * set by hand :) - */ - MT_CmMatrix4x4& - GetProjectionMatrix( - ); - - /** Sets the projection matrix. */ - void - SetProjectionMatrix( - MT_CmMatrix4x4& pmat - ); - /** * Activates new desired canvas width set at design time. * @param width The new desired width. @@ -500,7 +466,6 @@ public: void CalculateVisibleMeshes(RAS_IRasterizer* rasty, KX_Camera *cam, int layer=0); void UpdateMeshTransformations(); KX_Camera* GetpCamera(); - SND_Scene* GetSoundScene(); NG_NetworkDeviceInterface* GetNetworkDeviceInterface(); NG_NetworkScene* GetNetworkScene(); @@ -530,6 +495,11 @@ public: bool IsSuspended(); bool IsClearingZBuffer(); void EnableZBufferClearing(bool isclearingZbuffer); + // use of DBVT tree for camera culling + void SetDbvtCulling(bool b) { m_dbvt_culling = b; }; + bool GetDbvtCulling() { return m_dbvt_culling; }; + void SetDbvtOcclusionRes(int i) { m_dbvt_occlusion_res = i; }; + int GetDbvtOcclusionRes() { return m_dbvt_occlusion_res; }; void SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter); @@ -547,26 +517,27 @@ public: */ void SetNodeTree(SG_Tree* root); - KX_PYMETHOD_DOC(KX_Scene, getLightList); - KX_PYMETHOD_DOC(KX_Scene, getObjectList); - KX_PYMETHOD_DOC(KX_Scene, getName); -/* - KX_PYMETHOD_DOC(KX_Scene, getActiveCamera); - KX_PYMETHOD_DOC(KX_Scene, getActiveCamera); - KX_PYMETHOD_DOC(KX_Scene, findCamera); - - KX_PYMETHOD_DOC(KX_Scene, getGravity); - - KX_PYMETHOD_DOC(KX_Scene, setActivityCulling); - KX_PYMETHOD_DOC(KX_Scene, setActivityCullingRadius); - - KX_PYMETHOD_DOC(KX_Scene, setSceneViewport); - KX_PYMETHOD_DOC(KX_Scene, setSceneViewport); - */ + /* --------------------------------------------------------------------- */ + /* Python interface ---------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + + KX_PYMETHOD_DOC(KX_Scene, addObject); + KX_PYMETHOD_DOC(KX_Scene, get); - virtual PyObject* _getattr(const STR_String& attr); /* name, active_camera, gravity, suspended, viewport, framing, activity_culling, activity_culling_radius */ - virtual int _setattr(const STR_String &attr, PyObject *pyvalue); - virtual int _delattr(const STR_String &attr); + /* attributes */ + static PyObject* pyattr_get_name(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_objects(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_objects_inactive(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_lights(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_cameras(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_active_camera(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + virtual PyObject* py_repr(void) { return PyUnicode_FromString(GetName().ReadPtr()); } + + /* getitem/setitem */ + static PyMappingMethods Mapping; + static PySequenceMethods Sequence; /** * Sets the time the scene was suspended diff --git a/source/gameengine/Ketsji/KX_SceneActuator.cpp b/source/gameengine/Ketsji/KX_SceneActuator.cpp index 35484699b17..ea1be7bca6c 100644 --- a/source/gameengine/Ketsji/KX_SceneActuator.cpp +++ b/source/gameengine/Ketsji/KX_SceneActuator.cpp @@ -49,9 +49,8 @@ KX_SceneActuator::KX_SceneActuator(SCA_IObject *gameobj, KX_Scene *scene, KX_KetsjiEngine* ketsjiEngine, const STR_String& nextSceneName, - KX_Camera* camera, - PyTypeObject* T) - : SCA_IActuator(gameobj, T) + KX_Camera* camera) + : SCA_IActuator(gameobj) { m_mode = mode; m_scene = scene; @@ -76,9 +75,6 @@ CValue* KX_SceneActuator::GetReplica() { KX_SceneActuator* replica = new KX_SceneActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); - return replica; } @@ -137,7 +133,7 @@ bool KX_SceneActuator::Update() { // if no camera is set and the parent object is a camera, use it as the camera SCA_IObject* parent = GetParent(); - if (parent->isA(&KX_Camera::Type)) + if (parent->GetGameObjectType()==SCA_IObject::OBJ_CAMERA) { m_scene->SetActiveCamera((KX_Camera*)parent); } @@ -226,181 +222,69 @@ KX_Scene* KX_SceneActuator::FindScene(char * sceneName) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_SceneActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_SceneActuator", - sizeof(KX_SceneActuator), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 -}; - - - -PyParentObject KX_SceneActuator::Parents[] = -{ - &KX_SceneActuator::Type, - &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + PyVarObject_HEAD_INIT(NULL, 0) + "KX_SceneActuator", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_IActuator::Type, + 0,0,0,0,0,0, + py_base_new }; - - PyMethodDef KX_SceneActuator::Methods[] = { - {"setUseRestart", (PyCFunction) KX_SceneActuator::sPySetUseRestart, METH_VARARGS, (PY_METHODCHAR)SetUseRestart_doc}, - {"setScene", (PyCFunction) KX_SceneActuator::sPySetScene, METH_VARARGS, (PY_METHODCHAR)SetScene_doc}, - {"setCamera", (PyCFunction) KX_SceneActuator::sPySetCamera, METH_VARARGS, (PY_METHODCHAR)SetCamera_doc}, - {"getUseRestart", (PyCFunction) KX_SceneActuator::sPyGetUseRestart, METH_VARARGS, (PY_METHODCHAR)GetUseRestart_doc}, - {"getScene", (PyCFunction) KX_SceneActuator::sPyGetScene, METH_VARARGS, (PY_METHODCHAR)GetScene_doc}, - {"getCamera", (PyCFunction) KX_SceneActuator::sPyGetCamera, METH_VARARGS, (PY_METHODCHAR)GetCamera_doc}, {NULL,NULL} //Sentinel }; +PyAttributeDef KX_SceneActuator::Attributes[] = { + KX_PYATTRIBUTE_STRING_RW("scene",0,32,true,KX_SceneActuator,m_nextSceneName), + KX_PYATTRIBUTE_RW_FUNCTION("camera",KX_SceneActuator,pyattr_get_camera,pyattr_set_camera), + KX_PYATTRIBUTE_BOOL_RW("useRestart", KX_SceneActuator, m_restart), + KX_PYATTRIBUTE_INT_RW("mode", KX_SCENE_NODEF+1, KX_SCENE_MAX-1, true, KX_SceneActuator, m_mode), + { NULL } //Sentinel +}; - -PyObject* KX_SceneActuator::_getattr(const STR_String& attr) +PyObject* KX_SceneActuator::pyattr_get_camera(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) { - _getattr_up(SCA_IActuator); + KX_SceneActuator* actuator = static_cast<KX_SceneActuator*>(self); + if (!actuator->m_camera) + Py_RETURN_NONE; + + return actuator->m_camera->GetProxy(); } - - -/* 2. setUseRestart--------------------------------------------------------- */ -const char KX_SceneActuator::SetUseRestart_doc[] = -"setUseRestart(flag)\n" -"\t- flag: 0 or 1.\n" -"\tSet flag to 1 to restart the scene.\n" ; -PyObject* KX_SceneActuator::PySetUseRestart(PyObject* self, - PyObject* args, - PyObject* kwds) +int KX_SceneActuator::pyattr_set_camera(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - int boolArg; + KX_SceneActuator* actuator = static_cast<KX_SceneActuator*>(self); + KX_Camera *camOb; - if (!PyArg_ParseTuple(args, "i", &boolArg)) - { - return NULL; - } + if (!ConvertPythonToCamera(value, &camOb, true, "actu.camera = value: KX_SceneActuator")) + return PY_SET_ATTR_FAIL; - m_restart = boolArg != 0; + if (actuator->m_camera) + actuator->m_camera->UnregisterActuator(actuator); - Py_Return; -} - - - -/* 3. getUseRestart: */ -const char KX_SceneActuator::GetUseRestart_doc[] = -"getUseRestart()\n" -"\tReturn whether the scene will be restarted.\n" ; -PyObject* KX_SceneActuator::PyGetUseRestart(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - return PyInt_FromLong(!(m_restart == 0)); -} - - - -/* 4. set scene------------------------------------------------------------- */ -const char KX_SceneActuator::SetScene_doc[] = -"setScene(scene)\n" -"\t- scene: string\n" -"\tSet the name of scene the actuator will switch to.\n" ; -PyObject* KX_SceneActuator::PySetScene(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - /* one argument: a scene, ignore the rest */ - char *scene_name; - - if(!PyArg_ParseTuple(args, "s", &scene_name)) - { - return NULL; - } - - /* Scene switch is done by name. */ - m_nextSceneName = scene_name; - - Py_Return; -} - - - -/* 5. getScene: */ -const char KX_SceneActuator::GetScene_doc[] = -"getScene()\n" -"\tReturn the name of the scene the actuator wants to switch to.\n" ; -PyObject* KX_SceneActuator::PyGetScene(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - return PyString_FromString(m_nextSceneName); -} - - - -/* 6. set camera------------------------------------------------------------ */ -const char KX_SceneActuator::SetCamera_doc[] = -"setCamera(camera)\n" -"\t- camera: string\n" -"\tSet the camera to switch to.\n" ; -PyObject* KX_SceneActuator::PySetCamera(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - PyObject *cam; - if (PyArg_ParseTuple(args, "O!", &KX_Camera::Type, &cam)) - { - if (m_camera) - m_camera->UnregisterActuator(this); - m_camera = (KX_Camera*) cam; - if (m_camera) - m_camera->RegisterActuator(this); - Py_Return; + if(camOb==NULL) { + actuator->m_camera= NULL; } - PyErr_Clear(); - - /* one argument: a scene, ignore the rest */ - char *camName; - if(!PyArg_ParseTuple(args, "s", &camName)) - { - return NULL; - } - - KX_Camera *camOb = FindCamera(camName); - if (camOb) - { - if (m_camera) - m_camera->UnregisterActuator(this); - m_camera = camOb; - m_camera->RegisterActuator(this); + else { + actuator->m_camera = camOb; + actuator->m_camera->RegisterActuator(actuator); } - - Py_Return; + + return PY_SET_ATTR_SUCCESS; } - - -/* 7. getCamera: */ -const char KX_SceneActuator::GetCamera_doc[] = -"getCamera()\n" -"\tReturn the name of the camera to switch to.\n" ; -PyObject* KX_SceneActuator::PyGetCamera(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - return PyString_FromString(m_camera->GetName()); -} /* eof */ diff --git a/source/gameengine/Ketsji/KX_SceneActuator.h b/source/gameengine/Ketsji/KX_SceneActuator.h index 55aaf629d7c..e979a8ce559 100644 --- a/source/gameengine/Ketsji/KX_SceneActuator.h +++ b/source/gameengine/Ketsji/KX_SceneActuator.h @@ -77,8 +77,7 @@ class KX_SceneActuator : public SCA_IActuator KX_Scene* scene, KX_KetsjiEngine* ketsjiEngine, const STR_String& nextSceneName, - KX_Camera* camera, - PyTypeObject* T=&Type); + KX_Camera* camera); virtual ~KX_SceneActuator(); virtual CValue* GetReplica(); @@ -91,25 +90,10 @@ class KX_SceneActuator : public SCA_IActuator /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - virtual PyObject* _getattr(const STR_String& attr); - - /* 1. set */ - /* Removed */ - - /* 2. setUseRestart: */ - KX_PYMETHOD_DOC(KX_SceneActuator,SetUseRestart); - /* 3. getUseRestart: */ - KX_PYMETHOD_DOC(KX_SceneActuator,GetUseRestart); - /* 4. setScene: */ - KX_PYMETHOD_DOC(KX_SceneActuator,SetScene); - /* 5. getScene: */ - KX_PYMETHOD_DOC(KX_SceneActuator,GetScene); - /* 6. setCamera: */ - KX_PYMETHOD_DOC(KX_SceneActuator,SetCamera); - /* 7. getCamera: */ - KX_PYMETHOD_DOC(KX_SceneActuator,GetCamera); + static PyObject* pyattr_get_camera(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_camera(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + }; /* end of class KXSceneActuator */ #endif diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index afa5af3bc04..e2b4022a312 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -31,10 +31,8 @@ */ #include "KX_SoundActuator.h" -#include "SND_SoundObject.h" #include "KX_GameObject.h" -#include "SND_SoundObject.h" -#include "SND_Scene.h" // needed for replication +#include "KX_PyMath.h" // needed for PyObjectFrom() #include <iostream> #ifdef HAVE_CONFIG_H @@ -45,56 +43,107 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, - SND_SoundObject* sndobj, - SND_Scene* sndscene, - KX_SOUNDACT_TYPE type, - short start, - short end, - PyTypeObject* T) - : SCA_IActuator(gameobj,T) + AUD_Sound* sound, + float volume, + float pitch, + bool is3d, + KX_3DSoundSettings settings, + KX_SOUNDACT_TYPE type)//, + : SCA_IActuator(gameobj) { - m_soundObject = sndobj; - m_soundScene = sndscene; + m_sound = sound; + m_volume = volume; + m_pitch = pitch; + m_is3d = is3d; + m_3d = settings; + m_handle = NULL; m_type = type; - m_lastEvent = true; m_isplaying = false; - m_startFrame = start; - m_endFrame = end; - m_pino = false; - - } KX_SoundActuator::~KX_SoundActuator() { - if (m_soundObject) - { - m_soundScene->RemoveActiveObject(m_soundObject); - m_soundScene->DeleteObject(m_soundObject); - } + if(m_handle) + AUD_stop(m_handle); } +void KX_SoundActuator::play() +{ + if(m_handle) + AUD_stop(m_handle); + + if(!m_sound) + return; + + // this is the sound that will be played and not deleted afterwards + AUD_Sound* sound = m_sound; + // this sounds are for temporary stacked sounds, will be deleted if not NULL + AUD_Sound* sound2 = NULL; + AUD_Sound* sound3 = NULL; + + switch (m_type) + { + case KX_SOUNDACT_LOOPBIDIRECTIONAL: + case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: + // create a ping pong sound on sound2 stacked on the orignal sound + sound2 = AUD_pingpongSound(sound); + // create a loop sound on sound3 stacked on the pingpong sound and let that one play (save it to sound) + sound = sound3 = AUD_loopSound(sound2); + break; + case KX_SOUNDACT_LOOPEND: + case KX_SOUNDACT_LOOPSTOP: + // create a loop sound on sound2 stacked on the pingpong sound and let that one play (save it to sound) + sound = sound2 = AUD_loopSound(sound); + break; + case KX_SOUNDACT_PLAYSTOP: + case KX_SOUNDACT_PLAYEND: + default: + break; + } + if(m_is3d) + { + // sound shall be played 3D + m_handle = AUD_play3D(sound, 0); + + AUD_set3DSourceSetting(m_handle, AUD_3DSS_MAX_GAIN, m_3d.max_gain); + AUD_set3DSourceSetting(m_handle, AUD_3DSS_MIN_GAIN, m_3d.min_gain); + AUD_set3DSourceSetting(m_handle, AUD_3DSS_REFERENCE_DISTANCE, m_3d.reference_distance); + AUD_set3DSourceSetting(m_handle, AUD_3DSS_MAX_DISTANCE, m_3d.max_distance); + AUD_set3DSourceSetting(m_handle, AUD_3DSS_ROLLOFF_FACTOR, m_3d.rolloff_factor); + AUD_set3DSourceSetting(m_handle, AUD_3DSS_CONE_INNER_ANGLE, m_3d.cone_inner_angle); + AUD_set3DSourceSetting(m_handle, AUD_3DSS_CONE_OUTER_ANGLE, m_3d.cone_outer_angle); + AUD_set3DSourceSetting(m_handle, AUD_3DSS_CONE_OUTER_GAIN, m_3d.cone_outer_gain); + } + else + m_handle = AUD_play(sound, 0); + + AUD_setSoundPitch(m_handle, m_pitch); + AUD_setSoundVolume(m_handle, m_volume); + m_isplaying = true; + + // now we unload the pingpong and loop sounds, as we don't need them anymore + // the started sound will continue playing like it was created, don't worry! + if(sound3) + AUD_unload(sound3); + if(sound2) + AUD_unload(sound2); +} CValue* KX_SoundActuator::GetReplica() { KX_SoundActuator* replica = new KX_SoundActuator(*this); replica->ProcessReplica(); - if (m_soundObject) - { - SND_SoundObject* soundobj = new SND_SoundObject(*m_soundObject); - replica->setSoundObject(soundobj); - m_soundScene->AddObject(soundobj); - } - - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; }; - +void KX_SoundActuator::ProcessReplica() +{ + SCA_IActuator::ProcessReplica(); + m_handle = 0; +} bool KX_SoundActuator::Update(double curtime, bool frame) { @@ -104,25 +153,20 @@ bool KX_SoundActuator::Update(double curtime, bool frame) // do nothing on negative events, otherwise sounds are played twice! bool bNegativeEvent = IsNegativeEvent(); - + bool bPositiveEvent = m_posevent; + RemoveAllEvents(); - if (!m_soundObject) + if(!m_sound) return false; // actual audio device playing state - bool isplaying = (m_soundObject->GetPlaystate() != SND_STOPPED) ? true : false; - - if (m_pino) - { - bNegativeEvent = true; - m_pino = false; - } + bool isplaying = AUD_getStatus(m_handle) == AUD_STATUS_PLAYING; if (bNegativeEvent) - { + { // here must be a check if it is still playing - if (m_isplaying && isplaying) + if (m_isplaying && isplaying) { switch (m_type) { @@ -130,19 +174,20 @@ bool KX_SoundActuator::Update(double curtime, bool frame) case KX_SOUNDACT_LOOPSTOP: case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: { - m_soundScene->RemoveActiveObject(m_soundObject); + // stop immediately + AUD_stop(m_handle); break; } case KX_SOUNDACT_PLAYEND: { - m_soundObject->SetPlaystate(SND_MUST_STOP_WHEN_FINISHED); + // do nothing, sound will stop anyway when it's finished break; } case KX_SOUNDACT_LOOPEND: case KX_SOUNDACT_LOOPBIDIRECTIONAL: { - m_soundObject->SetLoopMode(SND_LOOP_OFF); - m_soundObject->SetPlaystate(SND_MUST_STOP_WHEN_FINISHED); + // stop the looping so that the sound stops when it finished + AUD_stopLoop(m_handle); break; } default: @@ -153,53 +198,61 @@ bool KX_SoundActuator::Update(double curtime, bool frame) // remember that we tried to stop the actuator m_isplaying = false; } - else - { + +#if 1 + // Warning: when de-activating the actuator, after a single negative event this runs again with... + // m_posevent==false && m_posevent==false, in this case IsNegativeEvent() returns false + // and assumes this is a positive event. + // check that we actually have a positive event so as not to play sounds when being disabled. + else if(bPositiveEvent) { // <- added since 2.49 +#else + else { // <- works in most cases except a loop-end sound will never stop unless + // the negative pulse is done continuesly +#endif if (!m_isplaying) - { - switch (m_type) - { - case KX_SOUNDACT_LOOPBIDIRECTIONAL: - case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: - { - m_soundObject->SetLoopMode(SND_LOOP_BIDIRECTIONAL); - m_soundScene->AddActiveObject(m_soundObject, curtime); - m_isplaying = true; - result = true; - break; - } - case KX_SOUNDACT_LOOPEND: - case KX_SOUNDACT_LOOPSTOP: - { - m_soundObject->SetLoopMode(SND_LOOP_NORMAL); - m_soundScene->AddActiveObject(m_soundObject, curtime); - m_isplaying = true; - result = true; - break; - } - case KX_SOUNDACT_PLAYSTOP: - case KX_SOUNDACT_PLAYEND: - { - m_soundObject->SetLoopMode(SND_LOOP_OFF); - m_soundScene->AddActiveObject(m_soundObject, curtime); - m_isplaying = true; - result = true; - break; - } - default: - // implement me !! - break; - } - } + play(); } // verify that the sound is still playing - isplaying = (m_soundObject->GetPlaystate() != SND_STOPPED) ? true : false; + isplaying = AUD_getStatus(m_handle) == AUD_STATUS_PLAYING ? true : false; if (isplaying) { - m_soundObject->SetPosition(((KX_GameObject*)this->GetParent())->NodeGetWorldPosition()); - m_soundObject->SetVelocity(((KX_GameObject*)this->GetParent())->GetLinearVelocity()); - m_soundObject->SetOrientation(((KX_GameObject*)this->GetParent())->NodeGetWorldOrientation()); + if(m_is3d) + { + AUD_3DData data; + float f; + ((KX_GameObject*)this->GetParent())->NodeGetWorldPosition().getValue(data.position); + ((KX_GameObject*)this->GetParent())->GetLinearVelocity().getValue(data.velocity); + ((KX_GameObject*)this->GetParent())->NodeGetWorldOrientation().getValue3x3(data.orientation); + + /* + * The 3D data from blender has to be transformed for OpenAL: + * - In blender z is up and y is forwards + * - In OpenAL y is up and z is backwards + * We have to do that for all 5 vectors. + */ + f = data.position[1]; + data.position[1] = data.position[2]; + data.position[2] = -f; + + f = data.velocity[1]; + data.velocity[1] = data.velocity[2]; + data.velocity[2] = -f; + + f = data.orientation[1]; + data.orientation[1] = data.orientation[2]; + data.orientation[2] = -f; + + f = data.orientation[4]; + data.orientation[4] = data.orientation[5]; + data.orientation[5] = -f; + + f = data.orientation[7]; + data.orientation[7] = data.orientation[8]; + data.orientation[8] = -f; + + AUD_update3DSource(m_handle, &data); + } result = true; } else @@ -207,23 +260,11 @@ bool KX_SoundActuator::Update(double curtime, bool frame) m_isplaying = false; result = false; } - /* - if (result && (m_soundObject->IsLifeSpanOver(curtime)) && ((m_type == KX_SOUNDACT_PLAYEND) || (m_type == KX_SOUNDACT_PLAYSTOP))) - { - m_pino = true; - } - */ return result; } -void KX_SoundActuator::setSoundObject(class SND_SoundObject* soundobject) -{ - m_soundObject = soundobject; -} - - /* ------------------------------------------------------------------------- */ /* Python functions */ @@ -233,303 +274,145 @@ void KX_SoundActuator::setSoundObject(class SND_SoundObject* soundobject) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_SoundActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_SoundActuator", - sizeof(KX_SoundActuator), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 -}; - - - -PyParentObject KX_SoundActuator::Parents[] = { - &KX_SoundActuator::Type, - &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + PyVarObject_HEAD_INIT(NULL, 0) + "KX_SoundActuator", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_IActuator::Type, + 0,0,0,0,0,0, + py_base_new }; - - PyMethodDef KX_SoundActuator::Methods[] = { - {"setFilename", (PyCFunction) KX_SoundActuator::sPySetFilename, METH_VARARGS,NULL}, - {"getFilename", (PyCFunction) KX_SoundActuator::sPyGetFilename, METH_VARARGS,NULL}, - {"startSound",(PyCFunction) KX_SoundActuator::sPyStartSound,METH_VARARGS,NULL}, - {"pauseSound",(PyCFunction) KX_SoundActuator::sPyPauseSound,METH_VARARGS,NULL}, - {"stopSound",(PyCFunction) KX_SoundActuator::sPyStopSound,METH_VARARGS,NULL}, - {"setGain",(PyCFunction) KX_SoundActuator::sPySetGain,METH_VARARGS,NULL}, - {"getGain",(PyCFunction) KX_SoundActuator::sPyGetGain,METH_VARARGS,NULL}, - {"setPitch",(PyCFunction) KX_SoundActuator::sPySetPitch,METH_VARARGS,NULL}, - {"getPitch",(PyCFunction) KX_SoundActuator::sPyGetPitch,METH_VARARGS,NULL}, - {"setRollOffFactor",(PyCFunction) KX_SoundActuator::sPySetRollOffFactor,METH_VARARGS,NULL}, - {"getRollOffFactor",(PyCFunction) KX_SoundActuator::sPyGetRollOffFactor,METH_VARARGS,NULL}, - {"setLooping",(PyCFunction) KX_SoundActuator::sPySetLooping,METH_VARARGS,NULL}, - {"getLooping",(PyCFunction) KX_SoundActuator::sPyGetLooping,METH_VARARGS,NULL}, - {"setPosition",(PyCFunction) KX_SoundActuator::sPySetPosition,METH_VARARGS,NULL}, - {"setVelocity",(PyCFunction) KX_SoundActuator::sPySetVelocity,METH_VARARGS,NULL}, - {"setOrientation",(PyCFunction) KX_SoundActuator::sPySetOrientation,METH_VARARGS,NULL}, - {"setType",(PyCFunction) KX_SoundActuator::sPySetType,METH_VARARGS,NULL}, - {"getType",(PyCFunction) KX_SoundActuator::sPyGetType,METH_VARARGS,NULL}, + KX_PYMETHODTABLE_NOARGS(KX_SoundActuator, startSound), + KX_PYMETHODTABLE_NOARGS(KX_SoundActuator, pauseSound), + KX_PYMETHODTABLE_NOARGS(KX_SoundActuator, stopSound), {NULL,NULL,NULL,NULL} //Sentinel }; +PyAttributeDef KX_SoundActuator::Attributes[] = { + KX_PYATTRIBUTE_RW_FUNCTION("volume", KX_SoundActuator, pyattr_get_gain, pyattr_set_gain), + KX_PYATTRIBUTE_RW_FUNCTION("pitch", KX_SoundActuator, pyattr_get_pitch, pyattr_set_pitch), + KX_PYATTRIBUTE_RW_FUNCTION("rollOffFactor", KX_SoundActuator, pyattr_get_rollOffFactor, pyattr_set_rollOffFactor), + KX_PYATTRIBUTE_ENUM_RW("mode",KX_SoundActuator::KX_SOUNDACT_NODEF+1,KX_SoundActuator::KX_SOUNDACT_MAX-1,false,KX_SoundActuator,m_type), + { NULL } //Sentinel +}; - -PyObject* KX_SoundActuator::_getattr(const STR_String& attr) -{ - _getattr_up(SCA_IActuator); -} - - - -PyObject* KX_SoundActuator::PySetFilename(PyObject* self, PyObject* args, PyObject* kwds) -{ - char *soundName = NULL; - // void *soundPointer = NULL; /*unused*/ - - if (!PyArg_ParseTuple(args, "s", &soundName)) - return NULL; - - Py_Return; -} - - - -PyObject* KX_SoundActuator::PyGetFilename(PyObject* self, PyObject* args, PyObject* kwds) +/* Methods ----------------------------------------------------------------- */ +KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, startSound, +"startSound()\n" +"\tStarts the sound.\n") { - if (!m_soundObject) + switch(AUD_getStatus(m_handle)) { - return PyString_FromString(""); + case AUD_STATUS_PLAYING: + break; + case AUD_STATUS_PAUSED: + AUD_resume(m_handle); + break; + default: + play(); } - STR_String objectname = m_soundObject->GetObjectName(); - char* name = objectname.Ptr(); - - if (!name) { - PyErr_SetString(PyExc_RuntimeError, "Unable to get sound filename"); - return NULL; - } else - return PyString_FromString(name); + Py_RETURN_NONE; } - - -PyObject* KX_SoundActuator::PyStartSound(PyObject* self, PyObject* args, PyObject* kwds) -{ - if (m_soundObject) - // This has no effect if the actuator is not active. - // To start the sound you must activate the actuator. - // This function is to restart the sound. - m_soundObject->StartSound(); - Py_Return; -} - - - -PyObject* KX_SoundActuator::PyPauseSound(PyObject* self, PyObject* args, PyObject* kwds) -{ - if (m_soundObject) - // unfortunately, openal does not implement pause correctly, it is equivalent to a stop - m_soundObject->PauseSound(); - Py_Return; -} - - - -PyObject* KX_SoundActuator::PyStopSound(PyObject* self, PyObject* args, PyObject* kwds) +KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, pauseSound, +"pauseSound()\n" +"\tPauses the sound.\n") { - if (m_soundObject) - m_soundObject->StopSound(); - Py_Return; + AUD_pause(m_handle); + Py_RETURN_NONE; } - - -PyObject* KX_SoundActuator::PySetGain(PyObject* self, PyObject* args, PyObject* kwds) +KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, stopSound, +"stopSound()\n" +"\tStops the sound.\n") { - float gain = 1.0; - if (!PyArg_ParseTuple(args, "f", &gain)) - return NULL; - - if (m_soundObject) - m_soundObject->SetGain(gain); - - Py_Return; -} - - - -PyObject* KX_SoundActuator::PyGetGain(PyObject* self, PyObject* args, PyObject* kwds) -{ - float gain = (m_soundObject) ? m_soundObject->GetGain() : 1.0f; - PyObject* result = PyFloat_FromDouble(gain); - - return result; + AUD_stop(m_handle); + Py_RETURN_NONE; } +/* Atribute setting and getting -------------------------------------------- */ - -PyObject* KX_SoundActuator::PySetPitch(PyObject* self, PyObject* args, PyObject* kwds) +PyObject* KX_SoundActuator::pyattr_get_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) { - float pitch = 1.0; - if (!PyArg_ParseTuple(args, "f", &pitch)) - return NULL; - - if (m_soundObject) - m_soundObject->SetPitch(pitch); - - Py_Return; -} - + KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); + float gain = actuator->m_volume; + PyObject* result = PyFloat_FromDouble(gain); -PyObject* KX_SoundActuator::PyGetPitch(PyObject* self, PyObject* args, PyObject* kwds) -{ - float pitch = (m_soundObject) ? m_soundObject->GetPitch() : 1.0; - PyObject* result = PyFloat_FromDouble(pitch); - return result; } - - -PyObject* KX_SoundActuator::PySetRollOffFactor(PyObject* self, PyObject* args, PyObject* kwds) +PyObject* KX_SoundActuator::pyattr_get_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) { - float rollofffactor = 1.0; - if (!PyArg_ParseTuple(args, "f", &rollofffactor)) - return NULL; - - if (m_soundObject) - m_soundObject->SetRollOffFactor(rollofffactor); - - Py_Return; -} - + KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); + float pitch = actuator->m_pitch; + PyObject* result = PyFloat_FromDouble(pitch); -PyObject* KX_SoundActuator::PyGetRollOffFactor(PyObject* self, PyObject* args, PyObject* kwds) -{ - float rollofffactor = (m_soundObject) ? m_soundObject->GetRollOffFactor() : 1.0; - PyObject* result = PyFloat_FromDouble(rollofffactor); - return result; } - - -PyObject* KX_SoundActuator::PySetLooping(PyObject* self, PyObject* args, PyObject* kwds) +PyObject* KX_SoundActuator::pyattr_get_rollOffFactor(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) { - bool looping = 1; - if (!PyArg_ParseTuple(args, "i", &looping)) - return NULL; - - if (m_soundObject) - m_soundObject->SetLoopMode(looping); - - Py_Return; -} - - + KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); + float rollofffactor = actuator->m_3d.rolloff_factor; + PyObject* result = PyFloat_FromDouble(rollofffactor); -PyObject* KX_SoundActuator::PyGetLooping(PyObject* self, PyObject* args, PyObject* kwds) -{ - int looping = (m_soundObject) ? m_soundObject->GetLoopMode() : SND_LOOP_OFF; - PyObject* result = PyInt_FromLong(looping); - return result; } - - -PyObject* KX_SoundActuator::PySetPosition(PyObject* self, PyObject* args, PyObject* kwds) +int KX_SoundActuator::pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - MT_Point3 pos; - pos[0] = 0.0; - pos[1] = 0.0; - pos[2] = 0.0; - - if (!PyArg_ParseTuple(args, "fff", &pos[0], &pos[1], &pos[2])) - return NULL; - - if (m_soundObject) - m_soundObject->SetPosition(pos); - - Py_Return; -} - - - -PyObject* KX_SoundActuator::PySetVelocity(PyObject* self, PyObject* args, PyObject* kwds) -{ - MT_Vector3 vel; - vel[0] = 0.0; - vel[1] = 0.0; - vel[2] = 0.0; - - if (!PyArg_ParseTuple(args, "fff", &vel[0], &vel[1], &vel[2])) - return NULL; - - if (m_soundObject) - m_soundObject->SetVelocity(vel); - - Py_Return; -} - + float gain = 1.0; + KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); + if (!PyArg_Parse(value, "f", &gain)) + return PY_SET_ATTR_FAIL; + actuator->m_volume = gain; + if(actuator->m_handle) + AUD_setSoundVolume(actuator->m_handle, gain); -PyObject* KX_SoundActuator::PySetOrientation(PyObject* self, PyObject* args, PyObject* kwds) -{ - MT_Matrix3x3 ori; - ori[0][0] = 1.0; - ori[0][1] = 0.0; - ori[0][2] = 0.0; - ori[1][0] = 0.0; - ori[1][1] = 1.0; - ori[1][2] = 0.0; - ori[2][0] = 0.0; - ori[2][1] = 0.0; - ori[2][2] = 1.0; - - if (!PyArg_ParseTuple(args, "fffffffff", &ori[0][0], &ori[0][1], &ori[0][2], &ori[1][0], &ori[1][1], &ori[1][2], &ori[2][0], &ori[2][1], &ori[2][2])) - return NULL; - - if (m_soundObject) - m_soundObject->SetOrientation(ori); - - Py_Return; + return PY_SET_ATTR_SUCCESS; } -PyObject* KX_SoundActuator::PySetType(PyObject* self, PyObject* args, PyObject* kwds) +int KX_SoundActuator::pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - int typeArg; - - if (!PyArg_ParseTuple(args, "i", &typeArg)) { - return NULL; - } + float pitch = 1.0; + KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); + if (!PyArg_Parse(value, "f", &pitch)) + return PY_SET_ATTR_FAIL; - if ( (typeArg > KX_SOUNDACT_NODEF) - && (typeArg < KX_SOUNDACT_MAX) ) { - m_type = (KX_SOUNDACT_TYPE) typeArg; - } + actuator->m_pitch = pitch; + if(actuator->m_handle) + AUD_setSoundPitch(actuator->m_handle, pitch); - Py_Return; + return PY_SET_ATTR_SUCCESS; } -PyObject* KX_SoundActuator::PyGetType(PyObject* self, PyObject* args, PyObject* kwds) +int KX_SoundActuator::pyattr_set_rollOffFactor(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - return PyInt_FromLong(m_type); -} - + KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); + float rollofffactor = 1.0; + if (!PyArg_Parse(value, "f", &rollofffactor)) + return PY_SET_ATTR_FAIL; + actuator->m_3d.rolloff_factor = rollofffactor; + if(actuator->m_handle) + AUD_set3DSourceSetting(actuator->m_handle, AUD_3DSS_ROLLOFF_FACTOR, rollofffactor); + return PY_SET_ATTR_SUCCESS; +} diff --git a/source/gameengine/Ketsji/KX_SoundActuator.h b/source/gameengine/Ketsji/KX_SoundActuator.h index 5a9edbc4c5e..43198f1a253 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.h +++ b/source/gameengine/Ketsji/KX_SoundActuator.h @@ -34,17 +34,34 @@ #include "SCA_IActuator.h" +#include "AUD_C-API.h" +#include "BKE_sound.h" + +typedef struct KX_3DSoundSettings +{ + float min_gain; + float max_gain; + float reference_distance; + float max_distance; + float rolloff_factor; + float cone_inner_angle; + float cone_outer_angle; + float cone_outer_gain; +} KX_3DSoundSettings; + class KX_SoundActuator : public SCA_IActuator { - Py_Header; - bool m_lastEvent; - bool m_isplaying; - /* just some handles to the audio-data... */ - class SND_SoundObject* m_soundObject; - class SND_Scene* m_soundScene; - short m_startFrame; - short m_endFrame; - bool m_pino; + Py_Header; + bool m_isplaying; + AUD_Sound* m_sound; + float m_volume; + float m_pitch; + bool m_is3d; + KX_3DSoundSettings m_3d; + AUD_Handle* m_handle; + + void play(); + public: enum KX_SOUNDACT_TYPE @@ -62,44 +79,37 @@ public: KX_SOUNDACT_TYPE m_type; KX_SoundActuator(SCA_IObject* gameobj, - class SND_SoundObject* sndobj, - class SND_Scene* sndscene, - KX_SOUNDACT_TYPE type, - short start, - short end, - PyTypeObject* T=&Type); + AUD_Sound* sound, + float volume, + float pitch, + bool is3d, + KX_3DSoundSettings settings, + KX_SOUNDACT_TYPE type); ~KX_SoundActuator(); - void setSoundObject(class SND_SoundObject* soundobject); virtual bool Update(double curtime, bool frame); CValue* GetReplica(); + void ProcessReplica(); /* -------------------------------------------------------------------- */ /* Python interface --------------------------------------------------- */ /* -------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); - - KX_PYMETHOD(KX_SoundActuator,SetFilename); - KX_PYMETHOD(KX_SoundActuator,GetFilename); - KX_PYMETHOD(KX_SoundActuator,StartSound); - KX_PYMETHOD(KX_SoundActuator,PauseSound); - KX_PYMETHOD(KX_SoundActuator,StopSound); - KX_PYMETHOD(KX_SoundActuator,SetGain); - KX_PYMETHOD(KX_SoundActuator,GetGain); - KX_PYMETHOD(KX_SoundActuator,SetPitch); - KX_PYMETHOD(KX_SoundActuator,GetPitch); - KX_PYMETHOD(KX_SoundActuator,SetRollOffFactor); - KX_PYMETHOD(KX_SoundActuator,GetRollOffFactor); - KX_PYMETHOD(KX_SoundActuator,SetLooping); - KX_PYMETHOD(KX_SoundActuator,GetLooping); - KX_PYMETHOD(KX_SoundActuator,SetPosition); - KX_PYMETHOD(KX_SoundActuator,SetVelocity); - KX_PYMETHOD(KX_SoundActuator,SetOrientation); - KX_PYMETHOD(KX_SoundActuator,SetType); - KX_PYMETHOD(KX_SoundActuator,GetType); + KX_PYMETHOD_DOC_NOARGS(KX_SoundActuator, startSound); + KX_PYMETHOD_DOC_NOARGS(KX_SoundActuator, pauseSound); + KX_PYMETHOD_DOC_NOARGS(KX_SoundActuator, stopSound); + + static int pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_rollOffFactor(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_type(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject* pyattr_get_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_rollOffFactor(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_type(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); }; #endif //__KX_SOUNDACTUATOR diff --git a/source/gameengine/Ketsji/KX_StateActuator.cpp b/source/gameengine/Ketsji/KX_StateActuator.cpp index e360c4bac1f..4159e9c373d 100644 --- a/source/gameengine/Ketsji/KX_StateActuator.cpp +++ b/source/gameengine/Ketsji/KX_StateActuator.cpp @@ -38,10 +38,9 @@ KX_StateActuator::KX_StateActuator( SCA_IObject* gameobj, int operation, - unsigned int mask, - PyTypeObject* T + unsigned int mask ) - : SCA_IActuator(gameobj,T), + : SCA_IActuator(gameobj), m_operation(operation), m_mask(mask) { @@ -55,6 +54,9 @@ KX_StateActuator::~KX_StateActuator( // intentionally empty } +// used to put state actuator to be executed before any other actuators +SG_QList KX_StateActuator::m_stateActuatorHead; + CValue* KX_StateActuator::GetReplica( void @@ -62,8 +64,6 @@ KX_StateActuator::GetReplica( { KX_StateActuator* replica = new KX_StateActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; } @@ -72,7 +72,10 @@ KX_StateActuator::Update() { bool bNegativeEvent = IsNegativeEvent(); unsigned int objMask; - + + // execution of state actuator means that we are in the execution phase, reset this pointer + // because all the active actuator of this object will be removed for sure. + m_gameobj->m_firstState = NULL; RemoveAllEvents(); if (bNegativeEvent) return false; @@ -101,6 +104,31 @@ KX_StateActuator::Update() return false; } +// this function is only used to deactivate actuators outside the logic loop +// e.g. when an object is deleted. +void KX_StateActuator::Deactivate() +{ + if (QDelink()) + { + // the actuator was in the active list + if (m_stateActuatorHead.QEmpty()) + // no more state object active + m_stateActuatorHead.Delink(); + } +} + +void KX_StateActuator::Activate(SG_DList& head) +{ + // sort the state actuators per object on the global list + if (QEmpty()) + { + InsertSelfActiveQList(m_stateActuatorHead, &m_gameobj->m_firstState); + // add front to make sure it runs before other actuators + head.AddFront(&m_stateActuatorHead); + } +} + + /* ------------------------------------------------------------------------- */ /* Python functions */ /* ------------------------------------------------------------------------- */ @@ -108,100 +136,34 @@ KX_StateActuator::Update() /* Integration hooks ------------------------------------------------------- */ -PyTypeObject -KX_StateActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, +PyTypeObject KX_StateActuator::Type = { + PyVarObject_HEAD_INIT(NULL, 0) "KX_StateActuator", - sizeof(KX_StateActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject -KX_StateActuator::Parents[] = { - &KX_StateActuator::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; -PyMethodDef -KX_StateActuator::Methods[] = { - {"setOperation", (PyCFunction) KX_StateActuator::sPySetOperation, - METH_VARARGS, (PY_METHODCHAR)SetOperation_doc}, - {"setMask", (PyCFunction) KX_StateActuator::sPySetMask, - METH_VARARGS, (PY_METHODCHAR)SetMask_doc}, +PyMethodDef KX_StateActuator::Methods[] = { {NULL,NULL} //Sentinel }; -PyObject* -KX_StateActuator::_getattr( - const STR_String& attr - ) -{ - _getattr_up(SCA_IActuator); +PyAttributeDef KX_StateActuator::Attributes[] = { + KX_PYATTRIBUTE_INT_RW("operation",KX_StateActuator::OP_NOP+1,KX_StateActuator::OP_COUNT-1,false,KX_StateActuator,m_operation), + KX_PYATTRIBUTE_INT_RW("mask",0,0x3FFFFFFF,false,KX_StateActuator,m_mask), + { NULL } //Sentinel }; - - - -/* set operation ---------------------------------------------------------- */ -const char -KX_StateActuator::SetOperation_doc[] = -"setOperation(op)\n" -"\t - op : bit operation (0=Copy, 1=Set, 2=Clear, 3=Negate)" -"\tSet the type of bit operation to be applied on object state mask.\n" -"\tUse setMask() to specify the bits that will be modified.\n"; -PyObject* - -KX_StateActuator::PySetOperation(PyObject* self, - PyObject* args, - PyObject* kwds) { - int oper; - - if(!PyArg_ParseTuple(args, "i", &oper)) { - return NULL; - } - - m_operation = oper; - - Py_Return; -} - -/* set mask ---------------------------------------------------------- */ -const char -KX_StateActuator::SetMask_doc[] = -"setMask(mask)\n" -"\t - mask : bits that will be modified" -"\tSet the value that defines the bits that will be modified by the operation.\n" -"\tThe bits that are 1 in the value will be updated in the object state,\n" -"\tthe bits that are 0 are will be left unmodified expect for the Copy operation\n" -"\twhich copies the value to the object state.\n"; -PyObject* - -KX_StateActuator::PySetMask(PyObject* self, - PyObject* args, - PyObject* kwds) { - int mask; - - if(!PyArg_ParseTuple(args, "i", &mask)) { - return NULL; - } - - m_mask = mask; - - Py_Return; -} - - diff --git a/source/gameengine/Ketsji/KX_StateActuator.h b/source/gameengine/Ketsji/KX_StateActuator.h index 8698e51b2c1..4cf84f74287 100644 --- a/source/gameengine/Ketsji/KX_StateActuator.h +++ b/source/gameengine/Ketsji/KX_StateActuator.h @@ -33,28 +33,41 @@ #include "SCA_IActuator.h" + +/* + * Use of SG_DList : element of actuator being deactivated + * Head: SCA_LogicManager::m_removedActuators + * Use of SG_QList : element of global activated state actuator list + * Head: KX_StateActuator::m_stateActuatorHead + */ class KX_StateActuator : public SCA_IActuator { Py_Header; /** Make visible? */ enum { + OP_NOP = -1, OP_CPY = 0, OP_SET, OP_CLR, - OP_NEG + OP_NEG, + OP_COUNT }; + // SG_Dlist: element of objects with active actuators, always put in front of the list + // Head: SCA_LogicManager::m_activeActuators + // SG_QList: Head of active state actuators list globally + // Elements: KX_StateActuator + static SG_QList m_stateActuatorHead; int m_operation; - unsigned int m_mask; + int m_mask; public: KX_StateActuator( SCA_IObject* gameobj, int operation, - unsigned int mask, - PyTypeObject* T=&Type - ); + unsigned int mask + ); virtual ~KX_StateActuator( @@ -69,14 +82,13 @@ class KX_StateActuator : public SCA_IActuator virtual bool Update(); + virtual void Deactivate(); + virtual void Activate(SG_DList& head); + /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); - //KX_PYMETHOD_DOC - KX_PYMETHOD_DOC(KX_StateActuator,SetOperation); - KX_PYMETHOD_DOC(KX_StateActuator,SetMask); }; #endif diff --git a/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp b/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp deleted file mode 100644 index c842ca1ee14..00000000000 --- a/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include "KX_ConvertPhysicsObject.h" - -#ifdef USE_SUMO_SOLID - -#ifdef WIN32 -#pragma warning (disable : 4786) -#endif - -#include "KX_SumoPhysicsController.h" -#include "SG_Spatial.h" -#include "SM_Scene.h" -#include "KX_GameObject.h" -#include "KX_MotionState.h" -#include "KX_ClientObjectInfo.h" - -#include "PHY_IPhysicsEnvironment.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -void KX_SumoPhysicsController::applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse) -{ - SumoPhysicsController::applyImpulse(attach[0],attach[1],attach[2],impulse[0],impulse[1],impulse[2]); -} -void KX_SumoPhysicsController::RelativeTranslate(const MT_Vector3& dloc,bool local) -{ - SumoPhysicsController::RelativeTranslate(dloc[0],dloc[1],dloc[2],local); - -} -void KX_SumoPhysicsController::RelativeRotate(const MT_Matrix3x3& drot,bool local) -{ - float oldmat[12]; - drot.getValue(oldmat); -/* float newmat[9]; - float *m = &newmat[0]; - double *orgm = &oldmat[0]; - - *m++ = *orgm++;*m++ = *orgm++;*m++ = *orgm++;orgm++; - *m++ = *orgm++;*m++ = *orgm++;*m++ = *orgm++;orgm++; - *m++ = *orgm++;*m++ = *orgm++;*m++ = *orgm++;orgm++; */ - - SumoPhysicsController::RelativeRotate(oldmat,local); -} - -void KX_SumoPhysicsController::SetLinearVelocity(const MT_Vector3& lin_vel,bool local) -{ - SumoPhysicsController::SetLinearVelocity(lin_vel[0],lin_vel[1],lin_vel[2],local); - -} - -void KX_SumoPhysicsController::SetAngularVelocity(const MT_Vector3& ang_vel,bool local) -{ - SumoPhysicsController::SetAngularVelocity(ang_vel[0],ang_vel[1],ang_vel[2],local); -} - -MT_Vector3 KX_SumoPhysicsController::GetVelocity(const MT_Point3& pos) -{ - - float linvel[3]; - SumoPhysicsController::GetVelocity(pos[0],pos[1],pos[2],linvel[0],linvel[1],linvel[2]); - - return MT_Vector3 (linvel); -} - -MT_Vector3 KX_SumoPhysicsController::GetLinearVelocity() -{ - return GetVelocity(MT_Point3(0,0,0)); - -} - -void KX_SumoPhysicsController::resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) -{ - SumoPhysicsController::resolveCombinedVelocities(linvelX,linvelY,linvelZ,angVelX,angVelY,angVelZ); -} - -void KX_SumoPhysicsController::ApplyTorque(const MT_Vector3& torque,bool local) -{ - SumoPhysicsController::ApplyTorque(torque[0],torque[1],torque[2],local); - -} - -void KX_SumoPhysicsController::ApplyForce(const MT_Vector3& force,bool local) -{ - SumoPhysicsController::ApplyForce(force[0],force[1],force[2],local); -} - -bool KX_SumoPhysicsController::Update(double time) -{ - return SynchronizeMotionStates(time); -} - -void KX_SumoPhysicsController::SetSimulatedTime(double time) -{ - -} - -void KX_SumoPhysicsController::SetSumoTransform(bool nondynaonly) -{ - SumoPhysicsController::setSumoTransform(nondynaonly); - -} - -void KX_SumoPhysicsController::SuspendDynamics(bool) -{ - SumoPhysicsController::SuspendDynamics(); -} - -void KX_SumoPhysicsController::RestoreDynamics() -{ - SumoPhysicsController::RestoreDynamics(); -} - -SG_Controller* KX_SumoPhysicsController::GetReplica(SG_Node* destnode) -{ - - PHY_IMotionState* motionstate = new KX_MotionState(destnode); - - KX_SumoPhysicsController* physicsreplica = new KX_SumoPhysicsController(*this); - - //parentcontroller is here be able to avoid collisions between parent/child - - PHY_IPhysicsController* parentctrl = NULL; - - if (destnode != destnode->GetRootSGParent()) - { - KX_GameObject* clientgameobj = (KX_GameObject*) destnode->GetRootSGParent()->GetSGClientObject(); - if (clientgameobj) - { - parentctrl = (KX_SumoPhysicsController*)clientgameobj->GetPhysicsController(); - } else - { - // it could be a false node, try the children - NodeList::const_iterator childit; - for ( - childit = destnode->GetSGChildren().begin(); - childit!= destnode->GetSGChildren().end(); - ++childit - ) { - KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); - if (clientgameobj) - { - parentctrl = (KX_SumoPhysicsController*)clientgameobj->GetPhysicsController(); - } - } - } - } - - physicsreplica->PostProcessReplica(motionstate,parentctrl); - - return physicsreplica; -} - - -void KX_SumoPhysicsController::SetObject (SG_IObject* object) -{ - SG_Controller::SetObject(object); - - // cheating here... -//should not be necessary, is it for duplicates ? - -KX_GameObject* gameobj = (KX_GameObject*) object->GetSGClientObject(); -gameobj->SetPhysicsController(this,gameobj->IsDynamic()); -GetSumoObject()->setClientObject(gameobj->getClientInfo()); -} - -void KX_SumoPhysicsController::setMargin(float collisionMargin) -{ - SumoPhysicsController::SetMargin(collisionMargin); -} - - -void KX_SumoPhysicsController::setOrientation(const MT_Matrix3x3& rot) -{ - MT_Quaternion orn = rot.getRotation(); - SumoPhysicsController::setOrientation( - orn[0],orn[1],orn[2],orn[3]); - -} -void KX_SumoPhysicsController::getOrientation(MT_Quaternion& orn) -{ - - float quat[4]; - - SumoPhysicsController::getOrientation(quat[0],quat[1],quat[2],quat[3]); - - orn = MT_Quaternion(quat); - -} - -void KX_SumoPhysicsController::setPosition(const MT_Point3& pos) -{ - SumoPhysicsController::setPosition(pos[0],pos[1],pos[2]); - -} - -void KX_SumoPhysicsController::setScaling(const MT_Vector3& scaling) -{ - SumoPhysicsController::setScaling(scaling[0],scaling[1],scaling[2]); - -} - -MT_Scalar KX_SumoPhysicsController::GetMass() -{ - return SumoPhysicsController::getMass(); -} - -MT_Scalar KX_SumoPhysicsController::GetRadius() -{ - return SumoPhysicsController::GetRadius(); -} - -MT_Vector3 KX_SumoPhysicsController::getReactionForce() -{ - float force[3]; - SumoPhysicsController::getReactionForce(force[0],force[1],force[2]); - return MT_Vector3(force); - -} - -void KX_SumoPhysicsController::setRigidBody(bool rigid) -{ - SumoPhysicsController::setRigidBody(rigid); - -} - - -KX_SumoPhysicsController::~KX_SumoPhysicsController() -{ - - -} - - -#endif//USE_SUMO_SOLID diff --git a/source/gameengine/Ketsji/KX_SumoPhysicsController.h b/source/gameengine/Ketsji/KX_SumoPhysicsController.h deleted file mode 100644 index abe48d99043..00000000000 --- a/source/gameengine/Ketsji/KX_SumoPhysicsController.h +++ /dev/null @@ -1,112 +0,0 @@ -/** - * $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ -#ifndef __KX_SUMOPHYSICSCONTROLLER_H -#define __KX_SUMOPHYSICSCONTROLLER_H - -#include "PHY_IPhysicsController.h" - -/** - Physics Controller, a special kind of Scene Graph Transformation Controller. - It get's callbacks from Sumo in case a transformation change took place. - Each time the scene graph get's updated, the controller get's a chance - in the 'Update' method to reflect changed. -*/ - -#include "SumoPhysicsController.h" -#include "KX_IPhysicsController.h" - -class KX_SumoPhysicsController : public KX_IPhysicsController, - public SumoPhysicsController - -{ - - -public: - KX_SumoPhysicsController( - class SM_Scene* sumoScene, - class SM_Object* sumoObj, - class PHY_IMotionState* motionstate - ,bool dyna) - : KX_IPhysicsController(dyna,NULL) , - SumoPhysicsController(sumoScene,/*solidscene,*/sumoObj,motionstate,dyna) - { - }; - virtual ~KX_SumoPhysicsController(); - - void applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse); - virtual void SetObject (SG_IObject* object); - virtual void setMargin (float collisionMargin); - - void RelativeTranslate(const MT_Vector3& dloc,bool local); - void RelativeRotate(const MT_Matrix3x3& drot,bool local); - void ApplyTorque(const MT_Vector3& torque,bool local); - void ApplyForce(const MT_Vector3& force,bool local); - MT_Vector3 GetLinearVelocity(); - MT_Vector3 GetAngularVelocity() // to keep compiler happy - { return MT_Vector3(0.0,0.0,0.0); } - MT_Vector3 GetVelocity(const MT_Point3& pos); - void SetAngularVelocity(const MT_Vector3& ang_vel,bool local); - void SetLinearVelocity(const MT_Vector3& lin_vel,bool local); - void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ); - - - void SuspendDynamics(bool); - void RestoreDynamics(); - virtual void getOrientation(MT_Quaternion& orn); - virtual void setOrientation(const MT_Matrix3x3& orn); - - virtual void setPosition(const MT_Point3& pos); - virtual void setScaling(const MT_Vector3& scaling); - virtual MT_Scalar GetMass(); - virtual MT_Scalar GetRadius(); - virtual MT_Vector3 getReactionForce(); - virtual void setRigidBody(bool rigid); - - - virtual SG_Controller* GetReplica(class SG_Node* destnode); - - - void SetSumoTransform(bool nondynaonly); - // todo: remove next line ! - virtual void SetSimulatedTime(double time); - - // call from scene graph to update - virtual bool Update(double time); - - void - SetOption( - int option, - int value - ){ - // intentionally empty - }; -}; - -#endif //__KX_SUMOPHYSICSCONTROLLER_H - diff --git a/source/gameengine/Ketsji/KX_TimeCategoryLogger.h b/source/gameengine/Ketsji/KX_TimeCategoryLogger.h index 0cc34b53736..fe15967f93c 100644 --- a/source/gameengine/Ketsji/KX_TimeCategoryLogger.h +++ b/source/gameengine/Ketsji/KX_TimeCategoryLogger.h @@ -125,6 +125,12 @@ protected: /** Maximum number of measurements. */ unsigned int m_maxNumMeasurements; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_TimeCategoryLogger"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // __KX_TIME_CATEGORY_LOGGER_H diff --git a/source/gameengine/Ketsji/KX_TimeLogger.h b/source/gameengine/Ketsji/KX_TimeLogger.h index 0962f02a877..2e73abc75b5 100644 --- a/source/gameengine/Ketsji/KX_TimeLogger.h +++ b/source/gameengine/Ketsji/KX_TimeLogger.h @@ -36,6 +36,10 @@ #include <deque> +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + /** * Stores and manages time measurements. */ @@ -98,6 +102,13 @@ protected: /** State of logging. */ bool m_logging; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_TimeLogger"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // __KX_TIME_LOGGER_H diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp index 48d4cf59a2b..712a512995e 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp +++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp @@ -85,14 +85,35 @@ bool KX_TouchEventManager::newBroadphaseResponse(void *client_data, PHY_IPhysicsController* ctrl = static_cast<PHY_IPhysicsController*>(object1); KX_ClientObjectInfo* info = (ctrl) ? static_cast<KX_ClientObjectInfo*>(ctrl->getNewClientInfo()) : NULL; // This call back should only be called for controllers of Near and Radar sensor - if (info && - info->m_sensors.size() == 1 && - (info->m_type == KX_ClientObjectInfo::NEAR || - info->m_type == KX_ClientObjectInfo::RADAR)) + if (!info) + return true; + + switch (info->m_type) { - // only one sensor for this type of object - KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(*info->m_sensors.begin()); - return touchsensor->BroadPhaseFilterCollision(object1,object2); + case KX_ClientObjectInfo::SENSOR: + if (info->m_sensors.size() == 1) + { + // only one sensor for this type of object + KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(*info->m_sensors.begin()); + return touchsensor->BroadPhaseFilterCollision(object1,object2); + } + break; + case KX_ClientObjectInfo::OBSENSOR: + case KX_ClientObjectInfo::OBACTORSENSOR: + // this object may have multiple collision sensors, + // check is any of them is interested in this object + for(std::list<SCA_ISensor*>::iterator it = info->m_sensors.begin(); + it != info->m_sensors.end(); + ++it) + { + if ((*it)->GetSensorType() == SCA_ISensor::ST_TOUCH) + { + KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(*it); + if (touchsensor->BroadPhaseSensorFilterCollision(object1, object2)) + return true; + } + } + return false; } return true; } @@ -100,7 +121,7 @@ bool KX_TouchEventManager::newBroadphaseResponse(void *client_data, void KX_TouchEventManager::RegisterSensor(SCA_ISensor* sensor) { KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(sensor); - if (m_sensors.insert(touchsensor).second) + if (m_sensors.AddBack(touchsensor)) // the sensor was effectively inserted, register it touchsensor->RegisterSumo(this); } @@ -108,7 +129,7 @@ void KX_TouchEventManager::RegisterSensor(SCA_ISensor* sensor) void KX_TouchEventManager::RemoveSensor(SCA_ISensor* sensor) { KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(sensor); - if (m_sensors.erase(touchsensor)) + if (touchsensor->Delink()) // the sensor was effectively removed, unregister it touchsensor->UnregisterSumo(this); } @@ -117,12 +138,10 @@ void KX_TouchEventManager::RemoveSensor(SCA_ISensor* sensor) void KX_TouchEventManager::EndFrame() { - set<SCA_ISensor*>::iterator it; - for ( it = m_sensors.begin(); - !(it==m_sensors.end());it++) + SG_DList::iterator<KX_TouchSensor> it(m_sensors); + for (it.begin();!it.end();++it) { - ((KX_TouchSensor*)*it)->EndFrame(); - + (*it)->EndFrame(); } } @@ -130,12 +149,11 @@ void KX_TouchEventManager::EndFrame() void KX_TouchEventManager::NextFrame() { - if (m_sensors.size() > 0) + if (!m_sensors.Empty()) { - set<SCA_ISensor*>::iterator it; - - for (it = m_sensors.begin();!(it==m_sensors.end());++it) - static_cast<KX_TouchSensor*>(*it)->SynchronizeTransform(); + SG_DList::iterator<KX_TouchSensor> it(m_sensors); + for (it.begin();!it.end();++it) + (*it)->SynchronizeTransform(); for (std::set<NewCollision>::iterator cit = m_newCollisions.begin(); cit != m_newCollisions.end(); ++cit) { @@ -161,7 +179,7 @@ void KX_TouchEventManager::NextFrame() m_newCollisions.clear(); - for (it = m_sensors.begin();!(it==m_sensors.end());++it) - (*it)->Activate(m_logicmgr,NULL); + for (it.begin();!it.end();++it) + (*it)->Activate(m_logicmgr); } } diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.h b/source/gameengine/Ketsji/KX_TouchEventManager.h index cc77bccfc31..6da37d615a4 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.h +++ b/source/gameengine/Ketsji/KX_TouchEventManager.h @@ -76,6 +76,12 @@ public: SCA_LogicManager* GetLogicManager() { return m_logicmgr;} PHY_IPhysicsEnvironment *GetPhysicsEnvironment() { return m_physEnv; } + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_TouchEventManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_TOUCHEVENTMANAGER diff --git a/source/gameengine/Ketsji/KX_TouchSensor.cpp b/source/gameengine/Ketsji/KX_TouchSensor.cpp index 1935a0bde39..cde67787e2f 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.cpp +++ b/source/gameengine/Ketsji/KX_TouchSensor.cpp @@ -34,7 +34,9 @@ #include "SCA_LogicManager.h" #include "KX_GameObject.h" #include "KX_TouchEventManager.h" -#include "KX_SumoPhysicsController.h" + +#include "PHY_IPhysicsController.h" + #include <iostream> #include "PHY_IPhysicsEnvironment.h" @@ -57,20 +59,20 @@ void KX_TouchSensor::EndFrame() { m_colliders->ReleaseAndRemoveAll(); m_hitObject = NULL; m_bTriggered = false; + m_bColliderHash = 0; } void KX_TouchSensor::UnregisterToManager() { // before unregistering the sensor, make sure we release all references EndFrame(); - m_eventmgr->RemoveSensor(this); + SCA_ISensor::UnregisterToManager(); } -bool KX_TouchSensor::Evaluate(CValue* event) +bool KX_TouchSensor::Evaluate() { bool result = false; bool reset = m_reset && m_level; - m_reset = false; if (m_bTriggered != m_bLastTriggered) { @@ -82,14 +84,24 @@ bool KX_TouchSensor::Evaluate(CValue* event) if (reset) // force an event result = true; + + if (m_bTouchPulse) { /* pulse on changes to the colliders */ + int count = m_colliders->GetCount(); + + if (m_bLastCount!=count || m_bColliderHash!=m_bLastColliderHash) { + m_bLastCount = count; + m_bLastColliderHash= m_bColliderHash; + result = true; + } + } return result; } -KX_TouchSensor::KX_TouchSensor(SCA_EventManager* eventmgr,KX_GameObject* gameobj,bool bFindMaterial,const STR_String& touchedpropname,PyTypeObject* T) -:SCA_ISensor(gameobj,eventmgr,T), +KX_TouchSensor::KX_TouchSensor(SCA_EventManager* eventmgr,KX_GameObject* gameobj,bool bFindMaterial,bool bTouchPulse,const STR_String& touchedpropname) +:SCA_ISensor(gameobj,eventmgr), m_touchedpropname(touchedpropname), m_bFindMaterial(bFindMaterial), -m_eventmgr(eventmgr) +m_bTouchPulse(bTouchPulse) /*m_sumoObj(sumoObj),*/ { // KX_TouchEventManager* touchmgr = (KX_TouchEventManager*) eventmgr; @@ -100,8 +112,8 @@ m_eventmgr(eventmgr) m_colliders = new CListValue(); KX_ClientObjectInfo *client_info = gameobj->getClientInfo(); - client_info->m_gameobject = gameobj; - client_info->m_auxilary_info = NULL; + //client_info->m_gameobject = gameobj; + //client_info->m_auxilary_info = NULL; client_info->m_sensors.push_back(this); m_physCtrl = dynamic_cast<PHY_IPhysicsController*>(gameobj->GetPhysicsController()); @@ -114,6 +126,8 @@ void KX_TouchSensor::Init() m_bCollision = false; m_bTriggered = false; m_bLastTriggered = (m_invert)?true:false; + m_bLastCount = 0; + m_bColliderHash = m_bLastColliderHash = 0; m_hitObject = NULL; m_reset = true; } @@ -127,13 +141,17 @@ KX_TouchSensor::~KX_TouchSensor() CValue* KX_TouchSensor::GetReplica() { KX_TouchSensor* replica = new KX_TouchSensor(*this); - replica->m_colliders = new CListValue(); - replica->Init(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); + replica->ProcessReplica(); return replica; } +void KX_TouchSensor::ProcessReplica() +{ + SCA_ISensor::ProcessReplica(); + m_colliders = new CListValue(); + Init(); +} + void KX_TouchSensor::ReParent(SCA_IObject* parent) { KX_GameObject *gameobj = static_cast<KX_GameObject *>(parent); @@ -143,8 +161,8 @@ void KX_TouchSensor::ReParent(SCA_IObject* parent) // m_solidHandle = m_sumoObj->getObjectHandle(); KX_ClientObjectInfo *client_info = gameobj->getClientInfo(); - client_info->m_gameobject = gameobj; - client_info->m_auxilary_info = NULL; + //client_info->m_gameobject = gameobj; + //client_info->m_auxilary_info = NULL; client_info->m_sensors.push_back(this); SCA_ISensor::ReParent(parent); @@ -154,19 +172,67 @@ void KX_TouchSensor::RegisterSumo(KX_TouchEventManager *touchman) { if (m_physCtrl) { - touchman->GetPhysicsEnvironment()->requestCollisionCallback(m_physCtrl); - // collision - // Deprecated - + if (touchman->GetPhysicsEnvironment()->requestCollisionCallback(m_physCtrl)) + { + KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>(m_physCtrl->getNewClientInfo()); + if (client_info->isSensor()) + touchman->GetPhysicsEnvironment()->addSensor(m_physCtrl); + } } } - void KX_TouchSensor::UnregisterSumo(KX_TouchEventManager* touchman) { if (m_physCtrl) { - touchman->GetPhysicsEnvironment()->removeCollisionCallback(m_physCtrl); + if (touchman->GetPhysicsEnvironment()->removeCollisionCallback(m_physCtrl)) + { + // no more sensor on the controller, can remove it if it is a sensor object + KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>(m_physCtrl->getNewClientInfo()); + if (client_info->isSensor()) + touchman->GetPhysicsEnvironment()->removeSensor(m_physCtrl); + } + } +} + +// this function is called only for sensor objects +// return true if the controller can collide with the object +bool KX_TouchSensor::BroadPhaseSensorFilterCollision(void*obj1,void*obj2) +{ + assert(obj1==m_physCtrl && obj2); + + KX_GameObject* myobj = (KX_GameObject*)GetParent(); + KX_GameObject* myparent = myobj->GetParent(); + KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>(((PHY_IPhysicsController*)obj2)->getNewClientInfo()); + KX_ClientObjectInfo* my_client_info = static_cast<KX_ClientObjectInfo*>(m_physCtrl->getNewClientInfo()); + KX_GameObject* otherobj = ( client_info ? client_info->m_gameobject : NULL); + + // first, decrement refcount as GetParent() increases it + if (myparent) + myparent->Release(); + + // we can only check on persistent characteristic: m_link and m_suspended are not + // good candidate because they are transient. That must be handled at another level + if (!otherobj || + otherobj == myparent || // don't interact with our parent + (my_client_info->m_type == KX_ClientObjectInfo::OBACTORSENSOR && + client_info->m_type != KX_ClientObjectInfo::ACTOR)) // only with actor objects + return false; + + bool found = m_touchedpropname.IsEmpty(); + if (!found) + { + if (m_bFindMaterial) + { + if (client_info->m_auxilary_info) + { + found = (!strcmp(m_touchedpropname.Ptr(), (char*)client_info->m_auxilary_info)); + } + } else + { + found = (otherobj->GetProperty(m_touchedpropname) != NULL); + } } + return found; } bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_CollData* colldata) @@ -189,8 +255,6 @@ bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_Coll if (m_links && !m_suspended && gameobj && (gameobj != parent) && client_info->isActor()) { - if (!m_colliders->SearchValue(gameobj)) - m_colliders->Add(gameobj->AddRef()); bool found = m_touchedpropname.IsEmpty(); if (!found) @@ -199,7 +263,7 @@ bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_Coll { if (client_info->m_auxilary_info) { - found = (m_touchedpropname == STR_String((char*)client_info->m_auxilary_info)); + found = (!strcmp(m_touchedpropname.Ptr(), (char*)client_info->m_auxilary_info)); } } else { @@ -208,13 +272,19 @@ bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_Coll } if (found) { + if (!m_colliders->SearchValue(gameobj)) { + m_colliders->Add(gameobj->AddRef()); + + if (m_bTouchPulse) + m_bColliderHash += (uint_ptr)(static_cast<void *>(&gameobj)); + } m_bTriggered = true; m_hitObject = gameobj; //printf("KX_TouchSensor::HandleCollision\n"); } } - return DT_CONTINUE; + return false; // was DT_CONTINUE but this was defined in sumo as false. } @@ -223,186 +293,56 @@ bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_Coll /* ------------------------------------------------------------------------- */ /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_TouchSensor::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_TouchSensor", - sizeof(KX_TouchSensor), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_TouchSensor::Parents[] = { - &KX_TouchSensor::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_ISensor::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_TouchSensor::Methods[] = { - {"setProperty", - (PyCFunction) KX_TouchSensor::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, - {"getProperty", - (PyCFunction) KX_TouchSensor::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, - {"getHitObject", - (PyCFunction) KX_TouchSensor::sPyGetHitObject, METH_VARARGS, (PY_METHODCHAR)GetHitObject_doc}, - {"getHitObjectList", - (PyCFunction) KX_TouchSensor::sPyGetHitObjectList, METH_VARARGS, (PY_METHODCHAR)GetHitObjectList_doc}, {NULL,NULL} //Sentinel }; -PyObject* KX_TouchSensor::_getattr(const STR_String& attr) { - _getattr_up(SCA_ISensor); -} +PyAttributeDef KX_TouchSensor::Attributes[] = { + KX_PYATTRIBUTE_STRING_RW("propName",0,100,false,KX_TouchSensor,m_touchedpropname), + KX_PYATTRIBUTE_BOOL_RW("useMaterial",KX_TouchSensor,m_bFindMaterial), + KX_PYATTRIBUTE_BOOL_RW("usePulseCollision",KX_TouchSensor,m_bTouchPulse), + KX_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_TouchSensor, pyattr_get_object_hit), + KX_PYATTRIBUTE_RO_FUNCTION("hitObjectList", KX_TouchSensor, pyattr_get_object_hit_list), + { NULL } //Sentinel +}; /* Python API */ -/* 1. setProperty */ -const char KX_TouchSensor::SetProperty_doc[] = -"setProperty(name)\n" -"\t- name: string\n" -"\tSet the property or material to collide with. Use\n" -"\tsetTouchMaterial() to switch between properties and\n" -"\tmaterials."; -PyObject* KX_TouchSensor::PySetProperty(PyObject* self, - PyObject* args, - PyObject* kwds) { - char *nameArg; - if (!PyArg_ParseTuple(args, "s", &nameArg)) { - return NULL; - } - - CValue* prop = GetParent()->FindIdentifier(nameArg); - - if (!prop->IsError()) { - m_touchedpropname = nameArg; - } else { - ; /* not found ... */ - } - prop->Release(); - - Py_Return; -} -/* 2. getProperty */ -const char KX_TouchSensor::GetProperty_doc[] = -"getProperty(name)\n" -"\tReturns the property or material to collide with. Use\n" -"\tgetTouchMaterial() to find out whether this sensor\n" -"\tlooks for properties or materials."; -PyObject* KX_TouchSensor::PyGetProperty(PyObject* self, - PyObject* args, - PyObject* kwds) { - return PyString_FromString(m_touchedpropname); -} - -const char KX_TouchSensor::GetHitObject_doc[] = -"getHitObject()\n" -; -PyObject* KX_TouchSensor::PyGetHitObject(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - /* to do: do Py_IncRef if the object is already known in Python */ - /* otherwise, this leaks memory */ - if (m_hitObject) - { - return m_hitObject->AddRef(); - } - Py_Return; -} - -const char KX_TouchSensor::GetHitObjectList_doc[] = -"getHitObjectList()\n" -"\tReturn a list of the objects this object collided with,\n" -"\tbut only those matching the property/material condition.\n"; -PyObject* KX_TouchSensor::PyGetHitObjectList(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_TouchSensor::pyattr_get_object_hit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - - /* to do: do Py_IncRef if the object is already known in Python */ - /* otherwise, this leaks memory */ - - if ( m_touchedpropname.IsEmpty() ) { - return m_colliders->AddRef(); - } else { - CListValue* newList = new CListValue(); - int i = 0; - while (i < m_colliders->GetCount()) { - if (m_bFindMaterial) { - /* need to associate the CValues from the list to material - * names. The collider list _should_ contains only - * KX_GameObjects. I am loathe to cast them, though... The - * material name must be retrieved from Sumo. To a Sumo - * object, a client-info block is attached. This block - * contains the material name. - * - this also doesn't work (obviously) for multi-materials... - */ - KX_GameObject* gameob = (KX_GameObject*) m_colliders->GetValue(i); - PHY_IPhysicsController* spc = dynamic_cast<PHY_IPhysicsController*>(gameob->GetPhysicsController()); - - if (spc) { - KX_ClientObjectInfo* cl_inf = static_cast<KX_ClientObjectInfo*>(spc->getNewClientInfo()); - - if (m_touchedpropname == ((char*)cl_inf->m_auxilary_info)) { - newList->Add(m_colliders->GetValue(i)->AddRef()); - } - } - - } else { - CValue* val = m_colliders->GetValue(i)->FindIdentifier(m_touchedpropname); - if (!val->IsError()) { - newList->Add(m_colliders->GetValue(i)->AddRef()); - } - val->Release(); - } - - i++; - } - return newList->AddRef(); - } - -} - -/* 5. getTouchMaterial */ -const char KX_TouchSensor::GetTouchMaterial_doc[] = -"getTouchMaterial()\n" -"\tReturns KX_TRUE if this sensor looks for a specific material,\n" -"\tKX_FALSE if it looks for a specific property.\n" ; -PyObject* KX_TouchSensor::PyGetTouchMaterial(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - return PyInt_FromLong(m_bFindMaterial); + KX_TouchSensor* self= static_cast<KX_TouchSensor*>(self_v); + + if (self->m_hitObject) + return self->m_hitObject->GetProxy(); + else + Py_RETURN_NONE; } -/* 6. setTouchMaterial */ -const char KX_TouchSensor::SetTouchMaterial_doc[] = -"setTouchMaterial(flag)\n" -"\t- flag: KX_TRUE or KX_FALSE.\n" -"\tSet flag to KX_TRUE to switch on positive pulse mode,\n" -"\tKX_FALSE to switch off positive pulse mode.\n" ; -PyObject* KX_TouchSensor::PySetTouchMaterial(PyObject* self, PyObject* args, PyObject* kwds) +PyObject* KX_TouchSensor::pyattr_get_object_hit_list(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - int pulseArg = 0; - - if(!PyArg_ParseTuple(args, "i", &pulseArg)) { - return NULL; - } - - m_bFindMaterial = pulseArg != 0; - - Py_Return; + KX_TouchSensor* self= static_cast<KX_TouchSensor*>(self_v); + return self->m_colliders->GetProxy(); } diff --git a/source/gameengine/Ketsji/KX_TouchSensor.h b/source/gameengine/Ketsji/KX_TouchSensor.h index 8fbb1c676ba..ad1830e05c9 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.h +++ b/source/gameengine/Ketsji/KX_TouchSensor.h @@ -39,6 +39,12 @@ struct PHY_CollData; #include "KX_ClientObjectInfo.h" +#if defined(_WIN64) +typedef unsigned __int64 uint_ptr; +#else +typedef unsigned long uint_ptr; +#endif + class KX_TouchEventManager; class KX_TouchSensor : public SCA_ISensor @@ -51,27 +57,34 @@ protected: */ STR_String m_touchedpropname; bool m_bFindMaterial; - class SCA_EventManager* m_eventmgr; + bool m_bTouchPulse; /* changes in the colliding objects trigger pulses */ class PHY_IPhysicsController* m_physCtrl; bool m_bCollision; bool m_bTriggered; bool m_bLastTriggered; + + // Use with m_bTouchPulse to detect changes + int m_bLastCount; /* size of m_colliders last tick */ + uint_ptr m_bColliderHash; /* hash collision objects pointers to trigger incase one object collides and another takes its place */ + uint_ptr m_bLastColliderHash; + SCA_IObject* m_hitObject; class CListValue* m_colliders; public: KX_TouchSensor(class SCA_EventManager* eventmgr, class KX_GameObject* gameobj, - bool fFindMaterial, - const STR_String& touchedpropname, - PyTypeObject* T=&Type) ; + bool bFindMaterial, + bool bTouchPulse, + const STR_String& touchedpropname) ; virtual ~KX_TouchSensor(); virtual CValue* GetReplica(); + virtual void ProcessReplica(); virtual void SynchronizeTransform(); - virtual bool Evaluate(CValue* event); + virtual bool Evaluate(); virtual void Init(); virtual void ReParent(SCA_IObject* parent); @@ -88,7 +101,8 @@ public: // obj1 = sensor physical controller, obj2 = physical controller of second object // return value = true if collision should be checked on pair of object virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2) { return true; } - + virtual bool BroadPhaseSensorFilterCollision(void*obj1,void*obj2); + virtual sensortype GetSensorType() { return ST_TOUCH; } virtual bool IsPositiveTrigger() { @@ -106,20 +120,9 @@ public: /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); - - /* 1. setProperty */ - KX_PYMETHOD_DOC(KX_TouchSensor,SetProperty); - /* 2. getProperty */ - KX_PYMETHOD_DOC(KX_TouchSensor,GetProperty); - /* 3. getHitObject */ - KX_PYMETHOD_DOC(KX_TouchSensor,GetHitObject); - /* 4. getHitObject */ - KX_PYMETHOD_DOC(KX_TouchSensor,GetHitObjectList); - /* 5. getTouchMaterial */ - KX_PYMETHOD_DOC(KX_TouchSensor,GetTouchMaterial); - /* 6. setTouchMaterial */ - KX_PYMETHOD_DOC(KX_TouchSensor,SetTouchMaterial); + static PyObject* pyattr_get_object_hit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_object_hit_list(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + }; diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp index acc4a6ab5d7..e6c2f86bbce 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp +++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp @@ -59,10 +59,8 @@ KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj, int time, bool allow3D, int trackflag, - int upflag, - PyTypeObject* T) - : - SCA_IActuator(gameobj, T) + int upflag) + : SCA_IActuator(gameobj) { m_time = time; m_allow3D = allow3D; @@ -74,7 +72,6 @@ KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj, if (m_object) m_object->RegisterActuator(this); - if (gameobj->isA(&KX_GameObject::Type)) { // if the object is vertex parented, don't check parent orientation as the link is broken if (!((KX_GameObject*)gameobj)->IsVertexParent()){ @@ -83,6 +80,10 @@ KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj, // if so, store the initial local rotation // this is needed to revert the effect of the parent inverse node (TBC) m_parentlocalmat = m_parentobj->GetSGNode()->GetLocalOrientation(); + // use registration mechanism rather than AddRef, it creates zombie objects + m_parentobj->RegisterActuator(this); + // GetParent did AddRef, undo here + m_parentobj->Release(); } } } @@ -189,7 +190,7 @@ KX_TrackToActuator::~KX_TrackToActuator() if (m_object) m_object->UnregisterActuator(this); if (m_parentobj) - m_parentobj->Release(); + m_parentobj->UnregisterActuator(this); } /* end of destructor */ void KX_TrackToActuator::ProcessReplica() @@ -198,7 +199,7 @@ void KX_TrackToActuator::ProcessReplica() if (m_object) m_object->RegisterActuator(this); if (m_parentobj) - m_parentobj->AddRef(); + m_parentobj->RegisterActuator(this); SCA_IActuator::ProcessReplica(); } @@ -211,6 +212,11 @@ bool KX_TrackToActuator::UnlinkObject(SCA_IObject* clientobj) m_object = NULL; return true; } + if (clientobj == m_parentobj) + { + m_parentobj = NULL; + return true; + } return false; } @@ -227,9 +233,9 @@ void KX_TrackToActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) void **h_parobj = (*obj_map)[m_parentobj]; if (h_parobj) { if (m_parentobj) - m_parentobj->Release(); + m_parentobj->UnregisterActuator(this); m_parentobj= (KX_GameObject*)(*h_parobj); - m_parentobj->AddRef(); + m_parentobj->RegisterActuator(this); } } @@ -258,18 +264,18 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) { case 0: { - up = MT_Vector3(1.0,0,0); + up.setValue(1.0,0,0); break; } case 1: { - up = MT_Vector3(0,1.0,0); + up.setValue(0,1.0,0); break; } case 2: default: { - up = MT_Vector3(0,0,1.0); + up.setValue(0,0,1.0); } } #endif @@ -402,7 +408,7 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) // set the models tranformation properties curobj->NodeSetLocalOrientation(mat); curobj->NodeSetLocalPosition(localpos); - curobj->UpdateTransform(); + //curobj->UpdateTransform(); } else { @@ -425,162 +431,65 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_TrackToActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_TrackToActuator", - sizeof(KX_TrackToActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - - - -PyParentObject KX_TrackToActuator::Parents[] = { - &KX_TrackToActuator::Type, - &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_IActuator::Type, + 0,0,0,0,0,0, + py_base_new }; - - PyMethodDef KX_TrackToActuator::Methods[] = { - {"setObject", (PyCFunction) KX_TrackToActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc}, - {"getObject", (PyCFunction) KX_TrackToActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc}, - {"setTime", (PyCFunction) KX_TrackToActuator::sPySetTime, METH_VARARGS, (PY_METHODCHAR)SetTime_doc}, - {"getTime", (PyCFunction) KX_TrackToActuator::sPyGetTime, METH_VARARGS, (PY_METHODCHAR)GetTime_doc}, - {"setUse3D", (PyCFunction) KX_TrackToActuator::sPySetUse3D, METH_VARARGS, (PY_METHODCHAR)SetUse3D_doc}, - {"getUse3D", (PyCFunction) KX_TrackToActuator::sPyGetUse3D, METH_VARARGS, (PY_METHODCHAR)GetUse3D_doc}, {NULL,NULL} //Sentinel }; +PyAttributeDef KX_TrackToActuator::Attributes[] = { + KX_PYATTRIBUTE_INT_RW("time",0,1000,true,KX_TrackToActuator,m_time), + KX_PYATTRIBUTE_BOOL_RW("use3D",KX_TrackToActuator,m_allow3D), + KX_PYATTRIBUTE_RW_FUNCTION("object", KX_TrackToActuator, pyattr_get_object, pyattr_set_object), + { NULL } //Sentinel +}; -PyObject* KX_TrackToActuator::_getattr(const STR_String& attr) -{ - _getattr_up(SCA_IActuator); -} - - - -/* 1. setObject */ -const char KX_TrackToActuator::SetObject_doc[] = -"setObject(object)\n" -"\t- object: KX_GameObject, string or None\n" -"\tSet the object to track with the parent of this actuator.\n"; -PyObject* KX_TrackToActuator::PySetObject(PyObject* self, PyObject* value) -{ - KX_GameObject *gameobj; - - if (!ConvertPythonToGameObject(value, &gameobj, true)) - return NULL; // ConvertPythonToGameObject sets the error - - if (m_object != NULL) - m_object->UnregisterActuator(this); - - m_object = (SCA_IObject*)gameobj; - if (m_object) - m_object->RegisterActuator(this); - - Py_RETURN_NONE; -} - - - -/* 2. getObject */ -const char KX_TrackToActuator::GetObject_doc[] = -"getObject(name_only = 1)\n" -"name_only - optional arg, when true will return the KX_GameObject rather then its name\n" -"\tReturns the object to track with the parent of this actuator\n"; -PyObject* KX_TrackToActuator::PyGetObject(PyObject* self, PyObject* args) +PyObject* KX_TrackToActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) { - int ret_name_only = 1; - if (!PyArg_ParseTuple(args, "|i", &ret_name_only)) - return NULL; - - if (!m_object) + KX_TrackToActuator* actuator = static_cast<KX_TrackToActuator*>(self); + if (!actuator->m_object) Py_RETURN_NONE; - - if (ret_name_only) - return PyString_FromString(m_object->GetName()); else - return m_object->AddRef(); -} - - - -/* 3. setTime */ -const char KX_TrackToActuator::SetTime_doc[] = -"setTime(time)\n" -"\t- time: integer\n" -"\tSet the time in frames with which to delay the tracking motion.\n"; -PyObject* KX_TrackToActuator::PySetTime(PyObject* self, PyObject* args, PyObject* kwds) -{ - int timeArg; - - if (!PyArg_ParseTuple(args, "i", &timeArg)) - { - return NULL; - } - - m_time= timeArg; - - Py_Return; + return actuator->m_object->GetProxy(); } - - -/* 4.getTime */ -const char KX_TrackToActuator::GetTime_doc[] = -"getTime()\n" -"\t- time: integer\n" -"\tReturn the time in frames with which the tracking motion is delayed.\n"; -PyObject* KX_TrackToActuator::PyGetTime(PyObject* self, PyObject* args, PyObject* kwds) +int KX_TrackToActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - return PyInt_FromLong(m_time); -} - - - -/* 5. getUse3D */ -const char KX_TrackToActuator::GetUse3D_doc[] = -"getUse3D()\n" -"\tReturns 1 if the motion is allowed to extend in the z-direction.\n"; -PyObject* KX_TrackToActuator::PyGetUse3D(PyObject* self, PyObject* args, PyObject* kwds) -{ - return PyInt_FromLong(!(m_allow3D == 0)); -} - - + KX_TrackToActuator* actuator = static_cast<KX_TrackToActuator*>(self); + KX_GameObject *gameobj; + + if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_TrackToActuator")) + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + + if (actuator->m_object != NULL) + actuator->m_object->UnregisterActuator(actuator); -/* 6. setUse3D */ -const char KX_TrackToActuator::SetUse3D_doc[] = -"setUse3D(value)\n" -"\t- value: 0 or 1\n" -"\tSet to 1 to allow the tracking motion to extend in the z-direction,\n" -"\tset to 0 to lock the tracking motion to the x-y plane.\n"; -PyObject* KX_TrackToActuator::PySetUse3D(PyObject* self, PyObject* args, PyObject* kwds) -{ - int boolArg; - - if (!PyArg_ParseTuple(args, "i", &boolArg)) { - return NULL; - } - - m_allow3D = !(boolArg == 0); - - Py_Return; + actuator->m_object = (SCA_IObject*) gameobj; + + if (actuator->m_object) + actuator->m_object->RegisterActuator(actuator); + + return PY_SET_ATTR_SUCCESS; } /* eof */ diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.h b/source/gameengine/Ketsji/KX_TrackToActuator.h index 445132a6094..bbfc1d17576 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.h +++ b/source/gameengine/Ketsji/KX_TrackToActuator.h @@ -56,13 +56,11 @@ class KX_TrackToActuator : public SCA_IActuator public: KX_TrackToActuator(SCA_IObject* gameobj, SCA_IObject *ob, int time, - bool threedee,int trackflag,int upflag, PyTypeObject* T=&Type); + bool threedee,int trackflag,int upflag); virtual ~KX_TrackToActuator(); virtual CValue* GetReplica() { KX_TrackToActuator* replica = new KX_TrackToActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; }; @@ -72,20 +70,10 @@ class KX_TrackToActuator : public SCA_IActuator virtual bool Update(double curtime, bool frame); /* Python part */ - virtual PyObject* _getattr(const STR_String& attr); - - /* 1. setObject */ - KX_PYMETHOD_DOC_O(KX_TrackToActuator,SetObject); - /* 2. getObject */ - KX_PYMETHOD_DOC_VARARGS(KX_TrackToActuator,GetObject); - /* 3. setTime */ - KX_PYMETHOD_DOC(KX_TrackToActuator,SetTime); - /* 4. getTime */ - KX_PYMETHOD_DOC(KX_TrackToActuator,GetTime); - /* 5. getUse3D */ - KX_PYMETHOD_DOC(KX_TrackToActuator,GetUse3D); - /* 6. setUse3D */ - KX_PYMETHOD_DOC(KX_TrackToActuator,SetUse3D); + + /* These are used to get and set m_ob */ + static PyObject* pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); }; /* end of class KX_TrackToActuator : public KX_EditObjectActuator */ diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp index 028f96f6c5b..1f46cbf53be 100644 --- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp +++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp @@ -16,8 +16,8 @@ KX_VehicleWrapper::KX_VehicleWrapper( PHY_IVehicle* vehicle, - PHY_IPhysicsEnvironment* physenv,PyTypeObject *T) : - PyObjectPlus(T), + PHY_IPhysicsEnvironment* physenv) : + PyObjectPlus(), m_vehicle(vehicle), m_physenv(physenv) { @@ -35,9 +35,7 @@ KX_VehicleWrapper::~KX_VehicleWrapper() } -PyObject* KX_VehicleWrapper::PyAddWheel(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PyAddWheel(PyObject* args) { PyObject* pylistPos,*pylistDir,*pylistAxleDir; @@ -46,14 +44,18 @@ PyObject* KX_VehicleWrapper::PyAddWheel(PyObject* self, int hasSteering; - if (PyArg_ParseTuple(args,"OOOOffi",&wheelGameObject,&pylistPos,&pylistDir,&pylistAxleDir,&suspensionRestLength,&wheelRadius,&hasSteering)) + if (PyArg_ParseTuple(args,"OOOOffi:addWheel",&wheelGameObject,&pylistPos,&pylistDir,&pylistAxleDir,&suspensionRestLength,&wheelRadius,&hasSteering)) { - KX_GameObject* gameOb = (KX_GameObject*) wheelGameObject; + KX_GameObject *gameOb; + if (!ConvertPythonToGameObject(wheelGameObject, &gameOb, false, "vehicle.addWheel(...): KX_VehicleWrapper (first argument)")) + return NULL; + if (gameOb->GetSGNode()) { PHY_IMotionState* motionState = new KX_MotionState(gameOb->GetSGNode()); - + + /* TODO - no error checking here! - bad juju */ MT_Vector3 attachPos,attachDir,attachAxle; PyVecTo(pylistPos,attachPos); PyVecTo(pylistDir,attachDir); @@ -82,14 +84,12 @@ PyObject* KX_VehicleWrapper::PyAddWheel(PyObject* self, -PyObject* KX_VehicleWrapper::PyGetWheelPosition(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PyGetWheelPosition(PyObject* args) { int wheelIndex; - if (PyArg_ParseTuple(args,"i",&wheelIndex)) + if (PyArg_ParseTuple(args,"i:getWheelPosition",&wheelIndex)) { float position[3]; m_vehicle->GetWheelPosition(wheelIndex,position[0],position[1],position[2]); @@ -99,24 +99,20 @@ PyObject* KX_VehicleWrapper::PyGetWheelPosition(PyObject* self, return NULL; } -PyObject* KX_VehicleWrapper::PyGetWheelRotation(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PyGetWheelRotation(PyObject* args) { int wheelIndex; - if (PyArg_ParseTuple(args,"i",&wheelIndex)) + if (PyArg_ParseTuple(args,"i:getWheelRotation",&wheelIndex)) { return PyFloat_FromDouble(m_vehicle->GetWheelRotation(wheelIndex)); } return NULL; } -PyObject* KX_VehicleWrapper::PyGetWheelOrientationQuaternion(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PyGetWheelOrientationQuaternion(PyObject* args) { int wheelIndex; - if (PyArg_ParseTuple(args,"i",&wheelIndex)) + if (PyArg_ParseTuple(args,"i:getWheelOrientationQuaternion",&wheelIndex)) { float orn[4]; m_vehicle->GetWheelOrientationQuaternion(wheelIndex,orn[0],orn[1],orn[2],orn[3]); @@ -129,31 +125,25 @@ PyObject* KX_VehicleWrapper::PyGetWheelOrientationQuaternion(PyObject* self, } -PyObject* KX_VehicleWrapper::PyGetNumWheels(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PyGetNumWheels(PyObject* args) { - return PyInt_FromLong(m_vehicle->GetNumWheels()); + return PyLong_FromSsize_t(m_vehicle->GetNumWheels()); } -PyObject* KX_VehicleWrapper::PyGetConstraintId(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PyGetConstraintId(PyObject* args) { - return PyInt_FromLong(m_vehicle->GetUserConstraintId()); + return PyLong_FromSsize_t(m_vehicle->GetUserConstraintId()); } -PyObject* KX_VehicleWrapper::PyApplyEngineForce(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PyApplyEngineForce(PyObject* args) { float force; int wheelIndex; - if (PyArg_ParseTuple(args,"fi",&force,&wheelIndex)) + if (PyArg_ParseTuple(args,"fi:applyEngineForce",&force,&wheelIndex)) { force *= -1.f;//someone reverse some conventions inside Bullet (axle winding) m_vehicle->ApplyEngineForce(force,wheelIndex); @@ -164,14 +154,12 @@ PyObject* KX_VehicleWrapper::PyApplyEngineForce(PyObject* self, Py_RETURN_NONE; } -PyObject* KX_VehicleWrapper::PySetTyreFriction(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PySetTyreFriction(PyObject* args) { float wheelFriction; int wheelIndex; - if (PyArg_ParseTuple(args,"fi",&wheelFriction,&wheelIndex)) + if (PyArg_ParseTuple(args,"fi:setTyreFriction",&wheelFriction,&wheelIndex)) { m_vehicle->SetWheelFriction(wheelFriction,wheelIndex); } @@ -181,14 +169,12 @@ PyObject* KX_VehicleWrapper::PySetTyreFriction(PyObject* self, Py_RETURN_NONE; } -PyObject* KX_VehicleWrapper::PySetSuspensionStiffness(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PySetSuspensionStiffness(PyObject* args) { float suspensionStiffness; int wheelIndex; - if (PyArg_ParseTuple(args,"fi",&suspensionStiffness,&wheelIndex)) + if (PyArg_ParseTuple(args,"fi:setSuspensionStiffness",&suspensionStiffness,&wheelIndex)) { m_vehicle->SetSuspensionStiffness(suspensionStiffness,wheelIndex); } @@ -198,14 +184,12 @@ PyObject* KX_VehicleWrapper::PySetSuspensionStiffness(PyObject* self, Py_RETURN_NONE; } -PyObject* KX_VehicleWrapper::PySetSuspensionDamping(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PySetSuspensionDamping(PyObject* args) { float suspensionDamping; int wheelIndex; - if (PyArg_ParseTuple(args,"fi",&suspensionDamping,&wheelIndex)) + if (PyArg_ParseTuple(args,"fi:setSuspensionDamping",&suspensionDamping,&wheelIndex)) { m_vehicle->SetSuspensionDamping(suspensionDamping,wheelIndex); } else { @@ -214,14 +198,12 @@ PyObject* KX_VehicleWrapper::PySetSuspensionDamping(PyObject* self, Py_RETURN_NONE; } -PyObject* KX_VehicleWrapper::PySetSuspensionCompression(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PySetSuspensionCompression(PyObject* args) { float suspensionCompression; int wheelIndex; - if (PyArg_ParseTuple(args,"fi",&suspensionCompression,&wheelIndex)) + if (PyArg_ParseTuple(args,"fi:setSuspensionCompression",&suspensionCompression,&wheelIndex)) { m_vehicle->SetSuspensionCompression(suspensionCompression,wheelIndex); } else { @@ -230,14 +212,12 @@ PyObject* KX_VehicleWrapper::PySetSuspensionCompression(PyObject* self, Py_RETURN_NONE; } -PyObject* KX_VehicleWrapper::PySetRollInfluence(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PySetRollInfluence(PyObject* args) { float rollInfluence; int wheelIndex; - if (PyArg_ParseTuple(args,"fi",&rollInfluence,&wheelIndex)) + if (PyArg_ParseTuple(args,"fi:setRollInfluence",&rollInfluence,&wheelIndex)) { m_vehicle->SetRollInfluence(rollInfluence,wheelIndex); } @@ -248,14 +228,12 @@ PyObject* KX_VehicleWrapper::PySetRollInfluence(PyObject* self, } -PyObject* KX_VehicleWrapper::PyApplyBraking(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PyApplyBraking(PyObject* args) { float braking; int wheelIndex; - if (PyArg_ParseTuple(args,"fi",&braking,&wheelIndex)) + if (PyArg_ParseTuple(args,"fi:applyBraking",&braking,&wheelIndex)) { m_vehicle->ApplyBraking(braking,wheelIndex); } @@ -268,14 +246,12 @@ PyObject* KX_VehicleWrapper::PyApplyBraking(PyObject* self, -PyObject* KX_VehicleWrapper::PySetSteeringValue(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PySetSteeringValue(PyObject* args) { float steeringValue; int wheelIndex; - if (PyArg_ParseTuple(args,"fi",&steeringValue,&wheelIndex)) + if (PyArg_ParseTuple(args,"fi:setSteeringValue",&steeringValue,&wheelIndex)) { m_vehicle->SetSteeringValue(steeringValue,wheelIndex); } @@ -286,11 +262,9 @@ PyObject* KX_VehicleWrapper::PySetSteeringValue(PyObject* self, } -PyObject* KX_VehicleWrapper::PyGetConstraintType(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_VehicleWrapper::PyGetConstraintType(PyObject* args) { - return PyInt_FromLong(m_vehicle->GetUserConstraintType()); + return PyLong_FromSsize_t(m_vehicle->GetUserConstraintType()); } @@ -299,64 +273,27 @@ PyObject* KX_VehicleWrapper::PyGetConstraintType(PyObject* self, //python specific stuff PyTypeObject KX_VehicleWrapper::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, - "KX_VehicleWrapper", - sizeof(KX_VehicleWrapper), - 0, - PyDestructor, - 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, - 0, - 0, - 0, - 0 -}; - -PyParentObject KX_VehicleWrapper::Parents[] = { - &KX_VehicleWrapper::Type, - NULL -}; - -PyObject* KX_VehicleWrapper::_getattr(const STR_String& attr) -{ - //here you can search for existing data members (like mass,friction etc.) - _getattr_up(PyObjectPlus); -} - -int KX_VehicleWrapper::_setattr(const STR_String& attr,PyObject* pyobj) -{ - - PyTypeObject* type = pyobj->ob_type; - int result = 1; - - if (type == &PyList_Type) - { - result = 0; - } - if (type == &PyFloat_Type) - { - result = 0; - - } - if (type == &PyInt_Type) - { - result = 0; - } - if (type == &PyString_Type) - { - result = 0; - } - if (result) - result = PyObjectPlus::_setattr(attr,pyobj); - return result; + PyVarObject_HEAD_INIT(NULL, 0) + "KX_VehicleWrapper", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &PyObjectPlus::Type, + 0,0,0,0,0,0, + py_base_new }; - PyMethodDef KX_VehicleWrapper::Methods[] = { {"addWheel",(PyCFunction) KX_VehicleWrapper::sPyAddWheel, METH_VARARGS}, {"getNumWheels",(PyCFunction) KX_VehicleWrapper::sPyGetNumWheels, METH_VARARGS}, @@ -382,3 +319,6 @@ PyMethodDef KX_VehicleWrapper::Methods[] = { {NULL,NULL} //Sentinel }; +PyAttributeDef KX_VehicleWrapper::Attributes[] = { + { NULL } //Sentinel +}; diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.h b/source/gameengine/Ketsji/KX_VehicleWrapper.h index b98369d401a..d7f2da5cd7c 100644 --- a/source/gameengine/Ketsji/KX_VehicleWrapper.h +++ b/source/gameengine/Ketsji/KX_VehicleWrapper.h @@ -12,42 +12,40 @@ class PHY_IMotionState; class KX_VehicleWrapper : public PyObjectPlus { Py_Header; - virtual PyObject* _getattr(const STR_String& attr); - virtual int _setattr(const STR_String& attr, PyObject *value); std::vector<PHY_IMotionState*> m_motionStates; public: - KX_VehicleWrapper(PHY_IVehicle* vehicle,class PHY_IPhysicsEnvironment* physenv,PyTypeObject *T = &Type); + KX_VehicleWrapper(PHY_IVehicle* vehicle,class PHY_IPhysicsEnvironment* physenv); virtual ~KX_VehicleWrapper (); int getConstraintId(); - KX_PYMETHOD(KX_VehicleWrapper,AddWheel); - KX_PYMETHOD(KX_VehicleWrapper,GetNumWheels); - KX_PYMETHOD(KX_VehicleWrapper,GetWheelOrientationQuaternion); - KX_PYMETHOD(KX_VehicleWrapper,GetWheelRotation); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,AddWheel); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,GetNumWheels); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,GetWheelOrientationQuaternion); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,GetWheelRotation); - KX_PYMETHOD(KX_VehicleWrapper,GetWheelPosition); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,GetWheelPosition); - KX_PYMETHOD(KX_VehicleWrapper,GetConstraintId); - KX_PYMETHOD(KX_VehicleWrapper,GetConstraintType); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,GetConstraintId); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,GetConstraintType); - KX_PYMETHOD(KX_VehicleWrapper,SetSteeringValue); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,SetSteeringValue); - KX_PYMETHOD(KX_VehicleWrapper,ApplyEngineForce); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,ApplyEngineForce); - KX_PYMETHOD(KX_VehicleWrapper,ApplyBraking); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,ApplyBraking); - KX_PYMETHOD(KX_VehicleWrapper,SetTyreFriction); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,SetTyreFriction); - KX_PYMETHOD(KX_VehicleWrapper,SetSuspensionStiffness); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,SetSuspensionStiffness); - KX_PYMETHOD(KX_VehicleWrapper,SetSuspensionDamping); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,SetSuspensionDamping); - KX_PYMETHOD(KX_VehicleWrapper,SetSuspensionCompression); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,SetSuspensionCompression); - KX_PYMETHOD(KX_VehicleWrapper,SetRollInfluence); + KX_PYMETHOD_VARARGS(KX_VehicleWrapper,SetRollInfluence); private: diff --git a/source/gameengine/Ketsji/KX_VertexProxy.cpp b/source/gameengine/Ketsji/KX_VertexProxy.cpp index 25205714308..6a47dec181b 100644 --- a/source/gameengine/Ketsji/KX_VertexProxy.cpp +++ b/source/gameengine/Ketsji/KX_VertexProxy.cpp @@ -37,199 +37,233 @@ #include "KX_PyMath.h" PyTypeObject KX_VertexProxy::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "KX_VertexProxy", - sizeof(KX_VertexProxy), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject KX_VertexProxy::Parents[] = { - &KX_VertexProxy::Type, - &SCA_IObject::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; PyMethodDef KX_VertexProxy::Methods[] = { -{"getXYZ", (PyCFunction)KX_VertexProxy::sPyGetXYZ,METH_VARARGS}, -{"setXYZ", (PyCFunction)KX_VertexProxy::sPySetXYZ,METH_VARARGS}, -{"getUV", (PyCFunction)KX_VertexProxy::sPyGetUV,METH_VARARGS}, -{"setUV", (PyCFunction)KX_VertexProxy::sPySetUV,METH_VARARGS}, +{"getXYZ", (PyCFunction)KX_VertexProxy::sPyGetXYZ,METH_NOARGS}, +{"setXYZ", (PyCFunction)KX_VertexProxy::sPySetXYZ,METH_O}, +{"getUV", (PyCFunction)KX_VertexProxy::sPyGetUV,METH_NOARGS}, +{"setUV", (PyCFunction)KX_VertexProxy::sPySetUV,METH_O}, -{"getUV2", (PyCFunction)KX_VertexProxy::sPyGetUV2,METH_VARARGS}, +{"getUV2", (PyCFunction)KX_VertexProxy::sPyGetUV2,METH_NOARGS}, {"setUV2", (PyCFunction)KX_VertexProxy::sPySetUV2,METH_VARARGS}, -{"getRGBA", (PyCFunction)KX_VertexProxy::sPyGetRGBA,METH_VARARGS}, -{"setRGBA", (PyCFunction)KX_VertexProxy::sPySetRGBA,METH_VARARGS}, -{"getNormal", (PyCFunction)KX_VertexProxy::sPyGetNormal,METH_VARARGS}, -{"setNormal", (PyCFunction)KX_VertexProxy::sPySetNormal,METH_VARARGS}, +{"getRGBA", (PyCFunction)KX_VertexProxy::sPyGetRGBA,METH_NOARGS}, +{"setRGBA", (PyCFunction)KX_VertexProxy::sPySetRGBA,METH_O}, +{"getNormal", (PyCFunction)KX_VertexProxy::sPyGetNormal,METH_NOARGS}, +{"setNormal", (PyCFunction)KX_VertexProxy::sPySetNormal,METH_O}, {NULL,NULL} //Sentinel }; +PyAttributeDef KX_VertexProxy::Attributes[] = { + //KX_PYATTRIBUTE_TODO("DummyProps"), + + KX_PYATTRIBUTE_DUMMY("x"), + KX_PYATTRIBUTE_DUMMY("y"), + KX_PYATTRIBUTE_DUMMY("z"), + + KX_PYATTRIBUTE_DUMMY("r"), + KX_PYATTRIBUTE_DUMMY("g"), + KX_PYATTRIBUTE_DUMMY("b"), + KX_PYATTRIBUTE_DUMMY("a"), + + KX_PYATTRIBUTE_DUMMY("u"), + KX_PYATTRIBUTE_DUMMY("v"), + + KX_PYATTRIBUTE_DUMMY("u2"), + KX_PYATTRIBUTE_DUMMY("v2"), + + KX_PYATTRIBUTE_DUMMY("XYZ"), + KX_PYATTRIBUTE_DUMMY("UV"), + + KX_PYATTRIBUTE_DUMMY("color"), + KX_PYATTRIBUTE_DUMMY("colour"), + + KX_PYATTRIBUTE_DUMMY("normal"), + + { NULL } //Sentinel +}; + +#if 0 PyObject* -KX_VertexProxy::_getattr(const STR_String& attr) +KX_VertexProxy::py_getattro(PyObject *attr) { - if (attr == "XYZ") + char *attr_str= _PyUnicode_AsString(attr); + if (attr_str[1]=='\0') { // Group single letters + // pos + if (attr_str[0]=='x') + return PyFloat_FromDouble(m_vertex->getXYZ()[0]); + if (attr_str[0]=='y') + return PyFloat_FromDouble(m_vertex->getXYZ()[1]); + if (attr_str[0]=='z') + return PyFloat_FromDouble(m_vertex->getXYZ()[2]); + + // Col + if (attr_str[0]=='r') + return PyFloat_FromDouble(m_vertex->getRGBA()[0]/255.0); + if (attr_str[0]=='g') + return PyFloat_FromDouble(m_vertex->getRGBA()[1]/255.0); + if (attr_str[0]=='b') + return PyFloat_FromDouble(m_vertex->getRGBA()[2]/255.0); + if (attr_str[0]=='a') + return PyFloat_FromDouble(m_vertex->getRGBA()[3]/255.0); + + // UV + if (attr_str[0]=='u') + return PyFloat_FromDouble(m_vertex->getUV1()[0]); + if (attr_str[0]=='v') + return PyFloat_FromDouble(m_vertex->getUV1()[1]); + } + + + if (!strcmp(attr_str, "XYZ")) return PyObjectFrom(MT_Vector3(m_vertex->getXYZ())); - if (attr == "UV") + if (!strcmp(attr_str, "UV")) return PyObjectFrom(MT_Point2(m_vertex->getUV1())); - if (attr == "colour" || attr == "color") + if (!strcmp(attr_str, "color") || !strcmp(attr_str, "colour")) { const unsigned char *colp = m_vertex->getRGBA(); MT_Vector4 color(colp[0], colp[1], colp[2], colp[3]); color /= 255.0; return PyObjectFrom(color); } - - if (attr == "normal") + + if (!strcmp(attr_str, "normal")) { return PyObjectFrom(MT_Vector3(m_vertex->getNormal())); } - // pos - if (attr == "x") - return PyFloat_FromDouble(m_vertex->getXYZ()[0]); - if (attr == "y") - return PyFloat_FromDouble(m_vertex->getXYZ()[1]); - if (attr == "z") - return PyFloat_FromDouble(m_vertex->getXYZ()[2]); - - // Col - if (attr == "r") - return PyFloat_FromDouble(m_vertex->getRGBA()[0]/255.0); - if (attr == "g") - return PyFloat_FromDouble(m_vertex->getRGBA()[1]/255.0); - if (attr == "b") - return PyFloat_FromDouble(m_vertex->getRGBA()[2]/255.0); - if (attr == "a") - return PyFloat_FromDouble(m_vertex->getRGBA()[3]/255.0); - - // UV - if (attr == "u") - return PyFloat_FromDouble(m_vertex->getUV1()[0]); - if (attr == "v") - return PyFloat_FromDouble(m_vertex->getUV1()[1]); - - _getattr_up(SCA_IObject); + py_getattro_up(CValue); } +#endif -int KX_VertexProxy::_setattr(const STR_String& attr, PyObject *pyvalue) + +#if 0 +int KX_VertexProxy::py_setattro(PyObject *attr, PyObject *pyvalue) { + char *attr_str= _PyUnicode_AsString(attr); if (PySequence_Check(pyvalue)) { - if (attr == "XYZ") + if (!strcmp(attr_str, "XYZ")) { MT_Point3 vec; if (PyVecTo(pyvalue, vec)) { m_vertex->SetXYZ(vec); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } - return 1; + return PY_SET_ATTR_FAIL; } - - if (attr == "UV") + + if (!strcmp(attr_str, "UV")) { MT_Point2 vec; if (PyVecTo(pyvalue, vec)) { m_vertex->SetUV(vec); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } - return 1; + return PY_SET_ATTR_FAIL; } - - if (attr == "colour" || attr == "color") + + if (!strcmp(attr_str, "color") || !strcmp(attr_str, "colour")) { MT_Vector4 vec; if (PyVecTo(pyvalue, vec)) { m_vertex->SetRGBA(vec); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } - return 1; + return PY_SET_ATTR_FAIL; } - - if (attr == "normal") + + if (!strcmp(attr_str, "normal")) { MT_Vector3 vec; if (PyVecTo(pyvalue, vec)) { m_vertex->SetNormal(vec); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } - return 1; + return PY_SET_ATTR_FAIL; } } - + if (PyFloat_Check(pyvalue)) { float val = PyFloat_AsDouble(pyvalue); // pos MT_Point3 pos(m_vertex->getXYZ()); - if (attr == "x") + if (!strcmp(attr_str, "x")) { pos.x() = val; m_vertex->SetXYZ(pos); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } - - if (attr == "y") + + if (!strcmp(attr_str, "y")) { pos.y() = val; m_vertex->SetXYZ(pos); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } - - if (attr == "z") + + if (!strcmp(attr_str, "z")) { pos.z() = val; m_vertex->SetXYZ(pos); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } - + // uv MT_Point2 uv = m_vertex->getUV1(); - if (attr == "u") + if (!strcmp(attr_str, "u")) { uv[0] = val; m_vertex->SetUV(uv); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } - if (attr == "v") + if (!strcmp(attr_str, "v")) { uv[1] = val; m_vertex->SetUV(uv); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } // uv MT_Point2 uv2 = m_vertex->getUV2(); - if (attr == "u2") + if (!strcmp(attr_str, "u2")) { uv[0] = val; m_vertex->SetUV2(uv); @@ -237,50 +271,51 @@ int KX_VertexProxy::_setattr(const STR_String& attr, PyObject *pyvalue) return 0; } - if (attr == "v2") + if (!strcmp(attr_str, "v2")) { uv[1] = val; m_vertex->SetUV2(uv); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } - + // col unsigned int icol = *((const unsigned int *)m_vertex->getRGBA()); unsigned char *cp = (unsigned char*) &icol; val *= 255.0; - if (attr == "r") + if (!strcmp(attr_str, "r")) { cp[0] = (unsigned char) val; m_vertex->SetRGBA(icol); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } - if (attr == "g") + if (!strcmp(attr_str, "g")) { cp[1] = (unsigned char) val; m_vertex->SetRGBA(icol); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } - if (attr == "b") + if (!strcmp(attr_str, "b")) { cp[2] = (unsigned char) val; m_vertex->SetRGBA(icol); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } - if (attr == "a") + if (!strcmp(attr_str, "a")) { cp[3] = (unsigned char) val; m_vertex->SetRGBA(icol); m_mesh->SetMeshModified(true); - return 0; + return PY_SET_ATTR_SUCCESS; } } - - return SCA_IObject::_setattr(attr, pyvalue); + + return CValue::py_setattro(attr, pyvalue); } +#endif KX_VertexProxy::KX_VertexProxy(KX_MeshProxy*mesh, RAS_TexVert* vertex) : m_vertex(vertex), @@ -296,142 +331,114 @@ KX_VertexProxy::~KX_VertexProxy() // stuff for cvalue related things CValue* KX_VertexProxy::Calc(VALUE_OPERATOR, CValue *) { return NULL;} -CValue* KX_VertexProxy::CalcFinal(VALUE_DATA_TYPE, VALUE_OPERATOR, CValue *) { return NULL;} +CValue* KX_VertexProxy::CalcFinal(VALUE_DATA_TYPE, VALUE_OPERATOR, CValue *) { return NULL;} STR_String sVertexName="vertex"; const STR_String & KX_VertexProxy::GetText() {return sVertexName;}; -float KX_VertexProxy::GetNumber() { return -1;} -STR_String KX_VertexProxy::GetName() { return sVertexName;} -void KX_VertexProxy::SetName(STR_String) { }; +double KX_VertexProxy::GetNumber() { return -1;} +STR_String& KX_VertexProxy::GetName() { return sVertexName;} +void KX_VertexProxy::SetName(const char *) { }; CValue* KX_VertexProxy::GetReplica() { return NULL;} -void KX_VertexProxy::ReplicaSetName(STR_String) {}; - // stuff for python integration - -PyObject* KX_VertexProxy::PyGetXYZ(PyObject*, - PyObject*, - PyObject*) + +PyObject* KX_VertexProxy::PyGetXYZ() { return PyObjectFrom(MT_Point3(m_vertex->getXYZ())); } -PyObject* KX_VertexProxy::PySetXYZ(PyObject*, - PyObject* args, - PyObject*) +PyObject* KX_VertexProxy::PySetXYZ(PyObject* value) { MT_Point3 vec; - if (PyVecArgTo(args, vec)) - { - m_vertex->SetXYZ(vec); - m_mesh->SetMeshModified(true); - Py_Return; - } - - return NULL; + if (!PyVecTo(value, vec)) + return NULL; + + m_vertex->SetXYZ(vec); + m_mesh->SetMeshModified(true); + Py_RETURN_NONE; } -PyObject* KX_VertexProxy::PyGetNormal(PyObject*, - PyObject*, - PyObject*) +PyObject* KX_VertexProxy::PyGetNormal() { return PyObjectFrom(MT_Vector3(m_vertex->getNormal())); } -PyObject* KX_VertexProxy::PySetNormal(PyObject*, - PyObject* args, - PyObject*) +PyObject* KX_VertexProxy::PySetNormal(PyObject* value) { MT_Vector3 vec; - if (PyVecArgTo(args, vec)) - { - m_vertex->SetNormal(vec); - m_mesh->SetMeshModified(true); - Py_Return; - } - - return NULL; + if (!PyVecTo(value, vec)) + return NULL; + + m_vertex->SetNormal(vec); + m_mesh->SetMeshModified(true); + Py_RETURN_NONE; } -PyObject* KX_VertexProxy::PyGetRGBA(PyObject*, - PyObject*, - PyObject*) +PyObject* KX_VertexProxy::PyGetRGBA() { int *rgba = (int *) m_vertex->getRGBA(); - return PyInt_FromLong(*rgba); + return PyLong_FromSsize_t(*rgba); } -PyObject* KX_VertexProxy::PySetRGBA(PyObject*, - PyObject* args, - PyObject*) +PyObject* KX_VertexProxy::PySetRGBA(PyObject* value) { - float r, g, b, a; - if (PyArg_ParseTuple(args, "(ffff)", &r, &g, &b, &a)) - { - m_vertex->SetRGBA(MT_Vector4(r, g, b, a)); - m_mesh->SetMeshModified(true); - Py_Return; - } - PyErr_Clear(); - - int rgba; - if (PyArg_ParseTuple(args,"i",&rgba)) - { + if PyLong_Check(value) { + int rgba = PyLong_AsSsize_t(value); m_vertex->SetRGBA(rgba); m_mesh->SetMeshModified(true); - Py_Return; + Py_RETURN_NONE; } - + else { + MT_Vector4 vec; + if (PyVecTo(value, vec)) + { + m_vertex->SetRGBA(vec); + m_mesh->SetMeshModified(true); + Py_RETURN_NONE; + } + } + + PyErr_SetString(PyExc_TypeError, "vert.setRGBA(value): KX_VertexProxy, expected a 4D vector or an int"); return NULL; } -PyObject* KX_VertexProxy::PyGetUV(PyObject*, - PyObject*, - PyObject*) +PyObject* KX_VertexProxy::PyGetUV() { return PyObjectFrom(MT_Vector2(m_vertex->getUV1())); } -PyObject* KX_VertexProxy::PySetUV(PyObject*, - PyObject* args, - PyObject*) +PyObject* KX_VertexProxy::PySetUV(PyObject* value) { MT_Point2 vec; - if (PyVecArgTo(args, vec)) - { - m_vertex->SetUV(vec); - m_mesh->SetMeshModified(true); - Py_Return; - } - - return NULL; + if (!PyVecTo(value, vec)) + return NULL; + + m_vertex->SetUV(vec); + m_mesh->SetMeshModified(true); + Py_RETURN_NONE; } -PyObject* KX_VertexProxy::PyGetUV2(PyObject*, - PyObject*, - PyObject*) +PyObject* KX_VertexProxy::PyGetUV2() { return PyObjectFrom(MT_Vector2(m_vertex->getUV2())); } -PyObject* KX_VertexProxy::PySetUV2(PyObject*, - PyObject* args, - PyObject*) +PyObject* KX_VertexProxy::PySetUV2(PyObject* args) { MT_Point2 vec; - unsigned int unit=0; - PyObject* list=0; - if(PyArg_ParseTuple(args, "Oi", &list, &unit)) - { - if (PyVecTo(list, vec)) - { - m_vertex->SetFlag((m_vertex->getFlag()|RAS_TexVert::SECOND_UV)); - m_vertex->SetUnit(unit); - m_vertex->SetUV2(vec); - m_mesh->SetMeshModified(true); - Py_Return; - } - } - return NULL; + unsigned int unit= RAS_TexVert::SECOND_UV; + + PyObject* list= NULL; + if(!PyArg_ParseTuple(args, "O|i:setUV2", &list, &unit)) + return NULL; + + if (!PyVecTo(list, vec)) + return NULL; + + m_vertex->SetFlag((m_vertex->getFlag()|RAS_TexVert::SECOND_UV)); + m_vertex->SetUnit(unit); + m_vertex->SetUV2(vec); + m_mesh->SetMeshModified(true); + Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_VertexProxy.h b/source/gameengine/Ketsji/KX_VertexProxy.h index e154ea11b40..13c57e9f556 100644 --- a/source/gameengine/Ketsji/KX_VertexProxy.h +++ b/source/gameengine/Ketsji/KX_VertexProxy.h @@ -31,7 +31,7 @@ #include "SCA_IObject.h" -class KX_VertexProxy : public SCA_IObject +class KX_VertexProxy : public CValue { Py_Header; protected: @@ -46,29 +46,26 @@ public: CValue* Calc(VALUE_OPERATOR op, CValue *val) ; CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); const STR_String & GetText(); - float GetNumber(); - STR_String GetName(); - void SetName(STR_String name); // Set the name of the value - void ReplicaSetName(STR_String name); + double GetNumber(); + STR_String& GetName(); + void SetName(const char *name); // Set the name of the value CValue* GetReplica(); // stuff for python integration - virtual PyObject* _getattr(const STR_String& attr); - virtual int _setattr(const STR_String& attr, PyObject *pyvalue); - KX_PYMETHOD(KX_VertexProxy,GetXYZ); - KX_PYMETHOD(KX_VertexProxy,SetXYZ); - KX_PYMETHOD(KX_VertexProxy,GetUV); - KX_PYMETHOD(KX_VertexProxy,SetUV); + KX_PYMETHOD_NOARGS(KX_VertexProxy,GetXYZ); + KX_PYMETHOD_O(KX_VertexProxy,SetXYZ); + KX_PYMETHOD_NOARGS(KX_VertexProxy,GetUV); + KX_PYMETHOD_O(KX_VertexProxy,SetUV); - KX_PYMETHOD(KX_VertexProxy,GetUV2); - KX_PYMETHOD(KX_VertexProxy,SetUV2); + KX_PYMETHOD_NOARGS(KX_VertexProxy,GetUV2); + KX_PYMETHOD_VARARGS(KX_VertexProxy,SetUV2); - KX_PYMETHOD(KX_VertexProxy,GetRGBA); - KX_PYMETHOD(KX_VertexProxy,SetRGBA); - KX_PYMETHOD(KX_VertexProxy,GetNormal); - KX_PYMETHOD(KX_VertexProxy,SetNormal); + KX_PYMETHOD_NOARGS(KX_VertexProxy,GetRGBA); + KX_PYMETHOD_O(KX_VertexProxy,SetRGBA); + KX_PYMETHOD_NOARGS(KX_VertexProxy,GetNormal); + KX_PYMETHOD_O(KX_VertexProxy,SetNormal); }; diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp index 4b0db5a7953..184e127209f 100644 --- a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp +++ b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp @@ -38,11 +38,12 @@ KX_VisibilityActuator::KX_VisibilityActuator( SCA_IObject* gameobj, bool visible, - bool recursive, - PyTypeObject* T + bool occlusion, + bool recursive ) - : SCA_IActuator(gameobj,T), + : SCA_IActuator(gameobj), m_visible(visible), + m_occlusion(occlusion), m_recursive(recursive) { // intentionally empty @@ -62,8 +63,6 @@ KX_VisibilityActuator::GetReplica( { KX_VisibilityActuator* replica = new KX_VisibilityActuator(*this); replica->ProcessReplica(); - // this will copy properties and so on... - CValue::AddDataToReplica(replica); return replica; } @@ -78,6 +77,7 @@ KX_VisibilityActuator::Update() KX_GameObject *obj = (KX_GameObject*) GetParent(); obj->SetVisible(m_visible, m_recursive); + obj->SetOccluder(m_occlusion, m_recursive); obj->UpdateBuckets(m_recursive); return false; @@ -90,72 +90,35 @@ KX_VisibilityActuator::Update() /* Integration hooks ------------------------------------------------------- */ -PyTypeObject -KX_VisibilityActuator::Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, +PyTypeObject KX_VisibilityActuator::Type = { + PyVarObject_HEAD_INIT(NULL, 0) "KX_VisibilityActuator", - sizeof(KX_VisibilityActuator), + sizeof(PyObjectPlus_Proxy), 0, - PyDestructor, + py_base_dealloc, 0, - __getattr, - __setattr, - 0, //&MyPyCompare, - __repr, - 0, //&cvalue_as_number, 0, 0, 0, - 0 -}; - -PyParentObject -KX_VisibilityActuator::Parents[] = { - &KX_VisibilityActuator::Type, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, &SCA_IActuator::Type, - &SCA_ILogicBrick::Type, - &CValue::Type, - NULL + 0,0,0,0,0,0, + py_base_new }; -PyMethodDef -KX_VisibilityActuator::Methods[] = { - {"set", (PyCFunction) KX_VisibilityActuator::sPySetVisible, - METH_VARARGS, (PY_METHODCHAR)SetVisible_doc}, +PyMethodDef KX_VisibilityActuator::Methods[] = { {NULL,NULL} //Sentinel }; -PyObject* -KX_VisibilityActuator::_getattr( - const STR_String& attr - ) -{ - _getattr_up(SCA_IActuator); +PyAttributeDef KX_VisibilityActuator::Attributes[] = { + KX_PYATTRIBUTE_BOOL_RW("visibility", KX_VisibilityActuator, m_visible), + KX_PYATTRIBUTE_BOOL_RW("useOcclusion", KX_VisibilityActuator, m_occlusion), + KX_PYATTRIBUTE_BOOL_RW("useRecursion", KX_VisibilityActuator, m_recursive), + { NULL } //Sentinel }; - - - -/* set visibility ---------------------------------------------------------- */ -const char -KX_VisibilityActuator::SetVisible_doc[] = -"setVisible(visible?)\n" -"\t - visible? : Make the object visible? (KX_TRUE, KX_FALSE)" -"\tSet the properties of the actuator.\n"; -PyObject* - -KX_VisibilityActuator::PySetVisible(PyObject* self, - PyObject* args, - PyObject* kwds) { - int vis; - - if(!PyArg_ParseTuple(args, "i", &vis)) { - return NULL; - } - - m_visible = PyArgToBool(vis); - - Py_Return; -} - - diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.h b/source/gameengine/Ketsji/KX_VisibilityActuator.h index d1b85ab998c..e75551644a4 100644 --- a/source/gameengine/Ketsji/KX_VisibilityActuator.h +++ b/source/gameengine/Ketsji/KX_VisibilityActuator.h @@ -39,6 +39,7 @@ class KX_VisibilityActuator : public SCA_IActuator /** Make visible? */ bool m_visible; + bool m_occlusion; bool m_recursive; public: @@ -46,9 +47,8 @@ class KX_VisibilityActuator : public SCA_IActuator KX_VisibilityActuator( SCA_IObject* gameobj, bool visible, - bool recursive, - PyTypeObject* T=&Type - ); + bool occlusion, + bool recursive); virtual ~KX_VisibilityActuator( @@ -67,10 +67,6 @@ class KX_VisibilityActuator : public SCA_IActuator /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual PyObject* _getattr(const STR_String& attr); - //KX_PYMETHOD_DOC - KX_PYMETHOD_DOC(KX_VisibilityActuator,SetVisible); - }; #endif diff --git a/source/gameengine/Ketsji/KX_WorldInfo.h b/source/gameengine/Ketsji/KX_WorldInfo.h index fe4e0c51b24..2c2346ca38e 100644 --- a/source/gameengine/Ketsji/KX_WorldInfo.h +++ b/source/gameengine/Ketsji/KX_WorldInfo.h @@ -31,6 +31,10 @@ #include "MT_Scalar.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class MT_CmMatrix4x4; class KX_WorldInfo @@ -59,6 +63,13 @@ public: virtual void setMistColorRed(float)=0; virtual void setMistColorGreen(float)=0; virtual void setMistColorBlue(float)=0; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_WorldInfo"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_WORLDINFO_H diff --git a/source/gameengine/Ketsji/KX_WorldIpoController.h b/source/gameengine/Ketsji/KX_WorldIpoController.h index d90c03d09ee..8622d80a35f 100644 --- a/source/gameengine/Ketsji/KX_WorldIpoController.h +++ b/source/gameengine/Ketsji/KX_WorldIpoController.h @@ -90,6 +90,13 @@ public: }; void AddInterpolator(KX_IInterpolator* interp); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:KX_WorldIpoController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // KX_LIGHTIPOSGCONTROLLER_H diff --git a/source/gameengine/Ketsji/Makefile b/source/gameengine/Ketsji/Makefile index 0b48ad8b8c3..0e9e657cc16 100644 --- a/source/gameengine/Ketsji/Makefile +++ b/source/gameengine/Ketsji/Makefile @@ -41,12 +41,12 @@ CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) CPPFLAGS += -I../../blender/python -CPPFLAGS += -I../../blender/python/api2_2x +CPPFLAGS += -I../../blender/python/generic CPPFLAGS += -I$(NAN_STRING)/include -CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include -CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO) -I$(NAN_MOTO)/include -CPPFLAGS += -I$(NAN_SOLID)/include +CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I$(NAN_BULLET2)/include +CPPFLAGS += -I$(NAN_AUDASPACE)/include + CPPFLAGS += -I../Rasterizer/RAS_OpenGLRasterizer CPPFLAGS += -I../Rasterizer -I../GameLogic -I../SceneGraph CPPFLAGS += -I../BlenderRoutines -I../Expressions @@ -54,14 +54,11 @@ CPPFLAGS += -I../../kernel/gen_system CPPFLAGS += -I../Network -IKXNetwork CPPFLAGS += -I../Physics/common CPPFLAGS += -I../Physics/Dummy -CPPFLAGS += -I../Physics/Sumo -CPPFLAGS += -I../Physics/BlOde CPPFLAGS += -I../Physics/Bullet CPPFLAGS += -I. CPPFLAGS += -I../Converter CPPFLAGS += -I../../blender/blenkernel CPPFLAGS += -I../../blender/blenlib -CPPFLAGS += -I../../blender/include CPPFLAGS += -I../../blender/makesdna CPPFLAGS += -I../../blender/imbuf CPPFLAGS += -I../../blender/gpu diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript index 02e7aed82a5..5f38020780b 100644 --- a/source/gameengine/Ketsji/SConscript +++ b/source/gameengine/Ketsji/SConscript @@ -4,45 +4,33 @@ import sys Import ('env') sources = env.Glob('*.cpp') +defs = [] -# Mathutils C files. -sources.extend([\ - '#source/blender/python/api2_2x/Mathutils.c',\ - '#source/blender/python/api2_2x/constant.c',\ - '#source/blender/python/api2_2x/euler.c',\ - '#source/blender/python/api2_2x/gen_utils.c',\ - '#source/blender/python/api2_2x/matrix.c',\ - '#source/blender/python/api2_2x/point.c',\ - '#source/blender/python/api2_2x/quat.c',\ - '#source/blender/python/api2_2x/vector.c',\ -]) - -incs = '. #source/blender/python/api2_2x' # Only for Mathutils! - no other deps +incs = '. #source/blender/python/generic' # Only for Mathutils! and bpy_internal_import.h, be very careful incs += ' #source/kernel/gen_system #intern/string #intern/guardedalloc' -incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer #intern/bmfont' -incs += ' #intern/SoundSystem #intern/SoundSystem/include #intern/SoundSystem/openal' -incs += ' #intern/SoundSystem/dummy #intern/SoundSystem/intern #source/gameengine/Converter' +incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer' +incs += ' #intern/audaspace/intern #source/gameengine/Converter' incs += ' #source/gameengine/BlenderRoutines #source/blender/imbuf #intern/moto/include' incs += ' #source/gameengine/Ketsji #source/gameengine/Ketsji/KXNetwork #source/blender/blenlib' -incs += ' #source/blender/blenkernel #source/blender #source/blender/include' +incs += ' #source/blender/blenkernel #source/blender #source/blender/editors/include' incs += ' #source/blender/makesdna #source/blender/python #source/gameengine/Rasterizer' incs += ' #source/gameengine/GameLogic #source/gameengine/Expressions #source/gameengine/Network' incs += ' #source/gameengine/SceneGraph #source/gameengine/Physics/common #source/gameengine/Physics/Bullet' -incs += ' #source/gameengine/Physics/BlOde #source/gameengine/Physics/Dummy' -incs += ' #source/gameengine/Physics/Sumo #source/gameengine/Physics/Sumo/include' -incs += ' #source/gameengine/Physics/Sumo/Fuzzics/include #source/gameengine/Network/LoopBackNetwork' +incs += ' #source/gameengine/Physics/Dummy' incs += ' #source/blender/misc #source/blender/blenloader #extern/glew/include #source/blender/gpu' -cflags = [] -if env['OURPLATFORM'] == 'win32-vc': - cflags.append('/GR') - cflags.append('/Ox') - -incs += ' ' + env['BF_SOLID_INC'] incs += ' ' + env['BF_PYTHON_INC'] -incs += ' ' + env['BF_SDL_INC'] incs += ' ' + env['BF_BULLET_INC'] incs += ' ' + env['BF_OPENGL_INC'] -env.BlenderLib ( 'bf_ketsji', sources, Split(incs), [], libtype=['game','player'], priority=[25, 72], compileflags = cflags ) +if env['WITH_BF_SDL']: + incs += ' ' + env['BF_SDL_INC'] +else: + defs.append('DISABLE_SDL') + +if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): + if env['BF_DEBUG']: + defs.append('_DEBUG') # for Python + +env.BlenderLib ( 'bf_ketsji', sources, Split(incs), defs, libtype=['core','player'], priority=[320,45], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/Makefile b/source/gameengine/Makefile index 1d3bc8c2058..bcb4b9098e7 100644 --- a/source/gameengine/Makefile +++ b/source/gameengine/Makefile @@ -35,10 +35,10 @@ DIR = $(OCGDIR)/gameengine DIRS = BlenderRoutines DIRS += Converter DIRS += Expressions GameLogic Ketsji Rasterizer SceneGraph -DIRS += Network Physics +DIRS += Network Physics VideoTexture ifeq ($(WITH_BF_BLENDERGAMEENGINE),true) - DIRS += GamePlayer +# DIRS += GamePlayer endif include nan_subdirs.mk diff --git a/source/gameengine/Network/CMakeLists.txt b/source/gameengine/Network/CMakeLists.txt index 933f0550d0b..1e467a7d08d 100644 --- a/source/gameengine/Network/CMakeLists.txt +++ b/source/gameengine/Network/CMakeLists.txt @@ -27,10 +27,10 @@ FILE(GLOB SRC *.cpp) SET(INC - . - ../../../source/kernel/gen_system - ../../../intern/string - ../../../intern/moto/include + . + ../../../source/kernel/gen_system + ../../../intern/string + ../../../intern/moto/include ) BLENDERLIB(bf_ngnetwork "${SRC}" "${INC}") diff --git a/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt b/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt index 0b958920dc5..18e3d8ef496 100644 --- a/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt +++ b/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt @@ -27,10 +27,10 @@ SET(SRC NG_LoopBackNetworkDeviceInterface.cpp) SET(INC - . - ../../../../source/kernel/gen_system - ../../../../intern/string - ../../../../source/gameengine/Network + . + ../../../../source/kernel/gen_system + ../../../../intern/string + ../../../../source/gameengine/Network ) BLENDERLIB(bf_loopbacknetwork "${SRC}" "${INC}") diff --git a/source/gameengine/Network/LoopBackNetwork/SConscript b/source/gameengine/Network/LoopBackNetwork/SConscript index 987603f1a49..dd23e1327eb 100644 --- a/source/gameengine/Network/LoopBackNetwork/SConscript +++ b/source/gameengine/Network/LoopBackNetwork/SConscript @@ -5,4 +5,4 @@ sources = 'NG_LoopBackNetworkDeviceInterface.cpp' incs = '. #source/kernel/gen_system #intern/string #source/gameengine/Network' -env.BlenderLib ( 'bf_loopbacknetwork', Split(sources), Split(incs), defines=[],libtype=['game2', 'player'], priority=[25, 165] ) +env.BlenderLib ( 'bf_loopbacknetwork', Split(sources), Split(incs), defines=[],libtype=['core','player'], priority=[400,135] ) diff --git a/source/gameengine/Network/NG_NetworkDeviceInterface.h b/source/gameengine/Network/NG_NetworkDeviceInterface.h index 4a47774a762..2a2a909a04d 100644 --- a/source/gameengine/Network/NG_NetworkDeviceInterface.h +++ b/source/gameengine/Network/NG_NetworkDeviceInterface.h @@ -76,6 +76,13 @@ public: */ virtual STR_String GetNetworkVersion(void)=0; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:NG_NetworkDeviceInterface"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //NG_NETWORKDEVICEINTERFACE_H diff --git a/source/gameengine/Network/NG_NetworkMessage.h b/source/gameengine/Network/NG_NetworkMessage.h index 687c8120eca..a2f76dc1fae 100644 --- a/source/gameengine/Network/NG_NetworkMessage.h +++ b/source/gameengine/Network/NG_NetworkMessage.h @@ -32,6 +32,10 @@ #include "STR_HashedString.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class NG_NetworkMessage { static int s_nextID; @@ -122,6 +126,13 @@ public: int GetMessageID() { return m_uniqueMessageID; } + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:NG_NetworkMessage"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //NG_NETWORKMESSAGE_H diff --git a/source/gameengine/Network/NG_NetworkObject.h b/source/gameengine/Network/NG_NetworkObject.h index c01d76a47fc..4bf636bf011 100644 --- a/source/gameengine/Network/NG_NetworkObject.h +++ b/source/gameengine/Network/NG_NetworkObject.h @@ -32,6 +32,10 @@ #include "STR_String.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class NG_NetworkObject { STR_String m_name; @@ -39,6 +43,13 @@ public: NG_NetworkObject(); ~NG_NetworkObject(); const STR_String& GetName(); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:NG_NetworkObject"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //NG_NETWORKOBJECT_H diff --git a/source/gameengine/Network/NG_NetworkScene.cpp b/source/gameengine/Network/NG_NetworkScene.cpp index 22263a2bdda..f8e489a8f48 100644 --- a/source/gameengine/Network/NG_NetworkScene.cpp +++ b/source/gameengine/Network/NG_NetworkScene.cpp @@ -119,7 +119,7 @@ void NG_NetworkScene::AddObject(NG_NetworkObject* object) { if (! m_networkdevice->IsOnline()) return; - STR_String name = object->GetName(); + const STR_String& name = object->GetName(); m_networkObjects.insert(name, object); } @@ -130,7 +130,7 @@ void NG_NetworkScene::RemoveObject(NG_NetworkObject* object) { if (! m_networkdevice->IsOnline()) return; - STR_String name = object->GetName(); + const STR_String& name = object->GetName(); m_networkObjects.remove(name); } diff --git a/source/gameengine/Network/NG_NetworkScene.h b/source/gameengine/Network/NG_NetworkScene.h index 58de9cf6af2..d5d6e8e0534 100644 --- a/source/gameengine/Network/NG_NetworkScene.h +++ b/source/gameengine/Network/NG_NetworkScene.h @@ -34,6 +34,15 @@ #include "STR_HashedString.h" #include <vector> +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + +//MSVC defines SendMessage as a win api function, even though we aren't using it +#ifdef SendMessage + #undef SendMessage +#endif + class NG_NetworkDeviceInterface; class NG_NetworkScene @@ -47,7 +56,7 @@ class NG_NetworkScene TMessageMap m_messagesBySenderName; TMessageMap m_messagesBySubject; -public: +public: NG_NetworkScene(NG_NetworkDeviceInterface *nic); ~NG_NetworkScene(); @@ -95,6 +104,13 @@ protected: * @param map Message map with messages. */ void ClearMessageMap(TMessageMap& map); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:NG_NetworkScene"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__NG_NETWORKSCENE_H diff --git a/source/gameengine/Network/SConscript b/source/gameengine/Network/SConscript index 0778418045f..3883dc71c9c 100644 --- a/source/gameengine/Network/SConscript +++ b/source/gameengine/Network/SConscript @@ -5,4 +5,4 @@ sources = env.Glob('*.cpp') #'NG_NetworkMessage.cpp NG_NetworkObject.cpp NG_Netw incs = '. #source/kernel/gen_system #intern/string #intern/moto/include' -env.BlenderLib ( 'bf_ngnetwork', sources, Split(incs), [], libtype=['game2', 'player'], priority=[15, 160] ) +env.BlenderLib ( 'bf_ngnetwork', sources, Split(incs), [], libtype=['core','player'], priority=[400,130] ) diff --git a/source/gameengine/Physics/BlOde/Makefile b/source/gameengine/Physics/BlOde/Makefile deleted file mode 100644 index 1fbbf198377..00000000000 --- a/source/gameengine/Physics/BlOde/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -# -# $Id$ -# -# ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** -# -# - -LIBNAME = blode -DIR = $(OCGDIR)/gameengine/blphys/$(LIBNAME) - -include nan_compile.mk - -CCFLAGS += $(LEVEL_1_CPP_WARNINGS) - -CPPFLAGS += -I$(OPENGL_HEADERS) -CPPFLAGS += -I$(NAN_STRING)/include -CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) - -CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO)/include -I$(NAN_MOTO)/include -CPPFLAGS += -I$(NAN_ODE)/include -CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include -CPPFLAGS += -I../../Physics/common -CPPFLAGS += -I../../Physics/Dummy -# nlin: fix this, should put in NAN_ODE dir -#CPPFLAGS += -I./ode/ode/include diff --git a/source/gameengine/Physics/BlOde/OdePhysicsController.cpp b/source/gameengine/Physics/BlOde/OdePhysicsController.cpp deleted file mode 100644 index efe4554d970..00000000000 --- a/source/gameengine/Physics/BlOde/OdePhysicsController.cpp +++ /dev/null @@ -1,622 +0,0 @@ -/** - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * The contents of this file may be used under the terms of either the GNU - * General Public License Version 2 or later (the "GPL", see - * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or - * later (the "BL", see http://www.blender.org/BL/ ) which has to be - * bought from the Blender Foundation to become active, in which case the - * above mentioned GPL option does not apply. - * - * The Original Code is Copyright (C) 2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#define USE_ODE -#ifdef USE_ODE - -#include "OdePhysicsController.h" -#include "PHY_IMotionState.h" - -#include <ode/ode.h> - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// general to-do list for ODE physics. This is maintained in doxygen format. -// -/// \todo determine assignment time for bounding spheres. -/// -/// it appears you have to select "sphere" for bounding volume AND "draw bounds" -/// in order for a bounding sphere to be generated. otherwise a box is generated. -/// determine exactly when and how the bounding volumes are generated and make -/// this consistent. -/// } -/// -/// \todo bounding sphere size incorrect -/// -/// it appears NOT to use the size of the shown bounding sphere (button "draw bounds"). -/// it appears instead to use the size of the "size" dynamic parameter in the -/// gamebuttons but this "size" draws an incorrectly-sized circle on screen for the -/// bounding sphere (leftover skewed size calculation from sumo?) so figure out WHERE -/// its getting the radius from. -/// -/// \todo ODE collisions must fire collision actuator -/// -/// See OdePhysicsEnvironment::OdeNearCallback. If a sensor was created to check -/// for the presence of this collision, then in the NearCallback you need to -/// take appropriate action regarding the sensor - something like checking its -/// controller and if needed firing its actuator. Need to find similar code in -/// Fuzzics which fires collision controllers/actuators. -/// -/// \todo Are ghost collisions possible? -/// -/// How do ghost collisions work? Do they require collision detection through ODE -/// and NON-CREATION of contact-joint in OdeNearCallback? Currently OdeNearCallback -/// creates joints ALWAYS for collisions. -/// -/// \todo Why is KX_GameObject::addLinearVelocity commented out? -/// -/// Try putting this code back in. -/// -/// \todo Too many non-dynamic actors bogs down ODE physics -/// -/// Lots of "geoms" (ODE static geometry) probably slows down ode. Try a test file -/// with lots of static geometry - the game performance in Blender says it is -/// spending all its time in physics, and I bet all that time is in collision -/// detection. It's ode's non-hierarchical collision detection. -/// try making a separate ode test program (not within blender) with 1000 geoms and -/// see how fast it is. if it is really slow, there is the culprit. -/// isnt someone working on an improved ODE collision detector? check -/// ode mailing list. -/// -/// -/// \todo support collision of dynas with non-dynamic triangle meshes -/// -/// ODE has trimesh-collision support but only for trimeshes without a transform -/// matrix. update ODE tricollider to support a transform matrix. this will allow -/// moving trimeshes non-dynamically (e.g. through Ipos). then collide trimeshes -/// with dynas. this allows dynamic primitives (spheres, boxes) to collide with -/// non-dynamic or kinematically controlled tri-meshes. full dynamic trimesh to -/// dynamic trimesh support is hard because it requires (a) collision and penetration -/// depth for trimesh to trimesh and (hard to compute) (b) an intertia tensor -/// (easy to compute). -/// -/// a triangle mesh collision geometry should be created when the blender -/// bounding volume (F9, EDITBUTTONS) is set to "polyheder", since this is -/// currently the place where sphere/box selection is made -/// -/// \todo specify ODE ERP+CFM in blender interface -/// -/// when ODE physics selected, have to be able to set global cfm and erp. -/// per-joint erp/cfm could be handled in constraint window. -/// -/// \todo moving infinite mass objects should impart extra impulse to objects they collide with -/// -/// currently ODE's ERP pushes them apart but doesn't account for their motion. -/// you have to detect if one body in a collision is a non-dyna. This -/// requires adding a new accessor method to -/// KX_IPhysicsInterfaceController to access the hidden m_isDyna variable, -/// currently it can only be written, not read). If one of the bodies in a -/// collision is a non-dyna, then impart an extra impulse based on the -/// motion of the static object (using its last 2 frames as an approximation -/// of its linear and angular velocity). Linear velocity is easy to -/// approximate, but angular? you have orientation at this frame and -/// orientation at previous frame. The question is what is the angular -/// velocity which would have taken you from the previous frame's orientation -/// to this frame's orientation? -/// -/// \todo allow tweaking bounding volume size -/// -/// the scene converter currently uses the blender bounding volume of the selected -/// object as the geometry for ODE collision purposes. this is good and automatic -/// intuitive - lets you choose between cube, sphere, mesh. but you need to be able -/// to tweak this size for physics. -/// -/// \todo off center meshes totally wrong for ode -/// -/// ode uses x, y, z extents regradless of center. then places geom at center of object. -/// but visual geom is not necessarily at center. need to detect off-center situations. -/// then do what? treat it as an encapsulated off-center mass, or recenter it? -/// -/// i.o.w. recalculate center, or recalculate mass distribution (using encapsulation)? -/// -/// \todo allow off-center mass -/// -/// using ode geometry encapsulators -/// -/// \todo allow entering compound geoms for complex collision shapes specified as a union of simpler shapes -/// -/// The collision shape for arbitrary triangle meshes can probably in general be -///well approximated by a compound ODE geometry object, which is merely a combination -///of many primitives (capsule, sphere, box). I eventually want to add the ability -///to associate compound geometry objects with Blender gameobjects. I think one -///way of doing this would be to add a new button in the GameButtons, "RigidBodyCompound". -///If the object is "Dynamic" + "RigidBody", then the object's bounding volume (sphere, -///box) is created. If an object is "Dynamic" + "RigidBodyCompound", then the object itself -///will merely create a "wrapper" compound object, with the actual geometry objects -///being created from the object's children in Blender. E.g. if I wanted to make a -///compound collision object consisting of a sphere and 2 boxes, I would create a -///parent gameobject with the actual triangle mesh, and set its GameButtons to -///"RigidBodyCompound". I would then create 3 children of this object, 1 sphere and -///2 boxes, and set the GameButtons for the children to be "RigidBody". Then at -///scene conversion time, the scene converter sees "RigidBodyCompound" for the -///top-level object, then appropriately traverses the children and creates the compound -///collision geometry consisting of 2 boxes and a sphere. In this way, arbitrary -///mesh-mesh collision becomes much less necessary - the artist can (or must, -///depending on your point of view!) approximate the collision shape for arbitrary -///meshes with a combination of one or more primitive shapes. I think using the -///parent/child relationship in Blender and a new button "RigidBodyCompound" for the -///parent object of a compound is a feasible way of doing this in Blender. -/// -///See ODE demo test_boxstack and look at the code when you drop a compound object -///with the "X" key. -/// -/// \todo add visual specification of constraints -/// -/// extend the armature constraint system. by using empties and constraining one empty -/// to "copy location" of another, you can get a p2p constraint between the two empties. -/// by making the two empties each a parent of a blender object, you effectively have -/// a p2p constraint between 2 blender bodies. the scene converter can detect these -/// empties, detect the constraint, and generate an ODE constraint. -/// -/// then add a new constraint type "hinge" and "slider" to correspond to ODE joints. -/// e.g. a slider would be a constraint which restricts the axis of its object to lie -/// along the same line as another axis of a different object. e.g. you constrain x-axis -/// of one empty to lie along the same line as the z-axis of another empty; this gives -/// a slider joint. -/// -/// open questions: how to handle powered joints? to what extent should/must constraints -/// be enforced during modeling? use CCD-style algorithm in modeler to enforce constraints? -/// how about ODE powered constraints e.g. motors? -/// -/// \todo enable suspension of bodies -/// ODE offers native support for suspending dynas. but what about suspending non-dynas -/// (e.g. geoms)? suspending geoms is also necessary to ease the load of ODE's (simple?) -/// collision detector. suspending dynas and geoms is important for the activity culling, -/// which apparently works at a simple level. perhaps suspension should actually -/// remove or insert geoms/dynas into the ODE space/world? is this operation (insertion/ -/// removal) fast enough at run-time? test it. if fast enough, then suspension=remove from -/// ODE simulation, awakening=insertion into ODE simulation. -/// -/// \todo python interface for tweaking constraints via python -/// -/// \todo raytesting to support gameengine sensors that need it -/// -/// \todo investigate compatibility issues with old Blender 2.25 physics engine (sumo/fuzzics) -/// is it possible to have compatibility? how hard is it? how important is it? - - -ODEPhysicsController::ODEPhysicsController(bool dyna, bool fullRigidBody, - bool phantom, class PHY_IMotionState* motionstate, struct dxSpace* space, - struct dxWorld* world, float mass,float friction,float restitution, - bool implicitsphere,float center[3],float extents[3],float radius) - : - m_OdeDyna(dyna), - m_firstTime(true), - m_bFullRigidBody(fullRigidBody), - m_bPhantom(phantom), - m_bKinematic(false), - m_bPrevKinematic(false), - m_MotionState(motionstate), - m_OdeSuspendDynamics(false), - m_space(space), - m_world(world), - m_mass(mass), - m_friction(friction), - m_restitution(restitution), - m_bodyId(0), - m_geomId(0), - m_implicitsphere(implicitsphere), - m_radius(radius) -{ - m_center[0] = center[0]; - m_center[1] = center[1]; - m_center[2] = center[2]; - m_extends[0] = extents[0]; - m_extends[1] = extents[1]; - m_extends[2] = extents[2]; -}; - - -ODEPhysicsController::~ODEPhysicsController() -{ - if (m_geomId) - { - dGeomDestroy (m_geomId); - } -} - -float ODEPhysicsController::getMass() -{ - dMass mass; - dBodyGetMass(m_bodyId,&mass); - return mass.mass; -} - -////////////////////////////////////////////////////////////////////// -/// \todo Impart some extra impulse to dynamic objects when they collide with kinematically controlled "static" objects (ODE geoms), by using last 2 frames as 1st order approximation to the linear/angular velocity, and computing an appropriate impulse. Sumo (old physics engine) did this, see for details. -/// \todo handle scaling of static ODE geoms or fail with error message if Ipo tries to change scale of a static geom object - -bool ODEPhysicsController::SynchronizeMotionStates(float time) -{ - /** - 'Late binding' of the rigidbody, because the World Scaling is not available until the scenegraph is traversed - */ - - - if (m_firstTime) - { - m_firstTime=false; - - m_MotionState->calculateWorldTransformations(); - - dQuaternion worldquat; - float worldpos[3]; - -#ifdef dDOUBLE - m_MotionState->getWorldOrientation((float)worldquat[1], - (float)worldquat[2],(float)worldquat[3],(float)worldquat[0]); -#else - m_MotionState->getWorldOrientation(worldquat[1], - worldquat[2],worldquat[3],worldquat[0]); -#endif - m_MotionState->getWorldPosition(worldpos[0],worldpos[1],worldpos[2]); - - float scaling[3]; - m_MotionState->getWorldScaling(scaling[0],scaling[1],scaling[2]); - - if (!m_bPhantom) - { - if (m_implicitsphere) - { - m_geomId = dCreateSphere (m_space,m_radius*scaling[0]); - } else - { - m_geomId = dCreateBox (m_space, m_extends[0]*scaling[0],m_extends[1]*scaling[1],m_extends[2]*scaling[2]); - } - } else - { - m_geomId=0; - } - - if (m_geomId) - dGeomSetData(m_geomId,this); - - if (!this->m_OdeDyna) - { - if (!m_bPhantom) - { - dGeomSetPosition (this->m_geomId,worldpos[0],worldpos[1],worldpos[2]); - dMatrix3 R; - dQtoR (worldquat, R); - dGeomSetRotation (this->m_geomId,R); - } - } else - { - //it's dynamic, so create a 'model' - m_bodyId = dBodyCreate(this->m_world); - dBodySetPosition (m_bodyId,worldpos[0],worldpos[1],worldpos[2]); - dBodySetQuaternion (this->m_bodyId,worldquat); - //this contains both scalar mass and inertia tensor - dMass m; - float length=1,width=1,height=1; - dMassSetBox (&m,1,m_extends[0]*scaling[0],m_extends[1]*scaling[1],m_extends[2]*scaling[2]); - dMassAdjust (&m,this->m_mass); - dBodySetMass (m_bodyId,&m); - - if (!m_bPhantom) - { - dGeomSetBody (m_geomId,m_bodyId); - } - - - } - - if (this->m_OdeDyna && !m_bFullRigidBody) - { - // ?? huh? what to do here? - } - } - - - - if (m_OdeDyna) - { - if (this->m_OdeSuspendDynamics) - { - return false; - } - - const float* worldPos = (float *)dBodyGetPosition(m_bodyId); - m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]); - - const float* worldquat = (float *)dBodyGetQuaternion(m_bodyId); - m_MotionState->setWorldOrientation(worldquat[1],worldquat[2],worldquat[3],worldquat[0]); - } - else { - // not a dyna, so dynamics (i.e. this controller) has not updated - // anything. BUT! an Ipo or something else might have changed the - // position/orientation of this geometry. - // so update the static geom position - - /// \todo impart some extra impulse to colliding objects! - dQuaternion worldquat; - float worldpos[3]; - -#ifdef dDOUBLE - m_MotionState->getWorldOrientation((float)worldquat[1], - (float)worldquat[2],(float)worldquat[3],(float)worldquat[0]); -#else - m_MotionState->getWorldOrientation(worldquat[1], - worldquat[2],worldquat[3],worldquat[0]); -#endif - m_MotionState->getWorldPosition(worldpos[0],worldpos[1],worldpos[2]); - - float scaling[3]; - m_MotionState->getWorldScaling(scaling[0],scaling[1],scaling[2]); - - /// \todo handle scaling! what if Ipo changes scale of object? - // Must propagate to geom... is scaling geoms possible with ODE? Also - // what about scaling trimeshes, that is certainly difficult... - dGeomSetPosition (this->m_geomId,worldpos[0],worldpos[1],worldpos[2]); - dMatrix3 R; - dQtoR (worldquat, R); - dGeomSetRotation (this->m_geomId,R); - } - - return false; //it update the worldpos -} - - - - -// kinematic methods -void ODEPhysicsController::RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local) -{ - -} -void ODEPhysicsController::RelativeRotate(const float drot[9],bool local) -{ -} -void ODEPhysicsController::setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal) -{ - - dQuaternion worldquat; - worldquat[0] = quatReal; - worldquat[1] = quatImag0; - worldquat[2] = quatImag1; - worldquat[3] = quatImag2; - - if (!this->m_OdeDyna) - { - dMatrix3 R; - dQtoR (worldquat, R); - dGeomSetRotation (this->m_geomId,R); - } else - { - dBodySetQuaternion (m_bodyId,worldquat); - this->m_MotionState->setWorldOrientation(quatImag0,quatImag1,quatImag2,quatReal); - } - -} - -void ODEPhysicsController::getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal) -{ - float q[4]; - this->m_MotionState->getWorldOrientation(q[0],q[1],q[2],q[3]); - quatImag0=q[0]; - quatImag1=q[1]; - quatImag2=q[2]; - quatReal=q[3]; -} - -void ODEPhysicsController::getPosition(PHY__Vector3& pos) const -{ - m_MotionState->getWorldPosition(pos[0],pos[1],pos[2]); - -} - -void ODEPhysicsController::setPosition(float posX,float posY,float posZ) -{ - if (!m_bPhantom) - { - if (!this->m_OdeDyna) - { - dGeomSetPosition (m_geomId, posX, posY, posZ); - } else - { - dBodySetPosition (m_bodyId, posX, posY, posZ); - } - } -} -void ODEPhysicsController::setScaling(float scaleX,float scaleY,float scaleZ) -{ -} - -// physics methods -void ODEPhysicsController::ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local) -{ - if (m_OdeDyna) { - if(local) { - dBodyAddRelTorque(m_bodyId, torqueX, torqueY, torqueZ); - } else { - dBodyAddTorque (m_bodyId, torqueX, torqueY, torqueZ); - } - } -} - -void ODEPhysicsController::ApplyForce(float forceX,float forceY,float forceZ,bool local) -{ - if (m_OdeDyna) { - if(local) { - dBodyAddRelForce(m_bodyId, forceX, forceY, forceZ); - } else { - dBodyAddForce (m_bodyId, forceX, forceY, forceZ); - } - } -} - -void ODEPhysicsController::SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local) -{ - if (m_OdeDyna) { - if(local) { - // TODO: translate angular vel into local frame, then apply - } else { - dBodySetAngularVel (m_bodyId, ang_velX,ang_velY,ang_velZ); - } - } -} - -void ODEPhysicsController::SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local) -{ - if (m_OdeDyna) - { - dVector3 vel = {lin_velX,lin_velY,lin_velZ, 1.0}; - if (local) - { - dMatrix3 worldmat; - dVector3 localvel; - dQuaternion worldquat; - -#ifdef dDOUBLE - m_MotionState->getWorldOrientation((float)worldquat[1], - (float)worldquat[2], (float)worldquat[3],(float)worldquat[0]); -#else - m_MotionState->getWorldOrientation(worldquat[1],worldquat[2], - worldquat[3],worldquat[0]); -#endif - dQtoR (worldquat, worldmat); - - dMULTIPLY0_331 (localvel,worldmat,vel); - dBodySetLinearVel (m_bodyId, localvel[0],localvel[1],localvel[2]); - - } else - { - dBodySetLinearVel (m_bodyId, lin_velX,lin_velY,lin_velZ); - } - } -} - -void ODEPhysicsController::applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ) -{ - if (m_OdeDyna) - { - //apply linear and angular effect - const dReal* linvel = dBodyGetLinearVel(m_bodyId); - float mass = getMass(); - if (mass >= 0.00001f) - { - float massinv = 1.f/mass; - float newvel[3]; - newvel[0]=linvel[0]+impulseX*massinv; - newvel[1]=linvel[1]+impulseY*massinv; - newvel[2]=linvel[2]+impulseZ*massinv; - dBodySetLinearVel(m_bodyId,newvel[0],newvel[1],newvel[2]); - - const float* worldPos = (float *)dBodyGetPosition(m_bodyId); - - const float* angvelc = (float *)dBodyGetAngularVel(m_bodyId); - float angvel[3]; - angvel[0]=angvelc[0]; - angvel[1]=angvelc[1]; - angvel[2]=angvelc[2]; - - dVector3 impulse; - impulse[0]=impulseX; - impulse[1]=impulseY; - impulse[2]=impulseZ; - - dVector3 ap; - ap[0]=attachX-worldPos[0]; - ap[1]=attachY-worldPos[1]; - ap[2]=attachZ-worldPos[2]; - - dCROSS(angvel,+=,ap,impulse); - dBodySetAngularVel(m_bodyId,angvel[0],angvel[1],angvel[2]); - - } - - } - -} - -void ODEPhysicsController::SuspendDynamics() -{ - -} - -void ODEPhysicsController::RestoreDynamics() -{ - -} - - -/** - reading out information from physics -*/ -void ODEPhysicsController::GetLinearVelocity(float& linvX,float& linvY,float& linvZ) -{ - if (m_OdeDyna) - { - const float* vel = (float *)dBodyGetLinearVel(m_bodyId); - linvX = vel[0]; - linvY = vel[1]; - linvZ = vel[2]; - } else - { - linvX = 0.f; - linvY = 0.f; - linvZ = 0.f; - - } -} -/** - GetVelocity parameters are in geometric coordinates (Origin is not center of mass!). -*/ -void ODEPhysicsController::GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ) -{ - -} - - -void ODEPhysicsController::getReactionForce(float& forceX,float& forceY,float& forceZ) -{ - -} -void ODEPhysicsController::setRigidBody(bool rigid) -{ - -} - - -void ODEPhysicsController::PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl) -{ - m_MotionState = motionstate; - m_bKinematic = false; - m_bPrevKinematic = false; - m_firstTime = true; -} - - -void ODEPhysicsController::SetSimulatedTime(float time) -{ -} - - -void ODEPhysicsController::WriteMotionStateToDynamics(bool nondynaonly) -{ - -} -#endif diff --git a/source/gameengine/Physics/BlOde/OdePhysicsController.h b/source/gameengine/Physics/BlOde/OdePhysicsController.h deleted file mode 100644 index 925f5b6686a..00000000000 --- a/source/gameengine/Physics/BlOde/OdePhysicsController.h +++ /dev/null @@ -1,159 +0,0 @@ -/** - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * The contents of this file may be used under the terms of either the GNU - * General Public License Version 2 or later (the "GPL", see - * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or - * later (the "BL", see http://www.blender.org/BL/ ) which has to be - * bought from the Blender Foundation to become active, in which case the - * above mentioned GPL option does not apply. - * - * The Original Code is Copyright (C) 2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ -#ifndef __ODE_PHYSICSCONTROLLER_H -#define __ODE_PHYSICSCONTROLLER_H - - -#include "PHY_IPhysicsController.h" - -/** - ODE Physics Controller, a special kind of a PhysicsController. - A Physics Controller is a special kind of Scene Graph Transformation Controller. - Each time the scene graph get's updated, the controller get's a chance - in the 'Update' method to reflect changes. -*/ - -class ODEPhysicsController : public PHY_IPhysicsController - -{ - - bool m_OdeDyna; - -public: - ODEPhysicsController( - bool dyna, - bool fullRigidBody, - bool phantom, - class PHY_IMotionState* motionstate, - struct dxSpace* space, - struct dxWorld* world, - float mass, - float friction, - float restitution, - bool implicitsphere, - float center[3], - float extends[3], - float radius); - - virtual ~ODEPhysicsController(); - - // kinematic methods - virtual void RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local); - virtual void RelativeRotate(const float drot[9],bool local); - virtual void getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal); - virtual void setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal); - virtual void setPosition(float posX,float posY,float posZ); - virtual void getPosition(PHY__Vector3& pos) const; - - virtual void setScaling(float scaleX,float scaleY,float scaleZ); - - // physics methods - virtual void ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local); - virtual void ApplyForce(float forceX,float forceY,float forceZ,bool local); - virtual void SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local); - virtual void SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local); - virtual void applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ); - virtual void SetActive(bool active){}; - virtual void SuspendDynamics(); - virtual void RestoreDynamics(); - virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) - { - //todo ? - } - - - /** - reading out information from physics - */ - virtual void GetLinearVelocity(float& linvX,float& linvY,float& linvZ); - /** - GetVelocity parameters are in geometric coordinates (Origin is not center of mass!). - */ - virtual void GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ); - virtual float getMass(); - virtual void getReactionForce(float& forceX,float& forceY,float& forceZ); - virtual void setRigidBody(bool rigid); - - - virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl); - - // \todo remove next line ! - virtual void SetSimulatedTime(float time); - - - virtual void WriteDynamicsToMotionState() {}; - virtual void WriteMotionStateToDynamics(bool nondynaonly); - - /** - call from Scene Graph Node to 'update'. - */ - virtual bool SynchronizeMotionStates(float time); - - virtual void calcXform(){} - virtual void SetMargin(float margin) {} - virtual float GetMargin() const {return 0.f;} - virtual float GetRadius() const {return 0.f;} - virtual void SetRadius(float margin) {} - - // clientinfo for raycasts for example - virtual void* getNewClientInfo() { return m_clientInfo;} - virtual void setNewClientInfo(void* clientinfo) {m_clientInfo = clientinfo;}; - void* m_clientInfo; - - struct dxBody* GetOdeBodyId() { return m_bodyId; } - - float getFriction() { return m_friction;} - float getRestitution() { return m_restitution;} - - - -private: - - bool m_firstTime; - bool m_bFullRigidBody; - bool m_bPhantom; // special flag for objects that are not affected by physics 'resolver' - - // data to calculate fake velocities for kinematic objects (non-dynas) - bool m_bKinematic; - bool m_bPrevKinematic; - - - float m_lastTime; - bool m_OdeSuspendDynamics; - class PHY_IMotionState* m_MotionState; - - //Ode specific members - struct dxBody* m_bodyId; - struct dxGeom* m_geomId; - struct dxSpace* m_space; - struct dxWorld* m_world; - float m_mass; - float m_friction; - float m_restitution; - bool m_implicitsphere; - float m_center[3]; - float m_extends[3]; - float m_radius; -}; - -#endif //__ODE_PHYSICSCONTROLLER_H - diff --git a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp deleted file mode 100644 index 2e8ee31058f..00000000000 --- a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/** - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * The contents of this file may be used under the terms of either the GNU - * General Public License Version 2 or later (the "GPL", see - * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or - * later (the "BL", see http://www.blender.org/BL/ ) which has to be - * bought from the Blender Foundation to become active, in which case the - * above mentioned GPL option does not apply. - * - * The Original Code is Copyright (C) 2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ -#include "OdePhysicsEnvironment.h" -#include "PHY_IMotionState.h" -#include "OdePhysicsController.h" - -#include <ode/ode.h> -#include <../ode/src/joint.h> -#include <ode/odemath.h> - -ODEPhysicsEnvironment::ODEPhysicsEnvironment() -{ - m_OdeWorld = dWorldCreate(); - m_OdeSpace = dHashSpaceCreate(); - m_OdeContactGroup = dJointGroupCreate (0); - dWorldSetCFM (m_OdeWorld,1e-5f); - - m_JointGroup = dJointGroupCreate(0); - - setFixedTimeStep(true,1.f/60.f); -} - - - -ODEPhysicsEnvironment::~ODEPhysicsEnvironment() -{ - dJointGroupDestroy (m_OdeContactGroup); - dJointGroupDestroy (m_JointGroup); - - dSpaceDestroy (m_OdeSpace); - dWorldDestroy (m_OdeWorld); -} - - - -void ODEPhysicsEnvironment::setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep) -{ - m_useFixedTimeStep = useFixedTimeStep; - - if (useFixedTimeStep) - { - m_fixedTimeStep = fixedTimeStep; - } else - { - m_fixedTimeStep = 0.f; - } - m_currentTime = 0.f; - - //todo:implement fixed timestepping - -} -float ODEPhysicsEnvironment::getFixedTimeStep() -{ - return m_fixedTimeStep; -} - - - -bool ODEPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep1) -{ - - float deltaTime = timeStep1; - int numSteps = 1; - - if (m_useFixedTimeStep) - { - m_currentTime += timeStep1; - // equal to subSampling (might be a little smaller). - numSteps = (int)(m_currentTime / m_fixedTimeStep); - m_currentTime -= m_fixedTimeStep * (float)numSteps; - deltaTime = m_fixedTimeStep; - //todo: experiment by smoothing the remaining time over the substeps - } - - for (int i=0;i<numSteps;i++) - { - // ode collision update - dSpaceCollide (m_OdeSpace,this,&ODEPhysicsEnvironment::OdeNearCallback); - - int m_odeContacts = GetNumOdeContacts(); - - //physics integrator + resolver update - //dWorldStep (m_OdeWorld,deltaTime); - //dWorldQuickStep (m_OdeWorld,deltaTime); - //dWorldID w, dReal stepsize) - - //clear collision points - this->ClearOdeContactGroup(); - } - return true; -} - -void ODEPhysicsEnvironment::setGravity(float x,float y,float z) -{ - dWorldSetGravity (m_OdeWorld,x,y,z); -} - - - -int ODEPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type, - float pivotX,float pivotY,float pivotZ,float axisX,float axisY,float axisZ) -{ - - int constraintid = 0; - ODEPhysicsController* dynactrl = (ODEPhysicsController*)ctrl; - ODEPhysicsController* dynactrl2 = (ODEPhysicsController*)ctrl2; - - switch (type) - { - case PHY_POINT2POINT_CONSTRAINT: - { - if (dynactrl) - { - dJointID jointid = dJointCreateBall (m_OdeWorld,m_JointGroup); - struct dxBody* bodyid1 = dynactrl->GetOdeBodyId(); - struct dxBody* bodyid2=0; - const dReal* pos = dBodyGetPosition(bodyid1); - const dReal* R = dBodyGetRotation(bodyid1); - dReal offset[3] = {pivotX,pivotY,pivotZ}; - dReal newoffset[3]; - dMULTIPLY0_331 (newoffset,R,offset); - newoffset[0] += pos[0]; - newoffset[1] += pos[1]; - newoffset[2] += pos[2]; - - - if (dynactrl2) - bodyid2 = dynactrl2->GetOdeBodyId(); - - dJointAttach (jointid, bodyid1, bodyid2); - - dJointSetBallAnchor (jointid, newoffset[0], newoffset[1], newoffset[2]); - - constraintid = (int) jointid; - } - break; - } - case PHY_LINEHINGE_CONSTRAINT: - { - if (dynactrl) - { - dJointID jointid = dJointCreateHinge (m_OdeWorld,m_JointGroup); - struct dxBody* bodyid1 = dynactrl->GetOdeBodyId(); - struct dxBody* bodyid2=0; - const dReal* pos = dBodyGetPosition(bodyid1); - const dReal* R = dBodyGetRotation(bodyid1); - dReal offset[3] = {pivotX,pivotY,pivotZ}; - dReal axisset[3] = {axisX,axisY,axisZ}; - - dReal newoffset[3]; - dReal newaxis[3]; - dMULTIPLY0_331 (newaxis,R,axisset); - - dMULTIPLY0_331 (newoffset,R,offset); - newoffset[0] += pos[0]; - newoffset[1] += pos[1]; - newoffset[2] += pos[2]; - - - if (dynactrl2) - bodyid2 = dynactrl2->GetOdeBodyId(); - - dJointAttach (jointid, bodyid1, bodyid2); - - dJointSetHingeAnchor (jointid, newoffset[0], newoffset[1], newoffset[2]); - dJointSetHingeAxis(jointid,newaxis[0],newaxis[1],newaxis[2]); - - constraintid = (int) jointid; - } - break; - } - default: - { - //not yet - } - } - - return constraintid; - -} - -void ODEPhysicsEnvironment::removeConstraint(void *constraintid) -{ - if (constraintid) - { - dJointDestroy((dJointID) constraintid); - } -} - -PHY_IPhysicsController* ODEPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ) -{ - - //m_OdeWorld - //collision detection / raytesting - return NULL; -} - - -void ODEPhysicsEnvironment::OdeNearCallback (void *data, dGeomID o1, dGeomID o2) -{ - // \todo if this is a registered collision sensor - // fire the callback - - int i; - // if (o1->body && o2->body) return; - ODEPhysicsEnvironment* env = (ODEPhysicsEnvironment*) data; - dBodyID b1,b2; - - b1 = dGeomGetBody(o1); - b2 = dGeomGetBody(o2); - // exit without doing anything if the two bodies are connected by a joint - if (b1 && b2 && dAreConnected (b1,b2)) return; - - ODEPhysicsController * ctrl1 =(ODEPhysicsController *)dGeomGetData(o1); - ODEPhysicsController * ctrl2 =(ODEPhysicsController *)dGeomGetData(o2); - float friction=ctrl1->getFriction(); - float restitution = ctrl1->getRestitution(); - //for friction, take minimum - - friction=(friction < ctrl2->getFriction() ? - friction :ctrl2->getFriction()); - - //restitution:take minimum - restitution = restitution < ctrl2->getRestitution()? - restitution : ctrl2->getRestitution(); - - dContact contact[3]; // up to 3 contacts per box - for (i=0; i<3; i++) { - contact[i].surface.mode = dContactBounce; //dContactMu2; - contact[i].surface.mu = friction;//dInfinity; - contact[i].surface.mu2 = 0; - contact[i].surface.bounce = restitution;//0.5; - contact[i].surface.bounce_vel = 0.1f; - contact[i].surface.slip1=0.0; - } - - if (int numc = dCollide (o1,o2,3,&contact[0].geom,sizeof(dContact))) { - // dMatrix3 RI; - // dRSetIdentity (RI); - // const dReal ss[3] = {0.02,0.02,0.02}; - for (i=0; i<numc; i++) { - dJointID c = dJointCreateContact (env->m_OdeWorld,env->m_OdeContactGroup,contact+i); - dJointAttach (c,b1,b2); - } - } -} - - -void ODEPhysicsEnvironment::ClearOdeContactGroup() -{ - dJointGroupEmpty (m_OdeContactGroup); -} - -int ODEPhysicsEnvironment::GetNumOdeContacts() -{ - return m_OdeContactGroup->num; -} - diff --git a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h deleted file mode 100644 index dcc87d614c0..00000000000 --- a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * The contents of this file may be used under the terms of either the GNU - * General Public License Version 2 or later (the "GPL", see - * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or - * later (the "BL", see http://www.blender.org/BL/ ) which has to be - * bought from the Blender Foundation to become active, in which case the - * above mentioned GPL option does not apply. - * - * The Original Code is Copyright (C) 2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ -#ifndef _ODEPHYSICSENVIRONMENT -#define _ODEPHYSICSENVIRONMENT - - -#include "PHY_IPhysicsEnvironment.h" - -/** -* Physics Environment takes care of stepping the simulation and is a container for physics entities (rigidbodies,constraints, materials etc.) -* A derived class may be able to 'construct' entities by loading and/or converting -*/ -class ODEPhysicsEnvironment : public PHY_IPhysicsEnvironment -{ - - bool m_useFixedTimeStep; - float m_fixedTimeStep; - float m_currentTime; - -public: - ODEPhysicsEnvironment(); - virtual ~ODEPhysicsEnvironment(); - virtual void beginFrame() {} - virtual void endFrame() {} - - -// Perform an integration step of duration 'timeStep'. - virtual bool proceedDeltaTime(double curTime,float timeStep); - virtual void setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep); - virtual float getFixedTimeStep(); - - virtual void setGravity(float x,float y,float z); - virtual int createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type, - float pivotX,float pivotY,float pivotZ, - float axisX,float axisY,float axisZ); - - virtual void removeConstraint(void * constraintid); - virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ); - - - //gamelogic callbacks - virtual void addSensor(PHY_IPhysicsController* ctrl) {} - virtual void removeSensor(PHY_IPhysicsController* ctrl) {} - virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user) - { - } - virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl) {} - virtual void removeCollisionCallback(PHY_IPhysicsController* ctrl) {} - virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position) {return 0;} - virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight) { return 0;} - - - - struct dxWorld* GetOdeWorld() { return m_OdeWorld; }; - struct dxSpace* GetOdeSpace() { return m_OdeSpace;}; - -private: - - - // ODE physics response - struct dxWorld* m_OdeWorld; - // ODE collision detection - struct dxSpace* m_OdeSpace; - void ClearOdeContactGroup(); - struct dxJointGroup* m_OdeContactGroup; - struct dxJointGroup* m_JointGroup; - - static void OdeNearCallback(void *data, struct dxGeom* o1, struct dxGeom* o2); - int GetNumOdeContacts(); - -}; - -#endif //_ODEPHYSICSENVIRONMENT - diff --git a/source/gameengine/Physics/BlOde/SConscript b/source/gameengine/Physics/BlOde/SConscript deleted file mode 100644 index 90e949d2d86..00000000000 --- a/source/gameengine/Physics/BlOde/SConscript +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/python -Import ('user_options_dict') -Import ('library_env') - -phy_ode_env = library_env.Copy () - -source_files = ['OdePhysicsController.cpp', - 'OdePhysicsEnvironment.cpp'] - -phy_ode_env.Append (CPPPATH=['.', - '../common', - ]) -phy_ode_env.Append (CPPPATH=user_options_dict['ODE_INCLUDE']) - -phy_ode_env.Library (target='#'+user_options_dict['BUILD_DIR']+'/lib/PHY_Ode', source=source_files) diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt index 6c733786caf..da885122a4f 100644 --- a/source/gameengine/Physics/Bullet/CMakeLists.txt +++ b/source/gameengine/Physics/Bullet/CMakeLists.txt @@ -24,16 +24,26 @@ # # ***** END GPL LICENSE BLOCK ***** -SET(SRC CcdPhysicsEnvironment.cpp CcdPhysicsController.cpp) +SET(SRC CcdPhysicsEnvironment.cpp CcdPhysicsController.cpp CcdGraphicController.cpp) SET(INC - . - ../common - ../../../../extern/bullet2/src - ../../../../intern/moto/include - ../../../kernel/gen_system - ../../../../intern/string - ../../Rasterizer + . + ../common + ../../../../extern/bullet2/src + ../../../../extern/glew/include + ../../../../intern/moto/include + ../../../../intern/guardedalloc + ../../../kernel/gen_system + ../../../../intern/string + ../../Rasterizer + ../../Ketsji + ../../Expressions + ../../GameLogic + ../../SceneGraph + ../../../../source/blender/makesdna + ../../../../source/blender/blenlib + ../../../../source/blender/blenkernel + ${PYTHON_INC} ) BLENDERLIB(bf_bullet "${SRC}" "${INC}") diff --git a/source/gameengine/Physics/Bullet/CcdGraphicController.cpp b/source/gameengine/Physics/Bullet/CcdGraphicController.cpp new file mode 100644 index 00000000000..2dbbb7fa4a0 --- /dev/null +++ b/source/gameengine/Physics/Bullet/CcdGraphicController.cpp @@ -0,0 +1,134 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "CcdPhysicsEnvironment.h" +#include "CcdGraphicController.h" +#include "btBulletDynamicsCommon.h" +#include "MT_Point3.h" + + +CcdGraphicController::CcdGraphicController (CcdPhysicsEnvironment* phyEnv, PHY_IMotionState* motionState) : + m_localAabbMin(0.f, 0.f, 0.f), + m_localAabbMax(0.f, 0.f, 0.f), + m_motionState(motionState), + m_phyEnv(phyEnv), + m_handle(NULL), + m_newClientInfo(NULL) +{ +} + +CcdGraphicController::~CcdGraphicController() +{ + if (m_phyEnv) + m_phyEnv->removeCcdGraphicController(this); + + if (m_motionState) + delete m_motionState; +} + +void CcdGraphicController::setLocalAabb(const btVector3& aabbMin,const btVector3& aabbMax) +{ + m_localAabbMin = aabbMin; + m_localAabbMax = aabbMax; + SetGraphicTransform(); +} + +void CcdGraphicController::setLocalAabb(const MT_Point3& aabbMin,const MT_Point3& aabbMax) +{ + m_localAabbMin.setValue(aabbMin[0],aabbMin[1],aabbMin[2]); + m_localAabbMax.setValue(aabbMax[0],aabbMax[1],aabbMax[2]); + SetGraphicTransform(); +} + +void CcdGraphicController::setLocalAabb(const PHY__Vector3& aabbMin,const PHY__Vector3& aabbMax) +{ + m_localAabbMin.setValue(aabbMin[0],aabbMin[1],aabbMin[2]); + m_localAabbMax.setValue(aabbMax[0],aabbMax[1],aabbMax[2]); + SetGraphicTransform(); +} + +void CcdGraphicController::setLocalAabb(const float* aabbMin,const float* aabbMax) +{ + m_localAabbMin.setValue(aabbMin[0],aabbMin[1],aabbMin[2]); + m_localAabbMax.setValue(aabbMax[0],aabbMax[1],aabbMax[2]); + SetGraphicTransform(); +} + +void CcdGraphicController::getAabb(btVector3& aabbMin, btVector3& aabbMax) +{ + btVector3 pos; + btVector3 scale; + float ori[12]; + m_motionState->getWorldPosition(pos.m_floats[0],pos.m_floats[1],pos.m_floats[2]); + m_motionState->getWorldScaling(scale.m_floats[0],scale.m_floats[1],scale.m_floats[2]); + m_motionState->getWorldOrientation(ori); + btMatrix3x3 rot(ori[0], ori[4], ori[8], + ori[1], ori[5], ori[9], + ori[2], ori[6], ori[10]); + + btVector3 localAabbMin = m_localAabbMin; + btVector3 localAabbMax = m_localAabbMax; + btVector3 tmpAabbMin = m_localAabbMin * scale; + btVector3 tmpAabbMax = m_localAabbMax * scale; + + localAabbMin[0] = (scale.getX() >= 0.) ? tmpAabbMin[0] : tmpAabbMax[0]; + localAabbMin[1] = (scale.getY() >= 0.) ? tmpAabbMin[1] : tmpAabbMax[1]; + localAabbMin[2] = (scale.getZ() >= 0.) ? tmpAabbMin[2] : tmpAabbMax[2]; + localAabbMax[0] = (scale.getX() <= 0.) ? tmpAabbMin[0] : tmpAabbMax[0]; + localAabbMax[1] = (scale.getY() <= 0.) ? tmpAabbMin[1] : tmpAabbMax[1]; + localAabbMax[2] = (scale.getZ() <= 0.) ? tmpAabbMin[2] : tmpAabbMax[2]; + + btVector3 localHalfExtents = btScalar(0.5)*(localAabbMax-localAabbMin); + btVector3 localCenter = btScalar(0.5)*(localAabbMax+localAabbMin); + + btMatrix3x3 abs_b = rot.absolute(); + btVector3 center = rot*localCenter + pos; + btVector3 extent = abs_b*localHalfExtents; + aabbMin = center - extent; + aabbMax = center + extent; +} + +bool CcdGraphicController::SetGraphicTransform() +{ + if (!m_handle) + return false; + btVector3 aabbMin; + btVector3 aabbMax; + getAabb(aabbMin, aabbMax); + // update Aabb in broadphase + m_phyEnv->getCullingTree()->setAabb(m_handle,aabbMin,aabbMax,NULL); + return true; +} + +PHY_IGraphicController* CcdGraphicController::GetReplica(class PHY_IMotionState* motionState) +{ + CcdGraphicController* replica = new CcdGraphicController(*this); + replica->m_motionState = motionState; + replica->m_newClientInfo = NULL; + replica->m_handle = NULL; + // don't add the graphic controller now: work around a bug in Bullet with rescaling, + // (the scale of the controller is not yet defined). + //m_phyEnv->addCcdGraphicController(replica); + return replica; +} + +void CcdGraphicController::Activate(bool active) +{ + if (active) + m_phyEnv->addCcdGraphicController(this); + else + m_phyEnv->removeCcdGraphicController(this); + +} diff --git a/source/gameengine/Physics/Bullet/CcdGraphicController.h b/source/gameengine/Physics/Bullet/CcdGraphicController.h new file mode 100644 index 00000000000..99885eb99ee --- /dev/null +++ b/source/gameengine/Physics/Bullet/CcdGraphicController.h @@ -0,0 +1,86 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef BULLET2_GRAPHICCONTROLLER_H +#define BULLET2_GRAPHICCONTROLLER_H + +#include "PHY_IGraphicController.h" + +#include "btBulletDynamicsCommon.h" +#include "LinearMath/btTransform.h" + +#include "PHY_IMotionState.h" +#include "MT_Point3.h" + +class CcdPhysicsEnvironment; +class btCollisionObject; + +///CcdGraphicController is a graphic object that supports view frustrum culling and occlusion +class CcdGraphicController : public PHY_IGraphicController +{ +public: + CcdGraphicController(CcdPhysicsEnvironment* phyEnv, PHY_IMotionState* motionState); + + virtual ~CcdGraphicController(); + + void setLocalAabb(const btVector3& aabbMin,const btVector3& aabbMax); + void setLocalAabb(const MT_Point3& aabbMin,const MT_Point3& aabbMax); + virtual void setLocalAabb(const PHY__Vector3& aabbMin,const PHY__Vector3& aabbMax); + virtual void setLocalAabb(const float aabbMin[3],const float aabbMax[3]); + + PHY_IMotionState* GetMotionState() { return m_motionState; } + void getAabb(btVector3& aabbMin, btVector3& aabbMax); + + virtual void setBroadphaseHandle(btBroadphaseProxy* handle) { m_handle = handle; } + virtual btBroadphaseProxy* getBroadphaseHandle() { return m_handle; } + + //////////////////////////////////// + // PHY_IGraphicController interface + //////////////////////////////////// + + /** + * Updates the Aabb based on the motion state + */ + virtual bool SetGraphicTransform(); + /** + * Add/remove to environment + */ + virtual void Activate(bool active); + + // client info for culling + virtual void* getNewClientInfo() { return m_newClientInfo; } + virtual void setNewClientInfo(void* clientinfo) { m_newClientInfo = clientinfo; } + virtual PHY_IGraphicController* GetReplica(class PHY_IMotionState* motionstate); + +private: + // unscaled aabb corner + btVector3 m_localAabbMin; + btVector3 m_localAabbMax; + + PHY_IMotionState* m_motionState; + CcdPhysicsEnvironment* m_phyEnv; + btBroadphaseProxy* m_handle; + void* m_newClientInfo; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CcdGraphicController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif //BULLET2_PHYSICSCONTROLLER_H diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index c9c30c1b450..df8dc3560ac 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -16,18 +16,31 @@ subject to the following restrictions: #include "CcdPhysicsController.h" #include "btBulletDynamicsCommon.h" #include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" + +#include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h" + #include "PHY_IMotionState.h" #include "CcdPhysicsEnvironment.h" #include "RAS_MeshObject.h" +#include "KX_GameObject.h" + #include "BulletSoftBody/btSoftBody.h" #include "BulletSoftBody//btSoftBodyInternals.h" #include "BulletSoftBody/btSoftBodyHelpers.h" #include "LinearMath/btConvexHull.h" #include "BulletCollision/Gimpact/btGImpactShape.h" +#include "BulletCollision/Gimpact/btGImpactShape.h" #include "BulletSoftBody/btSoftRigidDynamicsWorld.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +extern "C"{ +#include "BKE_cdderivedmesh.h" +} + class BP_Proxy; ///todo: fill all the empty CcdPhysicsController methods, hook them up to the btRigidBody class @@ -74,23 +87,26 @@ CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci) ///??? -#ifdef WIN32 +/*#ifdef WIN32 if (GetRigidBody() && !GetRigidBody()->isStaticObject()) GetRigidBody()->setLinearVelocity(startVel); -#endif +#endif*/ } -btTransform CcdPhysicsController::GetTransformFromMotionState(PHY_IMotionState* motionState) +btTransform& CcdPhysicsController::GetTransformFromMotionState(PHY_IMotionState* motionState) { - btTransform trans; - float tmp[3]; - motionState->getWorldPosition(tmp[0],tmp[1],tmp[2]); - trans.setOrigin(btVector3(tmp[0],tmp[1],tmp[2])); - - btQuaternion orn; - motionState->getWorldOrientation(orn[0],orn[1],orn[2],orn[3]); - trans.setRotation(orn); + static btTransform trans; + btVector3 tmp; + motionState->getWorldPosition(tmp.m_floats[0], tmp.m_floats[1], tmp.m_floats[2]); + trans.setOrigin(tmp); + + float ori[12]; + motionState->getWorldOrientation(ori); + trans.getBasis().setFromOpenGLSubMatrix(ori); + //btQuaternion orn; + //motionState->getWorldOrientation(orn[0],orn[1],orn[2],orn[3]); + //trans.setRotation(orn); return trans; } @@ -107,18 +123,18 @@ public: } - virtual void getWorldTransform(btTransform& worldTrans ) const + void getWorldTransform(btTransform& worldTrans ) const { - float pos[3]; - float quatOrn[4]; + btVector3 pos; + float ori[12]; - m_blenderMotionState->getWorldPosition(pos[0],pos[1],pos[2]); - m_blenderMotionState->getWorldOrientation(quatOrn[0],quatOrn[1],quatOrn[2],quatOrn[3]); - worldTrans.setOrigin(btVector3(pos[0],pos[1],pos[2])); - worldTrans.setBasis(btMatrix3x3(btQuaternion(quatOrn[0],quatOrn[1],quatOrn[2],quatOrn[3]))); + m_blenderMotionState->getWorldPosition(pos.m_floats[0],pos.m_floats[1],pos.m_floats[2]); + m_blenderMotionState->getWorldOrientation(ori); + worldTrans.setOrigin(pos); + worldTrans.getBasis().setFromOpenGLSubMatrix(ori); } - virtual void setWorldTransform(const btTransform& worldTrans) + void setWorldTransform(const btTransform& worldTrans) { m_blenderMotionState->setWorldPosition(worldTrans.getOrigin().getX(),worldTrans.getOrigin().getY(),worldTrans.getOrigin().getZ()); btQuaternion rotQuat = worldTrans.getRotation(); @@ -171,12 +187,12 @@ void CcdPhysicsController::CreateRigidbody() rbci.m_restitution = m_cci.m_restitution; - int nodecount = 0; + + - int numtriangles = 1; btVector3 p(0,0,0);// = getOrigin(); - btScalar h = 1.f; + btSoftRigidDynamicsWorld* softDynaWorld = (btSoftRigidDynamicsWorld*)m_cci.m_physicsEnv->getDynamicsWorld(); @@ -282,7 +298,11 @@ void CcdPhysicsController::CreateRigidbody() } } - + if (m_cci.m_margin > 0.f) + { + psb->getCollisionShape()->setMargin(m_cci.m_margin); + psb->updateBounds(); + } m_object = psb; @@ -482,10 +502,12 @@ void CcdPhysicsController::CreateRigidbody() //convert collision flags! //special case: a near/radar sensor controller should not be defined static or it will //generate loads of static-static collision messages on the console - if ((m_cci.m_collisionFilterGroup & CcdConstructionInfo::SensorFilter) != 0) + if (m_cci.m_bSensor) { // reset the flags that have been set so far GetCollisionObject()->setCollisionFlags(0); + // sensor must never go to sleep: they need to detect continously + GetCollisionObject()->setActivationState(DISABLE_DEACTIVATION); } GetCollisionObject()->setCollisionFlags(m_object->getCollisionFlags() | m_cci.m_collisionFlags); btRigidBody* body = GetRigidBody(); @@ -499,6 +521,8 @@ void CcdPhysicsController::CreateRigidbody() { body->setAngularFactor(0.f); } + body->setContactProcessingThreshold(m_cci.m_contactProcessingThreshold); + } if (m_object && m_cci.m_do_anisotropic) { @@ -507,7 +531,7 @@ void CcdPhysicsController::CreateRigidbody() } -static void DeleteBulletShape(btCollisionShape* shape) +static void DeleteBulletShape(btCollisionShape* shape, bool free) { if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE) { @@ -517,21 +541,13 @@ static void DeleteBulletShape(btCollisionShape* shape) if (meshInterface) delete meshInterface; } - delete shape; + if(free) { + delete shape; + } } -CcdPhysicsController::~CcdPhysicsController() +bool CcdPhysicsController::DeleteControllerShape( ) { - //will be reference counted, due to sharing - if (m_cci.m_physicsEnv) - m_cci.m_physicsEnv->removeCcdPhysicsController(this); - - if (m_MotionState) - delete m_MotionState; - if (m_bulletMotionState) - delete m_bulletMotionState; - delete m_object; - if (m_collisionShape) { // collision shape is always unique to the controller, can delete it here @@ -543,11 +559,64 @@ CcdPhysicsController::~CcdPhysicsController() for (int i=numChild-1 ; i >= 0; i--) { btCollisionShape* childShape = compoundShape->getChildShape(i); - DeleteBulletShape(childShape); + DeleteBulletShape(childShape, true); } } - DeleteBulletShape(m_collisionShape); + DeleteBulletShape(m_collisionShape, true); + + return true; } + + return false; +} + +bool CcdPhysicsController::ReplaceControllerShape(btCollisionShape *newShape) +{ + + /* Note, deleting the previous collision shape must be done alredy */ + /* if (m_collisionShape) DeleteControllerShape(); */ + + m_object->setCollisionShape(newShape); + m_collisionShape= newShape; + m_cci.m_collisionShape= newShape; + + + /* Copied from CcdPhysicsEnvironment::addCcdPhysicsController() */ + + /* without this, an object can rest on the old physics mesh + * and not move to account for the physics mesh, even with 'nosleep' */ + btSoftRigidDynamicsWorld* dw= GetPhysicsEnvironment()->getDynamicsWorld(); + btCollisionObjectArray &obarr= dw->getCollisionObjectArray(); + btCollisionObject *ob; + btBroadphaseProxy* proxy; + + for(int i= 0; i < obarr.size(); i++) { + ob= obarr[i]; + if (ob->getCollisionShape() == newShape); { + proxy = obarr[i]->getBroadphaseHandle(); + + if(proxy) + dw->getPairCache()->cleanProxyFromPairs(proxy,dw->getDispatcher()); + } + } + + return true; +} + +CcdPhysicsController::~CcdPhysicsController() +{ + //will be reference counted, due to sharing + if (m_cci.m_physicsEnv) + m_cci.m_physicsEnv->removeCcdPhysicsController(this); + + if (m_MotionState) + delete m_MotionState; + if (m_bulletMotionState) + delete m_bulletMotionState; + delete m_object; + + DeleteControllerShape(); + if (m_shapeInfo) { m_shapeInfo->Release(); @@ -565,10 +634,22 @@ bool CcdPhysicsController::SynchronizeMotionStates(float time) btSoftBody* sb = GetSoftBody(); if (sb) { - btVector3 aabbMin,aabbMax; - sb->getAabb(aabbMin,aabbMax); - btVector3 worldPos = (aabbMax+aabbMin)*0.5f; - m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]); + if (sb->m_pose.m_bframe) + { + btVector3 worldPos = sb->m_pose.m_com; + btQuaternion worldquat; + btMatrix3x3 trs = sb->m_pose.m_rot*sb->m_pose.m_scl; + trs.getRotation(worldquat); + m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]); + m_MotionState->setWorldOrientation(worldquat[0],worldquat[1],worldquat[2],worldquat[3]); + } + else + { + btVector3 aabbMin,aabbMax; + sb->getAabb(aabbMin,aabbMax); + btVector3 worldPos = (aabbMax+aabbMin)*0.5f; + m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]); + } m_MotionState->calculateWorldTransformations(); return true; } @@ -577,13 +658,26 @@ bool CcdPhysicsController::SynchronizeMotionStates(float time) if (body && !body->isStaticObject()) { - - const btVector3& worldPos = body->getCenterOfMassPosition(); - m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]); - const btQuaternion& worldquat = body->getOrientation(); - m_MotionState->setWorldOrientation(worldquat[0],worldquat[1],worldquat[2],worldquat[3]); - + if ((m_cci.m_clamp_vel_max>0.0) || (m_cci.m_clamp_vel_min>0.0)) + { + const btVector3& linvel = body->getLinearVelocity(); + float len= linvel.length(); + + if((m_cci.m_clamp_vel_max>0.0) && (len > m_cci.m_clamp_vel_max)) + body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_max / len)); + + else if ((m_cci.m_clamp_vel_min>0.0) && btFuzzyZero(len)==0 && (len < m_cci.m_clamp_vel_min)) + body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_min / len)); + } + + const btTransform& xform = body->getCenterOfMassTransform(); + const btMatrix3x3& worldOri = xform.getBasis(); + const btVector3& worldPos = xform.getOrigin(); + float ori[12]; + worldOri.getOpenGLSubMatrix(ori); + m_MotionState->setWorldOrientation(ori); + m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]); m_MotionState->calculateWorldTransformations(); float scale[3]; @@ -620,8 +714,10 @@ bool CcdPhysicsController::SynchronizeMotionStates(float time) void CcdPhysicsController::WriteMotionStateToDynamics(bool nondynaonly) { - + btTransform& xform = CcdPhysicsController::GetTransformFromMotionState(m_MotionState); + SetCenterOfMassTransform(xform); } + void CcdPhysicsController::WriteDynamicsToMotionState() { } @@ -638,12 +734,12 @@ void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionsta if (m_shapeInfo) { m_shapeInfo->AddRef(); - m_collisionShape = m_shapeInfo->CreateBulletShape(); + m_collisionShape = m_shapeInfo->CreateBulletShape(m_cci.m_margin); if (m_collisionShape) { // new shape has no scaling, apply initial scaling - m_collisionShape->setMargin(m_cci.m_margin); + //m_collisionShape->setMargin(m_cci.m_margin); m_collisionShape->setLocalScaling(m_cci.m_scaling); if (m_cci.m_mass) @@ -651,19 +747,29 @@ void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionsta } } + // load some characterists that are not + btRigidBody* oldbody = GetRigidBody(); m_object = 0; CreateRigidbody(); - btRigidBody* body = GetRigidBody(); - if (body) { if (m_cci.m_mass) { body->setMassProps(m_cci.m_mass, m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); } - } - m_cci.m_physicsEnv->addCcdPhysicsController(this); + + if (oldbody) + { + body->setLinearFactor(oldbody->getLinearFactor()); + body->setAngularFactor(oldbody->getAngularFactor()); + if (oldbody->getActivationState() == DISABLE_DEACTIVATION) + body->setActivationState(DISABLE_DEACTIVATION); + } + } + // sensor object are added when needed + if (!m_cci.m_bSensor) + m_cci.m_physicsEnv->addCcdPhysicsController(this); /* SM_Object* dynaparent=0; @@ -740,10 +846,13 @@ void CcdPhysicsController::RelativeTranslate(float dlocX,float dlocY,float dloc m_object->activate(true); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + // kinematic object should not set the transform, it disturbs the velocity interpolation + return; } - btRigidBody* body = GetRigidBody(); + // btRigidBody* body = GetRigidBody(); // not used anymore btVector3 dloc(dlocX,dlocY,dlocZ); btTransform xform = m_object->getWorldTransform(); @@ -766,7 +875,10 @@ void CcdPhysicsController::RelativeRotate(const float rotval[9],bool local) m_object->activate(true); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + // kinematic object should not set the transform, it disturbs the velocity interpolation + return; } btMatrix3x3 drotmat( rotval[0],rotval[4],rotval[8], @@ -789,10 +901,9 @@ void CcdPhysicsController::RelativeRotate(const float rotval[9],bool local) void CcdPhysicsController::GetWorldOrientation(btMatrix3x3& mat) { - float orn[4]; - m_MotionState->getWorldOrientation(orn[0],orn[1],orn[2],orn[3]); - btQuaternion quat(orn[0],orn[1],orn[2],orn[3]); - mat.setRotation(quat); + float ori[12]; + m_MotionState->getWorldOrientation(ori); + mat.setFromOpenGLSubMatrix(ori); } void CcdPhysicsController::getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal) @@ -810,7 +921,10 @@ void CcdPhysicsController::setOrientation(float quatImag0,float quatImag1,float m_object->activate(true); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + // kinematic object should not set the transform, it disturbs the velocity interpolation + return; } // not required //m_MotionState->setWorldOrientation(quatImag0,quatImag1,quatImag2,quatReal); @@ -831,7 +945,7 @@ void CcdPhysicsController::setWorldOrientation(const btMatrix3x3& orn) if (m_object) { m_object->activate(true); - if (m_object->isStaticObject()) + if (m_object->isStaticObject() && !m_cci.m_bSensor) { m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } @@ -862,7 +976,10 @@ void CcdPhysicsController::setPosition(float posX,float posY,float posZ) m_object->activate(true); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + // kinematic object should not set the transform, it disturbs the velocity interpolation + return; } // not required, this function is only used to update the physic controller //m_MotionState->setWorldPosition(posX,posY,posZ); @@ -874,9 +991,19 @@ void CcdPhysicsController::setPosition(float posX,float posY,float posZ) // not required //m_bulletMotionState->setWorldTransform(xform); } +} - +void CcdPhysicsController::forceWorldTransform(const btMatrix3x3& mat, const btVector3& pos) +{ + if (m_object) + { + btTransform& xform = m_object->getWorldTransform(); + xform.setBasis(mat); + xform.setOrigin(pos); + } } + + void CcdPhysicsController::resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) { } @@ -899,6 +1026,7 @@ void CcdPhysicsController::setScaling(float scaleX,float scaleY,float scaleZ) if (m_object && m_object->getCollisionShape()) { + m_object->activate(true); // without this, sleeping objects scale wont be applied in bullet if python changes the scale - Campbell. m_object->getCollisionShape()->setLocalScaling(m_cci.m_scaling); //printf("no inertia recalc for fixed objects with mass=0\n"); @@ -926,14 +1054,31 @@ void CcdPhysicsController::ApplyTorque(float torqueX,float torqueY,float torque m_object->activate(); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + return; } if (local) { torque = xform.getBasis()*torque; } if (body) - body->applyTorque(torque); + { + if (m_cci.m_bRigid) + { + body->applyTorque(torque); + } + else + { + //workaround for incompatibility between 'DYNAMIC' game object, and angular factor + //a DYNAMIC object has some inconsistency: it has no angular effect due to collisions, but still has torque + const btVector3& angFac = body->getAngularFactor(); + btVector3 tmpFac(1,1,1); + body->setAngularFactor(tmpFac); + body->applyTorque(torque); + body->setAngularFactor(angFac); + } + } } } @@ -947,27 +1092,26 @@ void CcdPhysicsController::ApplyForce(float forceX,float forceY,float forceZ,bo m_object->activate(); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + return; } - + btTransform xform = m_object->getWorldTransform(); + + if (local) + { + force = xform.getBasis()*force; + } + btRigidBody* body = GetRigidBody(); + if (body) + body->applyCentralForce(force); + btSoftBody* soft = GetSoftBody(); + if (soft) { - btTransform xform = m_object->getWorldTransform(); - - if (local) - { - force = xform.getBasis()*force; - } - btRigidBody* body = GetRigidBody(); - if (body) - body->applyCentralForce(force); - btSoftBody* soft = GetSoftBody(); - if (soft) - { - // the force is applied on each node, must reduce it in the same extend - if (soft->m_nodes.size() > 0) - force /= soft->m_nodes.size(); - soft->addForce(force); - } + // the force is applied on each node, must reduce it in the same extend + if (soft->m_nodes.size() > 0) + force /= soft->m_nodes.size(); + soft->addForce(force); } } } @@ -979,19 +1123,18 @@ void CcdPhysicsController::SetAngularVelocity(float ang_velX,float ang_velY,flo m_object->activate(true); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); - } else + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + return; + } + btTransform xform = m_object->getWorldTransform(); + if (local) { - btTransform xform = m_object->getWorldTransform(); - if (local) - { - angvel = xform.getBasis()*angvel; - } - btRigidBody* body = GetRigidBody(); - if (body) - body->setAngularVelocity(angvel); - + angvel = xform.getBasis()*angvel; } + btRigidBody* body = GetRigidBody(); + if (body) + body->setAngularVelocity(angvel); } } @@ -1004,7 +1147,8 @@ void CcdPhysicsController::SetLinearVelocity(float lin_velX,float lin_velY,floa m_object->activate(true); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); return; } @@ -1038,7 +1182,9 @@ void CcdPhysicsController::applyImpulse(float attachX,float attachY,float attac m_object->activate(); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + return; } btVector3 pos(attachX,attachY,attachZ); @@ -1165,7 +1311,7 @@ PHY_IPhysicsController* CcdPhysicsController::GetReplica() if (m_shapeInfo) { // This situation does not normally happen - cinfo.m_collisionShape = m_shapeInfo->CreateBulletShape(); + cinfo.m_collisionShape = m_shapeInfo->CreateBulletShape(m_cci.m_margin); } else if (m_collisionShape) { @@ -1232,15 +1378,25 @@ void DefaultMotionState::getWorldScaling(float& scaleX,float& scaleY,float& scal void DefaultMotionState::getWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal) { - quatIma0 = m_worldTransform.getRotation().x(); - quatIma1 = m_worldTransform.getRotation().y(); - quatIma2 = m_worldTransform.getRotation().z(); - quatReal = m_worldTransform.getRotation()[3]; + btQuaternion quat = m_worldTransform.getRotation(); + quatIma0 = quat.x(); + quatIma1 = quat.y(); + quatIma2 = quat.z(); + quatReal = quat[3]; } +void DefaultMotionState::getWorldOrientation(float* ori) +{ + m_worldTransform.getBasis().getOpenGLSubMatrix(ori); +} + +void DefaultMotionState::setWorldOrientation(const float* ori) +{ + m_worldTransform.getBasis().setFromOpenGLSubMatrix(ori); +} void DefaultMotionState::setWorldPosition(float posX,float posY,float posZ) { - btPoint3 pos(posX,posY,posZ); + btVector3 pos(posX,posY,posZ); m_worldTransform.setOrigin( pos ); } @@ -1258,9 +1414,9 @@ void DefaultMotionState::calculateWorldTransformations() // Shape constructor std::map<RAS_MeshObject*, CcdShapeConstructionInfo*> CcdShapeConstructionInfo::m_meshShapeMap; -CcdShapeConstructionInfo* CcdShapeConstructionInfo::FindMesh(RAS_MeshObject* mesh, bool polytope) +CcdShapeConstructionInfo* CcdShapeConstructionInfo::FindMesh(RAS_MeshObject* mesh, struct DerivedMesh* dm, bool polytope, bool gimpact) { - if (polytope) + if (polytope || dm || gimpact) // not yet supported return NULL; @@ -1270,165 +1426,598 @@ CcdShapeConstructionInfo* CcdShapeConstructionInfo::FindMesh(RAS_MeshObject* mes return NULL; } -bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, bool polytope,bool useGimpact) +bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, bool polytope,bool useGimpact) { + int numpolys, numverts; + m_useGimpact = useGimpact; // assume no shape information // no support for dynamic change of shape yet - assert(m_meshObject == NULL); + assert(IsUnused()); m_shapeType = PHY_SHAPE_NONE; - m_vertexArray.clear(); - m_polygonIndexArray.clear(); m_meshObject = NULL; + bool free_dm = false; - if (!meshobj) + // No mesh object or mesh has no polys + if (!meshobj || meshobj->HasColliderPolygon()==false) { + m_vertexArray.clear(); + m_polygonIndexArray.clear(); + m_triFaceArray.clear(); return false; + } - // Mesh has no polygons! - int numpolys = meshobj->NumPolygons(); - if (!numpolys) - { - return false; + if (!dm) { + free_dm = true; + dm = CDDM_from_mesh(meshobj->GetMesh(), NULL); } - // check that we have at least one colliding polygon - int numvalidpolys = 0; + MVert *mvert = dm->getVertArray(dm); + MFace *mface = dm->getFaceArray(dm); + numpolys = dm->getNumFaces(dm); + numverts = dm->getNumVerts(dm); + int* index = (int*)dm->getFaceDataArray(dm, CD_ORIGINDEX); + + m_shapeType = (polytope) ? PHY_SHAPE_POLYTOPE : PHY_SHAPE_MESH; + + /* Convert blender geometry into bullet mesh, need these vars for mapping */ + vector<bool> vert_tag_array(numverts, false); + unsigned int tot_bt_verts= 0; - for (int p=0; p<numpolys; p++) + if (polytope) { - RAS_Polygon* poly = meshobj->GetPolygon(p); + // Tag verts we're using + for (int p2=0; p2<numpolys; p2++) + { + MFace* mf = &mface[p2]; + RAS_Polygon* poly = meshobj->GetPolygon(index[p2]); + + // only add polygons that have the collision flag set + if (poly->IsCollider()) + { + if (vert_tag_array[mf->v1]==false) {vert_tag_array[mf->v1]= true;tot_bt_verts++;} + if (vert_tag_array[mf->v2]==false) {vert_tag_array[mf->v2]= true;tot_bt_verts++;} + if (vert_tag_array[mf->v3]==false) {vert_tag_array[mf->v3]= true;tot_bt_verts++;} + if (mf->v4 && vert_tag_array[mf->v4]==false) {vert_tag_array[mf->v4]= true;tot_bt_verts++;} + } + } + + m_vertexArray.resize(tot_bt_verts*3); + + btScalar *bt= &m_vertexArray[0]; + + for (int p2=0; p2<numpolys; p2++) + { + MFace* mf = &mface[p2]; + RAS_Polygon* poly= meshobj->GetPolygon(index[p2]); + + // only add polygons that have the collisionflag set + if (poly->IsCollider()) + { + if (vert_tag_array[mf->v1]==true) + { + const float* vtx = mvert[mf->v1].co; + vert_tag_array[mf->v1]= false; + *bt++ = vtx[0]; + *bt++ = vtx[1]; + *bt++ = vtx[2]; + } + if (vert_tag_array[mf->v2]==true) + { + const float* vtx = mvert[mf->v2].co; + vert_tag_array[mf->v2]= false; + *bt++ = vtx[0]; + *bt++ = vtx[1]; + *bt++ = vtx[2]; + } + if (vert_tag_array[mf->v3]==true) + { + const float* vtx = mvert[mf->v3].co; + vert_tag_array[mf->v3]= false; + *bt++ = vtx[0]; + *bt++ = vtx[1]; + *bt++ = vtx[2]; + } + if (mf->v4 && vert_tag_array[mf->v4]==true) + { + const float* vtx = mvert[mf->v4].co; + vert_tag_array[mf->v4]= false; + *bt++ = vtx[0]; + *bt++ = vtx[1]; + *bt++ = vtx[2]; + } + } + } + } + else { + unsigned int tot_bt_tris= 0; + vector<int> vert_remap_array(numverts, 0); + + // Tag verts we're using + for (int p2=0; p2<numpolys; p2++) + { + MFace* mf = &mface[p2]; + RAS_Polygon* poly= meshobj->GetPolygon(index[p2]); + + // only add polygons that have the collision flag set + if (poly->IsCollider()) + { + if (vert_tag_array[mf->v1]==false) + {vert_tag_array[mf->v1]= true;vert_remap_array[mf->v1]= tot_bt_verts;tot_bt_verts++;} + if (vert_tag_array[mf->v2]==false) + {vert_tag_array[mf->v2]= true;vert_remap_array[mf->v2]= tot_bt_verts;tot_bt_verts++;} + if (vert_tag_array[mf->v3]==false) + {vert_tag_array[mf->v3]= true;vert_remap_array[mf->v3]= tot_bt_verts;tot_bt_verts++;} + if (mf->v4 && vert_tag_array[mf->v4]==false) + {vert_tag_array[mf->v4]= true;vert_remap_array[mf->v4]= tot_bt_verts;tot_bt_verts++;} + tot_bt_tris += (mf->v4 ? 2:1); /* a quad or a tri */ + } + } - // only add polygons that have the collisionflag set - if (poly->IsCollider()) + m_vertexArray.resize(tot_bt_verts*3); + m_polygonIndexArray.resize(tot_bt_tris); + m_triFaceArray.resize(tot_bt_tris*3); + + btScalar *bt= &m_vertexArray[0]; + int *poly_index_pt= &m_polygonIndexArray[0]; + int *tri_pt= &m_triFaceArray[0]; + + for (int p2=0; p2<numpolys; p2++) { - numvalidpolys++; - break; + MFace* mf = &mface[p2]; + RAS_Polygon* poly= meshobj->GetPolygon(index[p2]); + + // only add polygons that have the collisionflag set + if (poly->IsCollider()) + { + MVert *v1= &mvert[mf->v1]; + MVert *v2= &mvert[mf->v2]; + MVert *v3= &mvert[mf->v3]; + + // the face indicies + tri_pt[0]= vert_remap_array[mf->v1]; + tri_pt[1]= vert_remap_array[mf->v2]; + tri_pt[2]= vert_remap_array[mf->v3]; + tri_pt= tri_pt+3; + + // m_polygonIndexArray + *poly_index_pt= index[p2]; + poly_index_pt++; + + // the vertex location + if (vert_tag_array[mf->v1]==true) { /* *** v1 *** */ + vert_tag_array[mf->v1]= false; + *bt++ = v1->co[0]; + *bt++ = v1->co[1]; + *bt++ = v1->co[2]; + } + if (vert_tag_array[mf->v2]==true) { /* *** v2 *** */ + vert_tag_array[mf->v2]= false; + *bt++ = v2->co[0]; + *bt++ = v2->co[1]; + *bt++ = v2->co[2]; + } + if (vert_tag_array[mf->v3]==true) { /* *** v3 *** */ + vert_tag_array[mf->v3]= false; + *bt++ = v3->co[0]; + *bt++ = v3->co[1]; + *bt++ = v3->co[2]; + } + + if (mf->v4) + { + MVert *v4= &mvert[mf->v4]; + + tri_pt[0]= vert_remap_array[mf->v1]; + tri_pt[1]= vert_remap_array[mf->v3]; + tri_pt[2]= vert_remap_array[mf->v4]; + tri_pt= tri_pt+3; + + // m_polygonIndexArray + *poly_index_pt= index[p2]; + poly_index_pt++; + + // the vertex location + if (vert_tag_array[mf->v4]==true) { /* *** v4 *** */ + vert_tag_array[mf->v4]= false; + *bt++ = v4->co[0]; + *bt++ = v4->co[1]; + *bt++ = v4->co[2]; + } + } + } } + + + /* If this ever gets confusing, print out an OBJ file for debugging */ +#if 0 + printf("# vert count %d\n", m_vertexArray.size()); + for(i=0; i<m_vertexArray.size(); i+=1) { + printf("v %.6f %.6f %.6f\n", m_vertexArray[i].x(), m_vertexArray[i].y(), m_vertexArray[i].z()); + } + + printf("# face count %d\n", m_triFaceArray.size()); + for(i=0; i<m_triFaceArray.size(); i+=3) { + printf("f %d %d %d\n", m_triFaceArray[i]+1, m_triFaceArray[i+1]+1, m_triFaceArray[i+2]+1); + } +#endif + } - // No collision polygons - if (numvalidpolys < 1) +#if 0 + if (validpolys==false) + { + // should not happen + m_shapeType = PHY_SHAPE_NONE; return false; + } +#endif + + m_meshObject = meshobj; + if (free_dm) { + dm->release(dm); + dm = NULL; + } - m_shapeType = (polytope) ? PHY_SHAPE_POLYTOPE : PHY_SHAPE_MESH; + // sharing only on static mesh at present, if you change that, you must also change in FindMesh + if (!polytope && !dm && !useGimpact) + { + // triangle shape can be shared, store the mesh object in the map + m_meshShapeMap.insert(std::pair<RAS_MeshObject*,CcdShapeConstructionInfo*>(meshobj,this)); + } + return true; +} - numvalidpolys = 0; +#include <cstdio> - for (int p2=0; p2<numpolys; p2++) - { - RAS_Polygon* poly = meshobj->GetPolygon(p2); +/* Updates the arrays used by CreateBulletShape(), + * take care that recalcLocalAabb() runs after CreateBulletShape is called. + * */ +bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RAS_MeshObject* meshobj) +{ + int numpolys; + int numverts; + + unsigned int tot_bt_tris= 0; + unsigned int tot_bt_verts= 0; + + int i, j; + int v_orig; + + /* Use for looping over verts in a face as a try or 2 tris */ + const int quad_verts[7]= {0,1,2, 0,2,3, -1}; + const int tri_verts[4]= {0,1,2, -1}; + const int *fv_pt; + + if(gameobj==NULL && meshobj==NULL) + return false; + + if(m_shapeType != PHY_SHAPE_MESH) + return false; + + RAS_Deformer *deformer= gameobj ? gameobj->GetDeformer():NULL; + + /* get the mesh from the object if not defined */ + if(meshobj==NULL) { + + /* modifier mesh */ + if(deformer && deformer->GetFinalMesh()) + meshobj= deformer->GetRasMesh(); + + /* game object first mesh */ + if(meshobj==NULL) { + if(gameobj->GetMeshCount() > 0) { + meshobj= gameobj->GetMesh(0); + } + } + } + + if(deformer && deformer->GetFinalMesh() && deformer->GetRasMesh() == meshobj) + { /* + * Derived Mesh Update + * + * */ + + DerivedMesh* dm= gameobj->GetDeformer()->GetFinalMesh(); + + MVert *mvert = dm->getVertArray(dm); + MFace *mface = dm->getFaceArray(dm); + numpolys = dm->getNumFaces(dm); + numverts = dm->getNumVerts(dm); + int* index = (int*)dm->getFaceDataArray(dm, CD_ORIGINDEX); + + MFace *mf; + MVert *mv; + + int flen; + + if(CustomData_has_layer(&dm->faceData, CD_MTFACE)) + { + MTFace *tface = (MTFace *)dm->getFaceDataArray(dm, CD_MTFACE); + MTFace *tf; + + vector<bool> vert_tag_array(numverts, false); + vector<int> vert_remap_array(numverts, 0); + + for(mf= mface, tf= tface, i=0; i < numpolys; mf++, tf++, i++) { + if(tf->mode & TF_DYNAMIC) + { + if(mf->v4) { + tot_bt_tris+= 2; + flen= 4; + } else { + tot_bt_tris++; + flen= 3; + } + + for(j=0; j<flen; j++) + { + v_orig = (*(&mf->v1 + j)); + + if(vert_tag_array[v_orig]==false) + { + vert_tag_array[v_orig]= true; + vert_remap_array[v_orig]= tot_bt_verts; + tot_bt_verts++; + } + } + } + } + + m_vertexArray.resize(tot_bt_verts*3); + btScalar *bt= &m_vertexArray[0]; + + m_triFaceArray.resize(tot_bt_tris*3); + int *tri_pt= &m_triFaceArray[0]; + + m_polygonIndexArray.resize(tot_bt_tris); + int *poly_index_pt= &m_polygonIndexArray[0]; - // only add polygons that have the collisionflag set - if (poly->IsCollider()) - { - //Bullet can raycast any shape, so - if (polytope) + + for(mf= mface, tf= tface, i=0; i < numpolys; mf++, tf++, i++) { - for (int i=0;i<poly->VertexCount();i++) + if(tf->mode & TF_DYNAMIC) { - const float* vtx = poly->GetVertex(i)->getXYZ(); - btPoint3 point(vtx[0],vtx[1],vtx[2]); - //avoid duplicates (could better directly use vertex offsets, rather than a vertex compare) - bool found = false; - for (int j=0;j<m_vertexArray.size();j++) + if(mf->v4) { + fv_pt= quad_verts; + *poly_index_pt++ = *poly_index_pt++ = index[i]; + flen= 4; + } else { + fv_pt= tri_verts; + *poly_index_pt++ = index[i]; + flen= 3; + } + + for(; *fv_pt > -1; fv_pt++) { - if (m_vertexArray[j]==point) + v_orig = (*(&mf->v1 + (*fv_pt))); + + if(vert_tag_array[v_orig]) { - found = true; - break; + mv= mvert + v_orig; + *bt++ = mv->co[0]; + *bt++ = mv->co[1]; + *bt++ = mv->co[2]; + + vert_tag_array[v_orig]= false; } + *tri_pt++ = vert_remap_array[v_orig]; } - if (!found) - m_vertexArray.push_back(point); + } + } + } + else { + /* no need for a vertex mapping. simple/fast */ + + tot_bt_verts= numverts; + + for(mf= mface, i=0; i < numpolys; mf++, i++) { + tot_bt_tris += (mf->v4 ? 2:1); + } - numvalidpolys++; + m_vertexArray.resize(tot_bt_verts*3); + btScalar *bt= &m_vertexArray[0]; + + m_triFaceArray.resize(tot_bt_tris*3); + int *tri_pt= &m_triFaceArray[0]; + + m_polygonIndexArray.resize(tot_bt_tris); + int *poly_index_pt= &m_polygonIndexArray[0]; + + for(mv= mvert, i=0; i < numverts; mv++, i++) { + *bt++ = mv->co[0]; *bt++ = mv->co[1]; *bt++ = mv->co[2]; + } + + for(mf= mface, i=0; i < numpolys; mf++, i++) { + if(mf->v4) { + fv_pt= quad_verts; + *poly_index_pt++ = *poly_index_pt++ = index[i]; } - } else + else { + fv_pt= tri_verts; + *poly_index_pt++ = index[i]; + } + + for(; *fv_pt > -1; fv_pt++) + *tri_pt++ = (*(&mf->v1 + (*fv_pt))); + } + } + } + else { /* + * RAS Mesh Update + * + * */ + + /* Note!, gameobj can be NULL here */ + + /* transverts are only used for deformed RAS_Meshes, the RAS_TexVert data + * is too hard to get at, see below for details */ + float (*transverts)[3]= NULL; + int transverts_tot= 0; /* with deformed meshes - should always be greater then the max orginal index, or we get crashes */ + + if(deformer) { + /* map locations from the deformed array + * + * Could call deformer->Update(); but rely on redraw updating. + * */ + transverts= deformer->GetTransVerts(&transverts_tot); + } + + // Tag verts we're using + numpolys= meshobj->NumPolygons(); + numverts= meshobj->m_sharedvertex_map.size(); + const float *xyz; + + + vector<bool> vert_tag_array(numverts, false); + vector<int> vert_remap_array(numverts, 0); + + for(int p=0; p<numpolys; p++) + { + RAS_Polygon* poly= meshobj->GetPolygon(p); + if (poly->IsCollider()) { + for(i=0; i < poly->VertexCount(); i++) { - const float* vtx = poly->GetVertex(2)->getXYZ(); - btPoint3 vertex0(vtx[0],vtx[1],vtx[2]); + v_orig= poly->GetVertex(i)->getOrigIndex(); + if(vert_tag_array[v_orig]==false) + { + vert_tag_array[v_orig]= true; + vert_remap_array[v_orig]= tot_bt_verts; + tot_bt_verts++; + } + } + tot_bt_tris += (poly->VertexCount()==4 ? 2:1); + } + } - vtx = poly->GetVertex(1)->getXYZ(); - btPoint3 vertex1(vtx[0],vtx[1],vtx[2]); + m_vertexArray.resize(tot_bt_verts*3); + btScalar *bt= &m_vertexArray[0]; - vtx = poly->GetVertex(0)->getXYZ(); - btPoint3 vertex2(vtx[0],vtx[1],vtx[2]); + m_triFaceArray.resize(tot_bt_tris*3); + int *tri_pt= &m_triFaceArray[0]; - m_vertexArray.push_back(vertex0); - m_vertexArray.push_back(vertex1); - m_vertexArray.push_back(vertex2); - m_polygonIndexArray.push_back(p2); - numvalidpolys++; - } - if (poly->VertexCount() == 4) + /* cant be used for anything useful in this case, since we dont rely on the original mesh + * will just be an array like pythons range(tot_bt_tris) */ + m_polygonIndexArray.resize(tot_bt_tris); + + + for(int p=0; p<numpolys; p++) + { + RAS_Polygon* poly= meshobj->GetPolygon(p); + + if (poly->IsCollider()) + { + /* quad or tri loop */ + fv_pt= (poly->VertexCount()==3 ? tri_verts:quad_verts); + + for(; *fv_pt > -1; fv_pt++) { - const float* vtx = poly->GetVertex(3)->getXYZ(); - btPoint3 vertex0(vtx[0],vtx[1],vtx[2]); + v_orig= poly->GetVertex(*fv_pt)->getOrigIndex(); - vtx = poly->GetVertex(2)->getXYZ(); - btPoint3 vertex1(vtx[0],vtx[1],vtx[2]); + if(vert_tag_array[v_orig]) + { + if(transverts) { + /* deformed mesh, using RAS_TexVert locations would be too troublesome + * because they are use the gameob as a hash in the material slot */ + *bt++ = transverts[v_orig][0]; + *bt++ = transverts[v_orig][1]; + *bt++ = transverts[v_orig][2]; + } + else { + /* static mesh python may have modified */ + xyz= meshobj->GetVertexLocation( v_orig ); + *bt++ = xyz[0]; + *bt++ = xyz[1]; + *bt++ = xyz[2]; + } - vtx = poly->GetVertex(0)->getXYZ(); - btPoint3 vertex2(vtx[0],vtx[1],vtx[2]); + vert_tag_array[v_orig]= false; + } - m_vertexArray.push_back(vertex0); - m_vertexArray.push_back(vertex1); - m_vertexArray.push_back(vertex2); - m_polygonIndexArray.push_back(p2); - numvalidpolys++; + *tri_pt++ = vert_remap_array[v_orig]; } - } + } + + m_polygonIndexArray[p]= p; /* dumb counting */ } } + +#if 0 + /* needs #include <cstdio> */ + printf("# vert count %d\n", m_vertexArray.size()); + for(int i=0; i<m_vertexArray.size(); i+=3) { + printf("v %.6f %.6f %.6f\n", m_vertexArray[i], m_vertexArray[i+1], m_vertexArray[i+2]); + } - if (!numvalidpolys) - { - // should not happen - m_shapeType = PHY_SHAPE_NONE; - return false; + printf("# face count %d\n", m_triFaceArray.size()); + for(int i=0; i<m_triFaceArray.size(); i+=3) { + printf("f %d %d %d\n", m_triFaceArray[i]+1, m_triFaceArray[i+1]+1, m_triFaceArray[i+2]+1); } - m_meshObject = meshobj; - if (!polytope) - { - // triangle shape can be shared, store the mesh object in the map - m_meshShapeMap.insert(std::pair<RAS_MeshObject*,CcdShapeConstructionInfo*>(meshobj,this)); +#endif + + /* force recreation of the m_unscaledShape. + * If this has multiple users we cant delete */ + if(m_unscaledShape) { + // dont free now so it can re-allocate under the same location and not break pointers. + // DeleteBulletShape(m_unscaledShape); + m_forceReInstance= true; } + + m_meshObject= meshobj; + + return true; +} + + + +bool CcdShapeConstructionInfo::SetProxy(CcdShapeConstructionInfo* shapeInfo) +{ + if (shapeInfo == NULL) + return false; + // no support for dynamic change + assert(IsUnused()); + m_shapeType = PHY_SHAPE_PROXY; + m_shapeProxy = shapeInfo; return true; } -btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() +btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape(btScalar margin) { btCollisionShape* collisionShape = 0; - btTriangleMeshShape* concaveShape = 0; - btTriangleMesh* collisionMeshData = 0; - btCompoundShape* compoundShape = 0; - CcdShapeConstructionInfo* nextShapeInfo; + btCompoundShape* compoundShape = 0; + + if (m_shapeType == PHY_SHAPE_PROXY && m_shapeProxy != NULL) + return m_shapeProxy->CreateBulletShape(margin); switch (m_shapeType) { - case PHY_SHAPE_NONE: + default: break; case PHY_SHAPE_BOX: collisionShape = new btBoxShape(m_halfExtend); + collisionShape->setMargin(margin); break; case PHY_SHAPE_SPHERE: collisionShape = new btSphereShape(m_radius); + collisionShape->setMargin(margin); break; case PHY_SHAPE_CYLINDER: collisionShape = new btCylinderShapeZ(m_halfExtend); + collisionShape->setMargin(margin); break; case PHY_SHAPE_CONE: collisionShape = new btConeShapeZ(m_radius, m_height); + collisionShape->setMargin(margin); break; case PHY_SHAPE_POLYTOPE: - collisionShape = new btConvexHullShape(&m_vertexArray.begin()->getX(), m_vertexArray.size()); + collisionShape = new btConvexHullShape(&m_vertexArray[0], m_vertexArray.size()/3, 3*sizeof(btScalar)); + collisionShape->setMargin(margin); break; case PHY_SHAPE_MESH: @@ -1440,37 +2029,74 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() // One possible optimization is to use directly the btBvhTriangleMeshShape when the scale is 1,1,1 // and btScaledBvhTriangleMeshShape otherwise. if (m_useGimpact) - { - collisionMeshData = new btTriangleMesh(); + { + btTriangleIndexVertexArray* indexVertexArrays = new btTriangleIndexVertexArray( + m_polygonIndexArray.size(), + &m_triFaceArray[0], + 3*sizeof(int), + m_vertexArray.size()/3, + &m_vertexArray[0], + 3*sizeof(btScalar) + ); - - // m_vertexArray is necessarily a multiple of 3 - for (std::vector<btPoint3>::iterator it=m_vertexArray.begin(); it != m_vertexArray.end(); ) - { - collisionMeshData->addTriangle(*it++,*it++,*it++); - } - btGImpactMeshShape* gimpactShape = new btGImpactMeshShape(collisionMeshData); - + btGImpactMeshShape* gimpactShape = new btGImpactMeshShape(indexVertexArrays); + gimpactShape->setMargin(margin); collisionShape = gimpactShape; gimpactShape->updateBound(); } else { - if (!m_unscaledShape) + if (!m_unscaledShape || m_forceReInstance) { - collisionMeshData = new btTriangleMesh(true,false); - collisionMeshData->m_weldingThreshold = m_weldingThreshold; + + btTriangleIndexVertexArray* indexVertexArrays = 0; - // m_vertexArray is necessarily a multiple of 3 - for (std::vector<btPoint3>::iterator it=m_vertexArray.begin(); it != m_vertexArray.end(); ) + ///enable welding, only for the objects that need it (such as soft bodies) + if (0.f != m_weldingThreshold1) { - collisionMeshData->addTriangle(*it++,*it++,*it++); + btTriangleMesh* collisionMeshData = new btTriangleMesh(true,false); + collisionMeshData->m_weldingThreshold = m_weldingThreshold1; + bool removeDuplicateVertices=true; + // m_vertexArray not in multiple of 3 anymore, use m_triFaceArray + for(unsigned int i=0; i<m_triFaceArray.size(); i+=3) { + btScalar *bt = &m_vertexArray[3*m_triFaceArray[i]]; + btVector3 v1(bt[0], bt[1], bt[2]); + bt = &m_vertexArray[3*m_triFaceArray[i+1]]; + btVector3 v2(bt[0], bt[1], bt[2]); + bt = &m_vertexArray[3*m_triFaceArray[i+2]]; + btVector3 v3(bt[0], bt[1], bt[2]); + collisionMeshData->addTriangle(v1, v2, v3, removeDuplicateVertices); + } + indexVertexArrays = collisionMeshData; + + } else + { + indexVertexArrays = new btTriangleIndexVertexArray( + m_polygonIndexArray.size(), + &m_triFaceArray[0], + 3*sizeof(int), + m_vertexArray.size()/3, + &m_vertexArray[0], + 3*sizeof(btScalar)); } + // this shape will be shared and not deleted until shapeInfo is deleted - m_unscaledShape = new btBvhTriangleMeshShape( collisionMeshData, true ); + + // for UpdateMesh, reuse the last memory location so instancing wont crash. + if(m_unscaledShape) { + DeleteBulletShape(m_unscaledShape, false); + m_unscaledShape->~btBvhTriangleMeshShape(); + + m_unscaledShape = new(m_unscaledShape) btBvhTriangleMeshShape( indexVertexArrays, true ); + } else { + m_unscaledShape = new btBvhTriangleMeshShape( indexVertexArrays, true ); + } + + m_forceReInstance= false; m_unscaledShape->recalcLocalAabb(); } collisionShape = new btScaledBvhTriangleMeshShape(m_unscaledShape, btVector3(1.0f,1.0f,1.0f)); + collisionShape->setMargin(margin); } break; @@ -1482,7 +2108,7 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() sit != m_shapeArray.end(); sit++) { - collisionShape = (*sit)->CreateBulletShape(); + collisionShape = (*sit)->CreateBulletShape(margin); if (collisionShape) { collisionShape->setLocalScaling((*sit)->m_childScale); @@ -1511,7 +2137,7 @@ CcdShapeConstructionInfo::~CcdShapeConstructionInfo() m_shapeArray.clear(); if (m_unscaledShape) { - DeleteBulletShape(m_unscaledShape); + DeleteBulletShape(m_unscaledShape, true); } m_vertexArray.clear(); if (m_shapeType == PHY_SHAPE_MESH && m_meshObject != NULL) @@ -1522,6 +2148,10 @@ CcdShapeConstructionInfo::~CcdShapeConstructionInfo() m_meshShapeMap.erase(mit); } } + if (m_shapeType == PHY_SHAPE_PROXY && m_shapeProxy != NULL) + { + m_shapeProxy->Release(); + } } diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 054ec91122a..69b16ca35bd 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -36,6 +36,7 @@ extern bool gDisableDeactivation; class CcdPhysicsEnvironment; class btMotionState; class RAS_MeshObject; +struct DerivedMesh; class btCollisionShape; @@ -57,9 +58,7 @@ class btCollisionShape; class CcdShapeConstructionInfo { public: - - - static CcdShapeConstructionInfo* FindMesh(RAS_MeshObject* mesh, bool polytope); + static CcdShapeConstructionInfo* FindMesh(class RAS_MeshObject* mesh, struct DerivedMesh* dm, bool polytope, bool gimpact); CcdShapeConstructionInfo() : m_shapeType(PHY_SHAPE_NONE), @@ -67,11 +66,13 @@ public: m_height(1.0), m_halfExtend(0.f,0.f,0.f), m_childScale(1.0f,1.0f,1.0f), + m_userData(NULL), m_refCount(1), m_meshObject(NULL), m_unscaledShape(NULL), m_useGimpact(false), - m_weldingThreshold(0.f) + m_weldingThreshold1(0.f), + m_shapeProxy(NULL) { m_childTrans.setIdentity(); } @@ -92,6 +93,11 @@ public: return 0; } + bool IsUnused(void) + { + return (m_meshObject==NULL && m_shapeArray.size() == 0 && m_shapeProxy == NULL); + } + void AddShape(CcdShapeConstructionInfo* shapeInfo); btTriangleMeshShape* GetMeshShape(void) @@ -100,19 +106,54 @@ public: } CcdShapeConstructionInfo* GetChildShape(int i) { - if (i < 0 || i >= m_shapeArray.size()) + if (i < 0 || i >= (int)m_shapeArray.size()) return NULL; return m_shapeArray.at(i); } + int FindChildShape(CcdShapeConstructionInfo* shapeInfo, void* userData) + { + if (shapeInfo == NULL) + return -1; + for (int i=0; i<(int)m_shapeArray.size(); i++) + { + CcdShapeConstructionInfo* childInfo = m_shapeArray.at(i); + if ((userData == NULL || userData == childInfo->m_userData) && + (childInfo == shapeInfo || + (childInfo->m_shapeType == PHY_SHAPE_PROXY && + childInfo->m_shapeProxy == shapeInfo))) + return i; + } + return -1; + } + + bool RemoveChildShape(int i) + { + if (i < 0 || i >= (int)m_shapeArray.size()) + return false; + m_shapeArray.at(i)->Release(); + if (i < (int)m_shapeArray.size()-1) + m_shapeArray[i] = m_shapeArray.back(); + m_shapeArray.pop_back(); + return true; + } - bool SetMesh(RAS_MeshObject* mesh, bool polytope,bool useGimpact); + bool SetMesh(class RAS_MeshObject* mesh, struct DerivedMesh* dm, bool polytope,bool useGimpact); RAS_MeshObject* GetMesh(void) { return m_meshObject; } - btCollisionShape* CreateBulletShape(); + bool UpdateMesh(class KX_GameObject* gameobj, class RAS_MeshObject* mesh); + + + bool SetProxy(CcdShapeConstructionInfo* shapeInfo); + CcdShapeConstructionInfo* GetProxy(void) + { + return m_shapeProxy; + } + + btCollisionShape* CreateBulletShape(btScalar margin); // member variables PHY_ShapeType m_shapeType; @@ -121,20 +162,20 @@ public: btVector3 m_halfExtend; btTransform m_childTrans; btVector3 m_childScale; - std::vector<btPoint3> m_vertexArray; // Contains both vertex array for polytope shape and - // triangle array for concave mesh shape. + void* m_userData; + btAlignedObjectArray<btScalar> m_vertexArray; // Contains both vertex array for polytope shape and + // triangle array for concave mesh shape. Each vertex is 3 consecutive values // In this case a triangle is made of 3 consecutive points std::vector<int> m_polygonIndexArray; // Contains the array of polygon index in the // original mesh that correspond to shape triangles. // only set for concave mesh shape. + + std::vector<int> m_triFaceArray; // Contains an array of triplets of face indicies + // quads turn into 2 tris - void setVertexWeldingThreshold(float threshold) - { - m_weldingThreshold = threshold; - } - float getVertexWeldingThreshold() const + void setVertexWeldingThreshold1(float threshold) { - return m_weldingThreshold; + m_weldingThreshold1 = threshold*threshold; } protected: static std::map<RAS_MeshObject*, CcdShapeConstructionInfo*> m_meshShapeMap; @@ -145,8 +186,16 @@ protected: // the actual shape is of type btScaledBvhTriangleMeshShape std::vector<CcdShapeConstructionInfo*> m_shapeArray; // for compound shapes bool m_useGimpact; //use gimpact for concave dynamic/moving collision detection - float m_weldingThreshold; //welding closeby vertices together can improve softbody stability etc. + bool m_forceReInstance; //use gimpact for concave dynamic/moving collision detection + float m_weldingThreshold1; //welding closeby vertices together can improve softbody stability etc. + CcdShapeConstructionInfo* m_shapeProxy; // only used for PHY_SHAPE_PROXY, pointer to actual shape info + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CcdShapeConstructionInfo"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; struct CcdConstructionInfo @@ -171,6 +220,8 @@ struct CcdConstructionInfo m_gravity(0,0,0), m_scaling(1.f,1.f,1.f), m_mass(0.f), + m_clamp_vel_min(-1.f), + m_clamp_vel_max(-1.f), m_restitution(0.1f), m_friction(0.5f), m_linearDamping(0.1f), @@ -180,6 +231,7 @@ struct CcdConstructionInfo m_collisionFlags(0), m_bRigid(false), m_bSoft(false), + m_bSensor(false), m_collisionFilterGroup(DefaultFilter), m_collisionFilterMask(AllFilter), m_collisionShape(0), @@ -188,7 +240,8 @@ struct CcdConstructionInfo m_physicsEnv(0), m_inertiaFactor(1.f), m_do_anisotropic(false), - m_anisotropicFriction(1.f,1.f,1.f) + m_anisotropicFriction(1.f,1.f,1.f), + m_contactProcessingThreshold(1e10) { } @@ -196,6 +249,8 @@ struct CcdConstructionInfo btVector3 m_gravity; btVector3 m_scaling; btScalar m_mass; + btScalar m_clamp_vel_min; + btScalar m_clamp_vel_max; btScalar m_restitution; btScalar m_friction; btScalar m_linearDamping; @@ -244,6 +299,7 @@ struct CcdConstructionInfo int m_collisionFlags; bool m_bRigid; bool m_bSoft; + bool m_bSensor; ///optional use of collision group/mask: ///only collision with object goups that match the collision mask. @@ -271,6 +327,13 @@ struct CcdConstructionInfo btScalar m_fh_distance; ///< The range above the surface where Fh is active. bool m_fh_normal; ///< Should the object slide off slopes? float m_radius;//for fh backwards compatibility + + ///m_contactProcessingThreshold allows to process contact points with positive distance + ///normally only contacts with negative distance (penetration) are solved + ///however, rigid body stacking is more stable when positive contacts are still passed into the constraint solver + ///this might sometimes lead to collisions with 'internal edges' such as a sliding character controller + ///so disable/set m_contactProcessingThreshold to zero for sliding characters etc. + float m_contactProcessingThreshold;///< Process contacts with positive distance in range [0..INF] }; @@ -282,7 +345,7 @@ class btSoftBody; ///CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution. class CcdPhysicsController : public PHY_IPhysicsController { - +protected: btCollisionObject* m_object; @@ -317,8 +380,8 @@ class CcdPhysicsController : public PHY_IPhysicsController return (--m_registerCount == 0) ? true : false; } - protected: - void setWorldOrientation(const btMatrix3x3& mat); + void setWorldOrientation(const btMatrix3x3& mat); + void forceWorldTransform(const btMatrix3x3& mat, const btVector3& pos); public: @@ -327,6 +390,9 @@ class CcdPhysicsController : public PHY_IPhysicsController CcdPhysicsController (const CcdConstructionInfo& ci); + bool DeleteControllerShape(); + bool ReplaceControllerShape(btCollisionShape *newShape); + virtual ~CcdPhysicsController(); CcdConstructionInfo& getConstructionInfo() @@ -363,6 +429,7 @@ class CcdPhysicsController : public PHY_IPhysicsController virtual void WriteMotionStateToDynamics(bool nondynaonly); virtual void WriteDynamicsToMotionState(); + // controller replication virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl); @@ -436,7 +503,24 @@ class CcdPhysicsController : public PHY_IPhysicsController } m_cci.m_radius = margin; } - + + // velocity clamping + virtual void SetLinVelocityMin(float val) + { + m_cci.m_clamp_vel_min= val; + } + virtual float GetLinVelocityMin() const + { + return m_cci.m_clamp_vel_min; + } + virtual void SetLinVelocityMax(float val) + { + m_cci.m_clamp_vel_max= val; + } + virtual float GetLinVelocityMax() const + { + return m_cci.m_clamp_vel_max; + } bool wantsSleeping(); @@ -444,7 +528,7 @@ class CcdPhysicsController : public PHY_IPhysicsController void SetCenterOfMassTransform(btTransform& xform); - static btTransform GetTransformFromMotionState(PHY_IMotionState* motionState); + static btTransform& GetTransformFromMotionState(PHY_IMotionState* motionState); void setAabb(const btVector3& aabbMin,const btVector3& aabbMax); @@ -480,7 +564,11 @@ class CcdPhysicsController : public PHY_IPhysicsController } - +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CcdPhysicsController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; @@ -501,12 +589,20 @@ class DefaultMotionState : public PHY_IMotionState virtual void setWorldPosition(float posX,float posY,float posZ); virtual void setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal); + virtual void getWorldOrientation(float* ori); + virtual void setWorldOrientation(const float* ori); virtual void calculateWorldTransformations(); btTransform m_worldTransform; btVector3 m_localScaling; - + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:DefaultMotionState"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index 4fe35630784..bf28802870a 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -18,6 +18,7 @@ subject to the following restrictions: #include "CcdPhysicsEnvironment.h" #include "CcdPhysicsController.h" +#include "CcdGraphicController.h" #include <algorithm> #include "btBulletDynamicsCommon.h" @@ -32,6 +33,10 @@ subject to the following restrictions: #include "PHY_IMotionState.h" +#include "KX_GameObject.h" +#include "RAS_MeshObject.h" +#include "RAS_Polygon.h" +#include "RAS_TexVert.h" #define CCD_CONSTRAINT_DISABLE_LINKED_COLLISION 0x80 @@ -46,7 +51,9 @@ btRaycastVehicle::btVehicleTuning gTuning; #endif //NEW_BULLET_VEHICLE_SUPPORT #include "LinearMath/btAabbUtil2.h" - +#include "MT_Matrix4x4.h" +#include "MT_Vector3.h" +#include "GL/glew.h" #ifdef WIN32 void DrawRasterizerLine(const float* from,const float* to,int color); @@ -316,8 +323,9 @@ static void DrawAabb(btIDebugDraw* debugDrawer,const btVector3& from,const btVec -CcdPhysicsEnvironment::CcdPhysicsEnvironment(btDispatcher* dispatcher,btOverlappingPairCache* pairCache) -:m_scalingPropagated(false), +CcdPhysicsEnvironment::CcdPhysicsEnvironment(bool useDbvtCulling,btDispatcher* dispatcher,btOverlappingPairCache* pairCache) +:m_cullingCache(NULL), +m_cullingTree(NULL), m_numIterations(10), m_numTimeSubSteps(1), m_ccdMode(0), @@ -326,8 +334,9 @@ m_profileTimings(0), m_enableSatCollisionDetection(false), m_solver(NULL), m_ownPairCache(NULL), +m_filterCallback(NULL), m_ownDispatcher(NULL), -m_filterCallback(NULL) +m_scalingPropagated(false) { for (int i=0;i<PHY_NUM_RESPONSE;i++) @@ -337,6 +346,7 @@ m_filterCallback(NULL) // m_collisionConfiguration = new btDefaultCollisionConfiguration(); m_collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration(); + //m_collisionConfiguration->setConvexConvexMultipointIterations(); if (!dispatcher) { @@ -349,6 +359,11 @@ m_filterCallback(NULL) //m_broadphase = new btAxisSweep3(btVector3(-1000,-1000,-1000),btVector3(1000,1000,1000)); //m_broadphase = new btSimpleBroadphase(); m_broadphase = new btDbvtBroadphase(); + // avoid any collision in the culling tree + if (useDbvtCulling) { + m_cullingCache = new btNullPairCache(); + m_cullingTree = new btDbvtBroadphase(m_cullingCache); + } m_filterCallback = new CcdOverlapFilterCallBack(this); m_broadphase->getOverlappingPairCache()->setOverlapFilterCallback(m_filterCallback); @@ -356,12 +371,13 @@ m_filterCallback(NULL) setSolverType(1);//issues with quickstep and memory allocations // m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,m_broadphase,m_solver,m_collisionConfiguration); m_dynamicsWorld = new btSoftRigidDynamicsWorld(dispatcher,m_broadphase,m_solver,m_collisionConfiguration); + //m_dynamicsWorld->getSolverInfo().m_linearSlop = 0.01f; + //m_dynamicsWorld->getSolverInfo().m_solverMode= SOLVER_USE_WARMSTARTING + SOLVER_USE_2_FRICTION_DIRECTIONS + SOLVER_RANDMIZE_ORDER + SOLVER_USE_FRICTION_WARMSTARTING; m_debugDrawer = 0; m_gravity = btVector3(0.f,-10.f,0.f); m_dynamicsWorld->setGravity(m_gravity); - } void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl) @@ -399,61 +415,7 @@ void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl) obj->setActivationState(ISLAND_SLEEPING); } - - //CollisionObject(body,ctrl->GetCollisionFilterGroup(),ctrl->GetCollisionFilterMask()); - assert(obj->getBroadphaseHandle()); - - btBroadphaseInterface* scene = getBroadphase(); - - - btCollisionShape* shapeinterface = ctrl->GetCollisionShape(); - - assert(shapeinterface); - - const btTransform& t = ctrl->GetCollisionObject()->getWorldTransform(); - - - btPoint3 minAabb,maxAabb; - - shapeinterface->getAabb(t,minAabb,maxAabb); - - float timeStep = 0.02f; - - - //extent it with the motion - - if (body) - { - btVector3 linMotion = body->getLinearVelocity()*timeStep; - - float maxAabbx = maxAabb.getX(); - float maxAabby = maxAabb.getY(); - float maxAabbz = maxAabb.getZ(); - float minAabbx = minAabb.getX(); - float minAabby = minAabb.getY(); - float minAabbz = minAabb.getZ(); - - if (linMotion.x() > 0.f) - maxAabbx += linMotion.x(); - else - minAabbx += linMotion.x(); - if (linMotion.y() > 0.f) - maxAabby += linMotion.y(); - else - minAabby += linMotion.y(); - if (linMotion.z() > 0.f) - maxAabbz += linMotion.z(); - else - minAabbz += linMotion.z(); - - - minAabb = btVector3(minAabbx,minAabby,minAabbz); - maxAabb = btVector3(maxAabbx,maxAabby,maxAabbz); - } - - - } @@ -464,6 +426,13 @@ void CcdPhysicsEnvironment::removeCcdPhysicsController(CcdPhysicsController* ctr btRigidBody* body = ctrl->GetRigidBody(); if (body) { + for (int i=body->getNumConstraintRefs()-1;i>=0;i--) + { + btTypedConstraint* con = body->getConstraintRef(i); + m_dynamicsWorld->removeConstraint(con); + body->removeConstraintRef(con); + //delete con; //might be kept by python KX_ConstraintWrapper + } m_dynamicsWorld->removeRigidBody(ctrl->GetRigidBody()); } else { @@ -517,6 +486,12 @@ void CcdPhysicsEnvironment::enableCcdPhysicsController(CcdPhysicsController* ctr { btCollisionObject* obj = ctrl->GetCollisionObject(); obj->setUserPointer(ctrl); + // update the position of the object from the user + if (ctrl->GetMotionState()) + { + btTransform xform = CcdPhysicsController::GetTransformFromMotionState(ctrl->GetMotionState()); + ctrl->SetCenterOfMassTransform(xform); + } m_dynamicsWorld->addCollisionObject(obj, ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask()); } @@ -536,20 +511,72 @@ void CcdPhysicsEnvironment::disableCcdPhysicsController(CcdPhysicsController* ct { } else { - m_dynamicsWorld->removeCollisionObject(body); + m_dynamicsWorld->removeCollisionObject(ctrl->GetCollisionObject()); } } } } +void CcdPhysicsEnvironment::refreshCcdPhysicsController(CcdPhysicsController* ctrl) +{ + btCollisionObject* obj = ctrl->GetCollisionObject(); + if (obj) + { + btBroadphaseProxy* proxy = obj->getBroadphaseHandle(); + if (proxy) + { + m_dynamicsWorld->getPairCache()->cleanProxyFromPairs(proxy,m_dynamicsWorld->getDispatcher()); + } + } +} + +void CcdPhysicsEnvironment::addCcdGraphicController(CcdGraphicController* ctrl) +{ + if (m_cullingTree && !ctrl->getBroadphaseHandle()) + { + btVector3 minAabb; + btVector3 maxAabb; + ctrl->getAabb(minAabb, maxAabb); + + ctrl->setBroadphaseHandle(m_cullingTree->createProxy( + minAabb, + maxAabb, + INVALID_SHAPE_PROXYTYPE, // this parameter is not used + ctrl, + 0, // this object does not collision with anything + 0, + NULL, // dispatcher => this parameter is not used + 0)); + + assert(ctrl->getBroadphaseHandle()); + } +} + +void CcdPhysicsEnvironment::removeCcdGraphicController(CcdGraphicController* ctrl) +{ + if (m_cullingTree) + { + btBroadphaseProxy* bp = ctrl->getBroadphaseHandle(); + if (bp) + { + m_cullingTree->destroyProxy(bp,NULL); + ctrl->setBroadphaseHandle(0); + } + } +} void CcdPhysicsEnvironment::beginFrame() { } +void CcdPhysicsEnvironment::debugDrawWorld() +{ + if (m_dynamicsWorld->getDebugDrawer() && m_dynamicsWorld->getDebugDrawer()->getDebugMode() >0) + m_dynamicsWorld->debugDrawWorld(); +} -bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep) +bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep,float interval) { std::set<CcdPhysicsController*>::iterator it; int i; @@ -559,24 +586,19 @@ bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep) (*it)->SynchronizeMotionStates(timeStep); } - processFhSprings(curTime,timeStep); - float subStep = timeStep / float(m_numTimeSubSteps); - for (i=0;i<m_numTimeSubSteps;i++) - { -// m_dynamicsWorld->stepSimulation(subStep,20,1./240.);//perform always a full simulation step - m_dynamicsWorld->stepSimulation(subStep,0);//perform always a full simulation step - } + i = m_dynamicsWorld->stepSimulation(interval,25,subStep);//perform always a full simulation step + processFhSprings(curTime,i*subStep); for (it=m_controllers.begin(); it!=m_controllers.end(); it++) { (*it)->SynchronizeMotionStates(timeStep); } - for (it=m_controllers.begin(); it!=m_controllers.end(); it++) - { - (*it)->SynchronizeMotionStates(timeStep); - } + //for (it=m_controllers.begin(); it!=m_controllers.end(); it++) + //{ + // (*it)->SynchronizeMotionStates(timeStep); + //} for (i=0;i<m_wrapperVehicles.size();i++) { @@ -584,9 +606,6 @@ bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep) veh->SyncWheels(); } - if (m_dynamicsWorld->getDebugDrawer() && m_dynamicsWorld->getDebugDrawer()->getDebugMode() >0) - m_dynamicsWorld->debugDrawWorld(); - CallbackTriggers(); @@ -601,9 +620,10 @@ class ClosestRayResultCallbackNotMe : public btCollisionWorld::ClosestRayResultC public: ClosestRayResultCallbackNotMe(const btVector3& rayFromWorld,const btVector3& rayToWorld,btCollisionObject* owner,btCollisionObject* parent) :btCollisionWorld::ClosestRayResultCallback(rayFromWorld,rayToWorld), - m_owner(owner) + m_owner(owner), + m_parent(parent) { - + } virtual bool needsCollision(btBroadphaseProxy* proxy0) const @@ -620,9 +640,11 @@ public: }; -void CcdPhysicsEnvironment::processFhSprings(double curTime,float timeStep) +void CcdPhysicsEnvironment::processFhSprings(double curTime,float interval) { std::set<CcdPhysicsController*>::iterator it; + // dynamic of Fh spring is based on a timestep of 1/60 + int numIter = (int)(interval*60.0001f); for (it=m_controllers.begin(); it!=m_controllers.end(); it++) { @@ -634,8 +656,6 @@ void CcdPhysicsEnvironment::processFhSprings(double curTime,float timeStep) //printf("has Fh or RotFh\n"); //re-implement SM_FhObject.cpp using btCollisionWorld::rayTest and info from ctrl->getConstructionInfo() //send a ray from {0.0, 0.0, 0.0} towards {0.0, 0.0, -10.0}, in local coordinates - - CcdPhysicsController* parentCtrl = ctrl->getParentCtrl(); btRigidBody* parentBody = parentCtrl?parentCtrl->GetRigidBody() : 0; btRigidBody* cl_object = parentBody ? parentBody : body; @@ -651,7 +671,7 @@ void CcdPhysicsEnvironment::processFhSprings(double curTime,float timeStep) //btVector3 rayToWorld = rayFromWorld + body->getCenterOfMassTransform().getBasis() * rayDirLocal; //ray always points down the z axis in world space... btVector3 rayToWorld = rayFromWorld + rayDirLocal; - + ClosestRayResultCallbackNotMe resultCallback(rayFromWorld,rayToWorld,body,parentBody); m_dynamicsWorld->rayTest(rayFromWorld,rayToWorld,resultCallback); @@ -682,82 +702,78 @@ void CcdPhysicsEnvironment::processFhSprings(double curTime,float timeStep) btVector3 normal = resultCallback.m_hitNormalWorld; normal.normalize(); - - if (ctrl->getConstructionInfo().m_do_fh) + for (int i=0; i<numIter; i++) { - btVector3 lspot = cl_object->getCenterOfMassPosition() - + rayDirLocal * resultCallback.m_closestHitFraction; + if (ctrl->getConstructionInfo().m_do_fh) + { + btVector3 lspot = cl_object->getCenterOfMassPosition() + + rayDirLocal * resultCallback.m_closestHitFraction; + + + lspot -= hit_object->getCenterOfMassPosition(); + btVector3 rel_vel = cl_object->getLinearVelocity() - hit_object->getVelocityInLocalPoint(lspot); + btScalar rel_vel_ray = ray_dir.dot(rel_vel); + btScalar spring_extent = 1.0 - distance / hitObjShapeProps.m_fh_distance; + + btScalar i_spring = spring_extent * hitObjShapeProps.m_fh_spring; + btScalar i_damp = rel_vel_ray * hitObjShapeProps.m_fh_damping; + cl_object->setLinearVelocity(cl_object->getLinearVelocity() + (-(i_spring + i_damp) * ray_dir)); + if (hitObjShapeProps.m_fh_normal) + { + cl_object->setLinearVelocity(cl_object->getLinearVelocity()+(i_spring + i_damp) *(normal - normal.dot(ray_dir) * ray_dir)); + } + + btVector3 lateral = rel_vel - rel_vel_ray * ray_dir; + + + if (ctrl->getConstructionInfo().m_do_anisotropic) { + //Bullet basis contains no scaling/shear etc. + const btMatrix3x3& lcs = cl_object->getCenterOfMassTransform().getBasis(); + btVector3 loc_lateral = lateral * lcs; + const btVector3& friction_scaling = cl_object->getAnisotropicFriction(); + loc_lateral *= friction_scaling; + lateral = lcs * loc_lateral; + } - lspot -= hit_object->getCenterOfMassPosition(); - btVector3 rel_vel = cl_object->getLinearVelocity() - hit_object->getVelocityInLocalPoint(lspot); - btScalar rel_vel_ray = ray_dir.dot(rel_vel); - btScalar spring_extent = 1.0 - distance / hitObjShapeProps.m_fh_distance; - - btScalar i_spring = spring_extent * hitObjShapeProps.m_fh_spring; - btScalar i_damp = rel_vel_ray * hitObjShapeProps.m_fh_damping; - - cl_object->setLinearVelocity(cl_object->getLinearVelocity() + (-(i_spring + i_damp) * ray_dir)); - if (hitObjShapeProps.m_fh_normal) - { - cl_object->setLinearVelocity(cl_object->getLinearVelocity()+(i_spring + i_damp) *(normal - normal.dot(ray_dir) * ray_dir)); - } - - btVector3 lateral = rel_vel - rel_vel_ray * ray_dir; - - - if (ctrl->getConstructionInfo().m_do_anisotropic) { - //Bullet basis contains no scaling/shear etc. - const btMatrix3x3& lcs = cl_object->getCenterOfMassTransform().getBasis(); - btVector3 loc_lateral = lateral * lcs; - const btVector3& friction_scaling = cl_object->getAnisotropicFriction(); - loc_lateral *= friction_scaling; - lateral = lcs * loc_lateral; + btScalar rel_vel_lateral = lateral.length(); + + if (rel_vel_lateral > SIMD_EPSILON) { + btScalar friction_factor = hit_object->getFriction();//cl_object->getFriction(); + + btScalar max_friction = friction_factor * btMax(btScalar(0.0), i_spring); + + btScalar rel_mom_lateral = rel_vel_lateral / cl_object->getInvMass(); + + btVector3 friction = (rel_mom_lateral > max_friction) ? + -lateral * (max_friction / rel_vel_lateral) : + -lateral; + + cl_object->applyCentralImpulse(friction); + } } - btScalar rel_vel_lateral = lateral.length(); - if (rel_vel_lateral > SIMD_EPSILON) { - btScalar friction_factor = hit_object->getFriction();//cl_object->getFriction(); + if (ctrl->getConstructionInfo().m_do_rot_fh) { + btVector3 up2 = cl_object->getWorldTransform().getBasis().getColumn(2); - btScalar max_friction = friction_factor * btMax(btScalar(0.0), i_spring); + btVector3 t_spring = up2.cross(normal) * hitObjShapeProps.m_fh_spring; + btVector3 ang_vel = cl_object->getAngularVelocity(); - btScalar rel_mom_lateral = rel_vel_lateral / cl_object->getInvMass(); + // only rotations that tilt relative to the normal are damped + ang_vel -= ang_vel.dot(normal) * normal; - btVector3 friction = (rel_mom_lateral > max_friction) ? - -lateral * (max_friction / rel_vel_lateral) : - -lateral; + btVector3 t_damp = ang_vel * hitObjShapeProps.m_fh_damping; - cl_object->applyCentralImpulse(friction); + cl_object->setAngularVelocity(cl_object->getAngularVelocity() + (t_spring - t_damp)); } } - - - if (ctrl->getConstructionInfo().m_do_rot_fh) { - btVector3 up2 = cl_object->getWorldTransform().getBasis().getColumn(2); - - btVector3 t_spring = up2.cross(normal) * hitObjShapeProps.m_fh_spring; - btVector3 ang_vel = cl_object->getAngularVelocity(); - - // only rotations that tilt relative to the normal are damped - ang_vel -= ang_vel.dot(normal) * normal; - - btVector3 t_damp = ang_vel * hitObjShapeProps.m_fh_damping; - - cl_object->setAngularVelocity(cl_object->getAngularVelocity() + (t_spring - t_damp)); - } - } - - } - - } } - } void CcdPhysicsEnvironment::setDebugMode(int debugMode) @@ -833,7 +849,8 @@ void CcdPhysicsEnvironment::setSolverType(int solverType) { m_solver = new btSequentialImpulseConstraintSolver(); -// ((btSequentialImpulseConstraintSolver*)m_solver)->setSolverMode(btSequentialImpulseConstraintSolver::SOLVER_USE_WARMSTARTING | btSequentialImpulseConstraintSolver::SOLVER_RANDMIZE_ORDER); + + break; } } @@ -905,7 +922,7 @@ int CcdPhysicsEnvironment::createUniversalD6Constraint( bool useReferenceFrameA = true; - genericConstraint = new btGeneric6DofConstraint( + genericConstraint = new btGeneric6DofSpringConstraint( *rb0,*rb1, frameInA,frameInB,useReferenceFrameA); genericConstraint->setLinearLowerLimit(linearMinLimits); @@ -986,7 +1003,7 @@ struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResul virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { - CcdPhysicsController* curHit = static_cast<CcdPhysicsController*>(rayResult.m_collisionObject->getUserPointer()); + //CcdPhysicsController* curHit = static_cast<CcdPhysicsController*>(rayResult.m_collisionObject->getUserPointer()); // save shape information as ClosestRayResultCallback::AddSingleResult() does not do it if (rayResult.m_localShapeInfo) { @@ -1004,10 +1021,6 @@ struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResul PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ) { - - - float minFraction = 1.f; - btVector3 rayFrom(fromX,fromY,fromZ); btVector3 rayTo(toX,toY,toZ); @@ -1128,7 +1141,577 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallbac return result.m_controller; } +// Handles occlusion culling. +// The implementation is based on the CDTestFramework +struct OcclusionBuffer +{ + struct WriteOCL + { + static inline bool Process(btScalar& q,btScalar v) { if(q<v) q=v;return(false); } + static inline void Occlusion(bool& flag) { flag = true; } + }; + struct QueryOCL + { + static inline bool Process(btScalar& q,btScalar v) { return(q<=v); } + static inline void Occlusion(bool& flag) { } + }; + btScalar* m_buffer; + size_t m_bufferSize; + bool m_initialized; + bool m_occlusion; + int m_sizes[2]; + btScalar m_scales[2]; + btScalar m_offsets[2]; + btScalar m_wtc[16]; // world to clip transform + btScalar m_mtc[16]; // model to clip transform + // constructor: size=largest dimension of the buffer. + // Buffer size depends on aspect ratio + OcclusionBuffer() + { + m_initialized=false; + m_occlusion = false; + m_buffer = NULL; + m_bufferSize = 0; + } + // multiplication of column major matrices: m=m1*m2 + template<typename T1, typename T2> + void CMmat4mul(btScalar* m, const T1* m1, const T2* m2) + { + m[ 0] = btScalar(m1[ 0]*m2[ 0]+m1[ 4]*m2[ 1]+m1[ 8]*m2[ 2]+m1[12]*m2[ 3]); + m[ 1] = btScalar(m1[ 1]*m2[ 0]+m1[ 5]*m2[ 1]+m1[ 9]*m2[ 2]+m1[13]*m2[ 3]); + m[ 2] = btScalar(m1[ 2]*m2[ 0]+m1[ 6]*m2[ 1]+m1[10]*m2[ 2]+m1[14]*m2[ 3]); + m[ 3] = btScalar(m1[ 3]*m2[ 0]+m1[ 7]*m2[ 1]+m1[11]*m2[ 2]+m1[15]*m2[ 3]); + + m[ 4] = btScalar(m1[ 0]*m2[ 4]+m1[ 4]*m2[ 5]+m1[ 8]*m2[ 6]+m1[12]*m2[ 7]); + m[ 5] = btScalar(m1[ 1]*m2[ 4]+m1[ 5]*m2[ 5]+m1[ 9]*m2[ 6]+m1[13]*m2[ 7]); + m[ 6] = btScalar(m1[ 2]*m2[ 4]+m1[ 6]*m2[ 5]+m1[10]*m2[ 6]+m1[14]*m2[ 7]); + m[ 7] = btScalar(m1[ 3]*m2[ 4]+m1[ 7]*m2[ 5]+m1[11]*m2[ 6]+m1[15]*m2[ 7]); + + m[ 8] = btScalar(m1[ 0]*m2[ 8]+m1[ 4]*m2[ 9]+m1[ 8]*m2[10]+m1[12]*m2[11]); + m[ 9] = btScalar(m1[ 1]*m2[ 8]+m1[ 5]*m2[ 9]+m1[ 9]*m2[10]+m1[13]*m2[11]); + m[10] = btScalar(m1[ 2]*m2[ 8]+m1[ 6]*m2[ 9]+m1[10]*m2[10]+m1[14]*m2[11]); + m[11] = btScalar(m1[ 3]*m2[ 8]+m1[ 7]*m2[ 9]+m1[11]*m2[10]+m1[15]*m2[11]); + + m[12] = btScalar(m1[ 0]*m2[12]+m1[ 4]*m2[13]+m1[ 8]*m2[14]+m1[12]*m2[15]); + m[13] = btScalar(m1[ 1]*m2[12]+m1[ 5]*m2[13]+m1[ 9]*m2[14]+m1[13]*m2[15]); + m[14] = btScalar(m1[ 2]*m2[12]+m1[ 6]*m2[13]+m1[10]*m2[14]+m1[14]*m2[15]); + m[15] = btScalar(m1[ 3]*m2[12]+m1[ 7]*m2[13]+m1[11]*m2[14]+m1[15]*m2[15]); + } + void setup(int size) + { + m_initialized=false; + m_occlusion=false; + // compute the size of the buffer + GLint v[4]; + GLdouble m[16],p[16]; + int maxsize; + double ratio; + glGetIntegerv(GL_VIEWPORT,v); + maxsize = (v[2] > v[3]) ? v[2] : v[3]; + assert(maxsize > 0); + ratio = 1.0/(2*maxsize); + // ensure even number + m_sizes[0] = 2*((int)(size*v[2]*ratio+0.5)); + m_sizes[1] = 2*((int)(size*v[3]*ratio+0.5)); + m_scales[0]=btScalar(m_sizes[0]/2); + m_scales[1]=btScalar(m_sizes[1]/2); + m_offsets[0]=m_scales[0]+0.5f; + m_offsets[1]=m_scales[1]+0.5f; + // prepare matrix + // at this time of the rendering, the modelview matrix is the + // world to camera transformation and the projection matrix is + // camera to clip transformation. combine both so that + glGetDoublev(GL_MODELVIEW_MATRIX,m); + glGetDoublev(GL_PROJECTION_MATRIX,p); + CMmat4mul(m_wtc,p,m); + } + void initialize() + { + size_t newsize = (m_sizes[0]*m_sizes[1])*sizeof(btScalar); + if (m_buffer) + { + // see if we can reuse + if (newsize > m_bufferSize) + { + free(m_buffer); + m_buffer = NULL; + m_bufferSize = 0; + } + } + if (!m_buffer) + { + m_buffer = (btScalar*)calloc(1, newsize); + m_bufferSize = newsize; + } else + { + // buffer exists already, just clears it + memset(m_buffer, 0, newsize); + } + // memory allocate must succeed + assert(m_buffer != NULL); + m_initialized = true; + m_occlusion = false; + } + void SetModelMatrix(double *fl) + { + CMmat4mul(m_mtc,m_wtc,fl); + if (!m_initialized) + initialize(); + } + + // transform a segment in world coordinate to clip coordinate + void transformW(const btVector3& x, btVector4& t) + { + t[0] = x[0]*m_wtc[0]+x[1]*m_wtc[4]+x[2]*m_wtc[8]+m_wtc[12]; + t[1] = x[0]*m_wtc[1]+x[1]*m_wtc[5]+x[2]*m_wtc[9]+m_wtc[13]; + t[2] = x[0]*m_wtc[2]+x[1]*m_wtc[6]+x[2]*m_wtc[10]+m_wtc[14]; + t[3] = x[0]*m_wtc[3]+x[1]*m_wtc[7]+x[2]*m_wtc[11]+m_wtc[15]; + } + void transformM(const float* x, btVector4& t) + { + t[0] = x[0]*m_mtc[0]+x[1]*m_mtc[4]+x[2]*m_mtc[8]+m_mtc[12]; + t[1] = x[0]*m_mtc[1]+x[1]*m_mtc[5]+x[2]*m_mtc[9]+m_mtc[13]; + t[2] = x[0]*m_mtc[2]+x[1]*m_mtc[6]+x[2]*m_mtc[10]+m_mtc[14]; + t[3] = x[0]*m_mtc[3]+x[1]*m_mtc[7]+x[2]*m_mtc[11]+m_mtc[15]; + } + // convert polygon to device coordinates + static bool project(btVector4* p,int n) + { + for(int i=0;i<n;++i) + { + p[i][2]=1/p[i][3]; + p[i][0]*=p[i][2]; + p[i][1]*=p[i][2]; + } + return(true); + } + // pi: closed polygon in clip coordinate, NP = number of segments + // po: same polygon with clipped segments removed + template <const int NP> + static int clip(const btVector4* pi,btVector4* po) + { + btScalar s[2*NP]; + btVector4 pn[2*NP]; + int i, j, m, n, ni; + // deal with near clipping + for(i=0, m=0;i<NP;++i) + { + s[i]=pi[i][2]+pi[i][3]; + if(s[i]<0) m+=1<<i; + } + if(m==((1<<NP)-1)) + return(0); + if(m!=0) + { + for(i=NP-1,j=0,n=0;j<NP;i=j++) + { + const btVector4& a=pi[i]; + const btVector4& b=pi[j]; + const btScalar t=s[i]/(a[3]+a[2]-b[3]-b[2]); + if((t>0)&&(t<1)) + { + pn[n][0] = a[0]+(b[0]-a[0])*t; + pn[n][1] = a[1]+(b[1]-a[1])*t; + pn[n][2] = a[2]+(b[2]-a[2])*t; + pn[n][3] = a[3]+(b[3]-a[3])*t; + ++n; + } + if(s[j]>0) pn[n++]=b; + } + // ready to test far clipping, start from the modified polygon + pi = pn; + ni = n; + } else + { + // no clipping on the near plane, keep same vector + ni = NP; + } + // now deal with far clipping + for(i=0, m=0;i<ni;++i) + { + s[i]=pi[i][2]-pi[i][3]; + if(s[i]>0) m+=1<<i; + } + if(m==((1<<ni)-1)) + return(0); + if(m!=0) + { + for(i=ni-1,j=0,n=0;j<ni;i=j++) + { + const btVector4& a=pi[i]; + const btVector4& b=pi[j]; + const btScalar t=s[i]/(a[2]-a[3]-b[2]+b[3]); + if((t>0)&&(t<1)) + { + po[n][0] = a[0]+(b[0]-a[0])*t; + po[n][1] = a[1]+(b[1]-a[1])*t; + po[n][2] = a[2]+(b[2]-a[2])*t; + po[n][3] = a[3]+(b[3]-a[3])*t; + ++n; + } + if(s[j]<0) po[n++]=b; + } + return(n); + } + for(int i=0;i<ni;++i) po[i]=pi[i]; + return(ni); + } + // write or check a triangle to buffer. a,b,c in device coordinates (-1,+1) + template <typename POLICY> + inline bool draw( const btVector4& a, + const btVector4& b, + const btVector4& c, + const float face, + const btScalar minarea) + { + const btScalar a2=cross(b-a,c-a)[2]; + if((face*a2)<0.f || btFabs(a2)<minarea) + return false; + // further down we are normally going to write to the Zbuffer, mark it so + POLICY::Occlusion(m_occlusion); + + int x[3], y[3], ib=1, ic=2; + btScalar z[3]; + x[0]=(int)(a.x()*m_scales[0]+m_offsets[0]); + y[0]=(int)(a.y()*m_scales[1]+m_offsets[1]); + z[0]=a.z(); + if (a2 < 0.f) + { + // negative aire is possible with double face => must + // change the order of b and c otherwise the algorithm doesn't work + ib=2; + ic=1; + } + x[ib]=(int)(b.x()*m_scales[0]+m_offsets[0]); + x[ic]=(int)(c.x()*m_scales[0]+m_offsets[0]); + y[ib]=(int)(b.y()*m_scales[1]+m_offsets[1]); + y[ic]=(int)(c.y()*m_scales[1]+m_offsets[1]); + z[ib]=b.z(); + z[ic]=c.z(); + const int mix=btMax(0,btMin(x[0],btMin(x[1],x[2]))); + const int mxx=btMin(m_sizes[0],1+btMax(x[0],btMax(x[1],x[2]))); + const int miy=btMax(0,btMin(y[0],btMin(y[1],y[2]))); + const int mxy=btMin(m_sizes[1],1+btMax(y[0],btMax(y[1],y[2]))); + const int width=mxx-mix; + const int height=mxy-miy; + if ((width*height) <= 1) + { + // degenerated in at most one single pixel + btScalar* scan=&m_buffer[miy*m_sizes[0]+mix]; + // use for loop to detect the case where width or height == 0 + for(int iy=miy;iy<mxy;++iy) + { + for(int ix=mix;ix<mxx;++ix) + { + if(POLICY::Process(*scan,z[0])) + return(true); + if(POLICY::Process(*scan,z[1])) + return(true); + if(POLICY::Process(*scan,z[2])) + return(true); + } + } + } else if (width == 1) + { + // Degenerated in at least 2 vertical lines + // The algorithm below doesn't work when face has a single pixel width + // We cannot use general formulas because the plane is degenerated. + // We have to interpolate along the 3 edges that overlaps and process each pixel. + // sort the y coord to make formula simpler + int ytmp; + btScalar ztmp; + if (y[0] > y[1]) { ytmp=y[1];y[1]=y[0];y[0]=ytmp;ztmp=z[1];z[1]=z[0];z[0]=ztmp; } + if (y[0] > y[2]) { ytmp=y[2];y[2]=y[0];y[0]=ytmp;ztmp=z[2];z[2]=z[0];z[0]=ztmp; } + if (y[1] > y[2]) { ytmp=y[2];y[2]=y[1];y[1]=ytmp;ztmp=z[2];z[2]=z[1];z[1]=ztmp; } + int dy[]={ y[0]-y[1], + y[1]-y[2], + y[2]-y[0]}; + btScalar dzy[3]; + dzy[0] = (dy[0]) ? (z[0]-z[1])/dy[0] : btScalar(0.f); + dzy[1] = (dy[1]) ? (z[1]-z[2])/dy[1] : btScalar(0.f); + dzy[2] = (dy[2]) ? (z[2]-z[0])/dy[2] : btScalar(0.f); + btScalar v[3] = { dzy[0]*(miy-y[0])+z[0], + dzy[1]*(miy-y[1])+z[1], + dzy[2]*(miy-y[2])+z[2] }; + dy[0] = y[1]-y[0]; + dy[1] = y[0]-y[1]; + dy[2] = y[2]-y[0]; + btScalar* scan=&m_buffer[miy*m_sizes[0]+mix]; + for(int iy=miy;iy<mxy;++iy) + { + if(dy[0] >= 0 && POLICY::Process(*scan,v[0])) + return(true); + if(dy[1] >= 0 && POLICY::Process(*scan,v[1])) + return(true); + if(dy[2] >= 0 && POLICY::Process(*scan,v[2])) + return(true); + scan+=m_sizes[0]; + v[0] += dzy[0]; v[1] += dzy[1]; v[2] += dzy[2]; + dy[0]--; dy[1]++, dy[2]--; + } + } else if (height == 1) + { + // Degenerated in at least 2 horizontal lines + // The algorithm below doesn't work when face has a single pixel width + // We cannot use general formulas because the plane is degenerated. + // We have to interpolate along the 3 edges that overlaps and process each pixel. + int xtmp; + btScalar ztmp; + if (x[0] > x[1]) { xtmp=x[1];x[1]=x[0];x[0]=xtmp;ztmp=z[1];z[1]=z[0];z[0]=ztmp; } + if (x[0] > x[2]) { xtmp=x[2];x[2]=x[0];x[0]=xtmp;ztmp=z[2];z[2]=z[0];z[0]=ztmp; } + if (x[1] > x[2]) { xtmp=x[2];x[2]=x[1];x[1]=xtmp;ztmp=z[2];z[2]=z[1];z[1]=ztmp; } + int dx[]={ x[0]-x[1], + x[1]-x[2], + x[2]-x[0]}; + btScalar dzx[3]; + dzx[0] = (dx[0]) ? (z[0]-z[1])/dx[0] : btScalar(0.f); + dzx[1] = (dx[1]) ? (z[1]-z[2])/dx[1] : btScalar(0.f); + dzx[2] = (dx[2]) ? (z[2]-z[0])/dx[2] : btScalar(0.f); + btScalar v[3] = { dzx[0]*(mix-x[0])+z[0], + dzx[1]*(mix-x[1])+z[1], + dzx[2]*(mix-x[2])+z[2] }; + dx[0] = x[1]-x[0]; + dx[1] = x[0]-x[1]; + dx[2] = x[2]-x[0]; + btScalar* scan=&m_buffer[miy*m_sizes[0]+mix]; + for(int ix=mix;ix<mxx;++ix) + { + if(dx[0] >= 0 && POLICY::Process(*scan,v[0])) + return(true); + if(dx[1] >= 0 && POLICY::Process(*scan,v[1])) + return(true); + if(dx[2] >= 0 && POLICY::Process(*scan,v[2])) + return(true); + scan++; + v[0] += dzx[0]; v[1] += dzx[1]; v[2] += dzx[2]; + dx[0]--; dx[1]++, dx[2]--; + } + } else + { + // general case + const int dx[]={ y[0]-y[1], + y[1]-y[2], + y[2]-y[0]}; + const int dy[]={ x[1]-x[0]-dx[0]*width, + x[2]-x[1]-dx[1]*width, + x[0]-x[2]-dx[2]*width}; + const int a=x[2]*y[0]+x[0]*y[1]-x[2]*y[1]-x[0]*y[2]+x[1]*y[2]-x[1]*y[0]; + const btScalar ia=1/(btScalar)a; + const btScalar dzx=ia*(y[2]*(z[1]-z[0])+y[1]*(z[0]-z[2])+y[0]*(z[2]-z[1])); + const btScalar dzy=ia*(x[2]*(z[0]-z[1])+x[0]*(z[1]-z[2])+x[1]*(z[2]-z[0]))-(dzx*width); + int c[]={ miy*x[1]+mix*y[0]-x[1]*y[0]-mix*y[1]+x[0]*y[1]-miy*x[0], + miy*x[2]+mix*y[1]-x[2]*y[1]-mix*y[2]+x[1]*y[2]-miy*x[1], + miy*x[0]+mix*y[2]-x[0]*y[2]-mix*y[0]+x[2]*y[0]-miy*x[2]}; + btScalar v=ia*((z[2]*c[0])+(z[0]*c[1])+(z[1]*c[2])); + btScalar* scan=&m_buffer[miy*m_sizes[0]]; + for(int iy=miy;iy<mxy;++iy) + { + for(int ix=mix;ix<mxx;++ix) + { + if((c[0]>=0)&&(c[1]>=0)&&(c[2]>=0)) + { + if(POLICY::Process(scan[ix],v)) + return(true); + } + c[0]+=dx[0];c[1]+=dx[1];c[2]+=dx[2];v+=dzx; + } + c[0]+=dy[0];c[1]+=dy[1];c[2]+=dy[2];v+=dzy; + scan+=m_sizes[0]; + } + } + return(false); + } + // clip than write or check a polygon + template <const int NP,typename POLICY> + inline bool clipDraw( const btVector4* p, + const float face, + btScalar minarea) + { + btVector4 o[NP*2]; + int n=clip<NP>(p,o); + bool earlyexit=false; + if (n) + { + project(o,n); + for(int i=2;i<n && !earlyexit;++i) + { + earlyexit|=draw<POLICY>(o[0],o[i-1],o[i],face,minarea); + } + } + return(earlyexit); + } + // add a triangle (in model coordinate) + // face = 0.f if face is double side, + // = 1.f if face is single sided and scale is positive + // = -1.f if face is single sided and scale is negative + void appendOccluderM(const float* a, + const float* b, + const float* c, + const float face) + { + btVector4 p[3]; + transformM(a,p[0]); + transformM(b,p[1]); + transformM(c,p[2]); + clipDraw<3,WriteOCL>(p,face,btScalar(0.f)); + } + // add a quad (in model coordinate) + void appendOccluderM(const float* a, + const float* b, + const float* c, + const float* d, + const float face) + { + btVector4 p[4]; + transformM(a,p[0]); + transformM(b,p[1]); + transformM(c,p[2]); + transformM(d,p[3]); + clipDraw<4,WriteOCL>(p,face,btScalar(0.f)); + } + // query occluder for a box (c=center, e=extend) in world coordinate + inline bool queryOccluderW( const btVector3& c, + const btVector3& e) + { + if (!m_occlusion) + // no occlusion yet, no need to check + return true; + btVector4 x[8]; + transformW(btVector3(c[0]-e[0],c[1]-e[1],c[2]-e[2]),x[0]); + transformW(btVector3(c[0]+e[0],c[1]-e[1],c[2]-e[2]),x[1]); + transformW(btVector3(c[0]+e[0],c[1]+e[1],c[2]-e[2]),x[2]); + transformW(btVector3(c[0]-e[0],c[1]+e[1],c[2]-e[2]),x[3]); + transformW(btVector3(c[0]-e[0],c[1]-e[1],c[2]+e[2]),x[4]); + transformW(btVector3(c[0]+e[0],c[1]-e[1],c[2]+e[2]),x[5]); + transformW(btVector3(c[0]+e[0],c[1]+e[1],c[2]+e[2]),x[6]); + transformW(btVector3(c[0]-e[0],c[1]+e[1],c[2]+e[2]),x[7]); + for(int i=0;i<8;++i) + { + // the box is clipped, it's probably a large box, don't waste our time to check + if((x[i][2]+x[i][3])<=0) return(true); + } + static const int d[]={ 1,0,3,2, + 4,5,6,7, + 4,7,3,0, + 6,5,1,2, + 7,6,2,3, + 5,4,0,1}; + for(unsigned int i=0;i<(sizeof(d)/sizeof(d[0]));) + { + const btVector4 p[]={ x[d[i++]], + x[d[i++]], + x[d[i++]], + x[d[i++]]}; + if(clipDraw<4,QueryOCL>(p,1.f,0.f)) + return(true); + } + return(false); + } +}; + + +struct DbvtCullingCallback : btDbvt::ICollide +{ + PHY_CullingCallback m_clientCallback; + void* m_userData; + OcclusionBuffer *m_ocb; + + DbvtCullingCallback(PHY_CullingCallback clientCallback, void* userData) + { + m_clientCallback = clientCallback; + m_userData = userData; + m_ocb = NULL; + } + bool Descent(const btDbvtNode* node) + { + return(m_ocb->queryOccluderW(node->volume.Center(),node->volume.Extents())); + } + void Process(const btDbvtNode* node,btScalar depth) + { + Process(node); + } + void Process(const btDbvtNode* leaf) + { + btBroadphaseProxy* proxy=(btBroadphaseProxy*)leaf->data; + // the client object is a graphic controller + CcdGraphicController* ctrl = static_cast<CcdGraphicController*>(proxy->m_clientObject); + KX_ClientObjectInfo* info = (KX_ClientObjectInfo*)ctrl->getNewClientInfo(); + if (m_ocb) + { + // means we are doing occlusion culling. Check if this object is an occluders + KX_GameObject* gameobj = KX_GameObject::GetClientObject(info); + if (gameobj && gameobj->GetOccluder()) + { + double* fl = gameobj->GetOpenGLMatrixPtr()->getPointer(); + // this will create the occlusion buffer if not already done + // and compute the transformation from model local space to clip space + m_ocb->SetModelMatrix(fl); + float face = (gameobj->IsNegativeScaling()) ? -1.0f : 1.0f; + // walk through the meshes and for each add to buffer + for (int i=0; i<gameobj->GetMeshCount(); i++) + { + RAS_MeshObject* meshobj = gameobj->GetMesh(i); + const float *v1, *v2, *v3, *v4; + + int polycount = meshobj->NumPolygons(); + for (int j=0; j<polycount; j++) + { + RAS_Polygon* poly = meshobj->GetPolygon(j); + switch (poly->VertexCount()) + { + case 3: + v1 = poly->GetVertex(0)->getXYZ(); + v2 = poly->GetVertex(1)->getXYZ(); + v3 = poly->GetVertex(2)->getXYZ(); + m_ocb->appendOccluderM(v1,v2,v3,((poly->IsTwoside())?0.f:face)); + break; + case 4: + v1 = poly->GetVertex(0)->getXYZ(); + v2 = poly->GetVertex(1)->getXYZ(); + v3 = poly->GetVertex(2)->getXYZ(); + v4 = poly->GetVertex(3)->getXYZ(); + m_ocb->appendOccluderM(v1,v2,v3,v4,((poly->IsTwoside())?0.f:face)); + break; + } + } + } + } + } + if (info) + (*m_clientCallback)(info, m_userData); + } +}; +static OcclusionBuffer gOcb; +bool CcdPhysicsEnvironment::cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4 *planes, int nplanes, int occlusionRes) +{ + if (!m_cullingTree) + return false; + DbvtCullingCallback dispatcher(callback, userData); + btVector3 planes_n[6]; + btScalar planes_o[6]; + if (nplanes > 6) + nplanes = 6; + for (int i=0; i<nplanes; i++) + { + planes_n[i].setValue(planes[i][0], planes[i][1], planes[i][2]); + planes_o[i] = planes[i][3]; + } + // if occlusionRes != 0 => occlusion culling + if (occlusionRes) + { + gOcb.setup(occlusionRes); + dispatcher.m_ocb = &gOcb; + // occlusion culling, the direction of the view is taken from the first plan which MUST be the near plane + btDbvt::collideOCL(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,planes_n[0],nplanes,dispatcher); + btDbvt::collideOCL(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,planes_n[0],nplanes,dispatcher); + }else + { + btDbvt::collideKDOP(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,nplanes,dispatcher); + btDbvt::collideKDOP(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,nplanes,dispatcher); + } + return true; +} int CcdPhysicsEnvironment::getNumContactPoints() { @@ -1193,9 +1776,55 @@ CcdPhysicsEnvironment::~CcdPhysicsEnvironment() if (NULL != m_broadphase) delete m_broadphase; + + if (NULL != m_cullingTree) + delete m_cullingTree; + + if (NULL != m_cullingCache) + delete m_cullingCache; + } +float CcdPhysicsEnvironment::getConstraintParam(int constraintId,int param) +{ + btTypedConstraint* typedConstraint = getConstraintById(constraintId); + switch (typedConstraint->getUserConstraintType()) + { + case PHY_GENERIC_6DOF_CONSTRAINT: + { + + switch (param) + { + case 0: case 1: case 2: + { + //param = 0..2 are linear constraint values + btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; + genCons->calculateTransforms(); + return genCons->getRelativePivotPosition(param); + break; + } + case 3: case 4: case 5: + { + //param = 3..5 are relative constraint (Euler) angles + btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; + genCons->calculateTransforms(); + return genCons->getAngle(param-3); + break; + } + default: + { + } + } + break; + }; + default: + { + }; + }; + return 0.f; +} + void CcdPhysicsEnvironment::setConstraintParam(int constraintId,int param,float value0,float value1) { btTypedConstraint* typedConstraint = getConstraintById(constraintId); @@ -1203,9 +1832,63 @@ void CcdPhysicsEnvironment::setConstraintParam(int constraintId,int param,float { case PHY_GENERIC_6DOF_CONSTRAINT: { - //param = 1..12, min0,max0,min1,max1...min6,max6 - btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; - genCons->setLimit(param,value0,value1); + + switch (param) + { + case 0: case 1: case 2: case 3: case 4: case 5: + { + //param = 0..5 are constraint limits, with low/high limit value + btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; + genCons->setLimit(param,value0,value1); + break; + } + case 6: case 7: case 8: + { + //param = 6,7,8 are translational motors, with value0=target velocity, value1 = max motor force + btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; + int transMotorIndex = param-6; + btTranslationalLimitMotor* transMotor = genCons->getTranslationalLimitMotor(); + transMotor->m_targetVelocity[transMotorIndex]= value0; + transMotor->m_maxMotorForce[transMotorIndex]=value1; + transMotor->m_enableMotor[transMotorIndex] = (value1>0.f); + break; + } + case 9: case 10: case 11: + { + //param = 9,10,11 are rotational motors, with value0=target velocity, value1 = max motor force + btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; + int angMotorIndex = param-9; + btRotationalLimitMotor* rotMotor = genCons->getRotationalLimitMotor(angMotorIndex); + rotMotor->m_enableMotor = (value1 > 0.f); + rotMotor->m_targetVelocity = value0; + rotMotor->m_maxMotorForce = value1; + break; + } + + case 12: case 13: case 14: case 15: case 16: case 17: + { + //param 13-17 are for motorized springs on each of the degrees of freedom + btGeneric6DofSpringConstraint* genCons = (btGeneric6DofSpringConstraint*)typedConstraint; + int springIndex = param-12; + if (value0!=0.f) + { + bool springEnabled = true; + genCons->setStiffness(springIndex,value0); + genCons->setDamping(springIndex,value1); + genCons->enableSpring(springIndex,springEnabled); + genCons->setEquilibriumPoint(springIndex); + } else + { + bool springEnabled = false; + genCons->enableSpring(springIndex,springEnabled); + } + break; + } + + default: + { + } + } break; }; default: @@ -1242,29 +1925,20 @@ void CcdPhysicsEnvironment::addSensor(PHY_IPhysicsController* ctrl) // addCcdPhysicsController(ctrl1); //} enableCcdPhysicsController(ctrl1); - - //Collision filter/mask is now set at the time of the creation of the controller - //force collision detection with everything, including static objects (might hurt performance!) - //ctrl1->GetRigidBody()->getBroadphaseHandle()->m_collisionFilterMask = btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::SensorTrigger; - //ctrl1->GetRigidBody()->getBroadphaseHandle()->m_collisionFilterGroup = btBroadphaseProxy::SensorTrigger; - //todo: make this 'sensor'! - - requestCollisionCallback(ctrl); - //printf("addSensor\n"); } -void CcdPhysicsEnvironment::removeCollisionCallback(PHY_IPhysicsController* ctrl) +bool CcdPhysicsEnvironment::removeCollisionCallback(PHY_IPhysicsController* ctrl) { CcdPhysicsController* ccdCtrl = (CcdPhysicsController*)ctrl; - if (ccdCtrl->Unregister()) - m_triggerControllers.erase(ccdCtrl); + if (!ccdCtrl->Unregister()) + return false; + m_triggerControllers.erase(ccdCtrl); + return true; } void CcdPhysicsEnvironment::removeSensor(PHY_IPhysicsController* ctrl) { - removeCollisionCallback(ctrl); - disableCcdPhysicsController((CcdPhysicsController*)ctrl); } @@ -1300,19 +1974,18 @@ void CcdPhysicsEnvironment::addTouchCallback(int response_class, PHY_ResponseCal m_triggerCallbacksUserPtrs[response_class] = user; } -void CcdPhysicsEnvironment::requestCollisionCallback(PHY_IPhysicsController* ctrl) +bool CcdPhysicsEnvironment::requestCollisionCallback(PHY_IPhysicsController* ctrl) { CcdPhysicsController* ccdCtrl = static_cast<CcdPhysicsController*>(ctrl); - if (ccdCtrl->Register()) - m_triggerControllers.insert(ccdCtrl); + if (!ccdCtrl->Register()) + return false; + m_triggerControllers.insert(ccdCtrl); + return true; } void CcdPhysicsEnvironment::CallbackTriggers() { - - CcdPhysicsController* ctrl0=0,*ctrl1=0; - if (m_triggerCallbacks[PHY_OBJECT_RESPONSE] || (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints))) { //walk over all overlapping pairs, and if one of the involved bodies is registered for trigger callback, perform callback @@ -1447,19 +2120,20 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::CreateSphereController(float radi { CcdConstructionInfo cinfo; - // memory leak! The shape is not deleted by Bullet and we cannot add it to the KX_Scene.m_shapes list - cinfo.m_collisionShape = new btSphereShape(radius); + memset(&cinfo, 0, sizeof(cinfo)); /* avoid uninitialized values */ + cinfo.m_collisionShape = new btSphereShape(radius); // memory leak! The shape is not deleted by Bullet and we cannot add it to the KX_Scene.m_shapes list cinfo.m_MotionState = 0; cinfo.m_physicsEnv = this; // declare this object as Dyamic rather then static!! // The reason as it is designed to detect all type of object, including static object // It would cause static-static message to be printed on the console otherwise - cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE/* | btCollisionObject::CF_KINEMATIC_OBJECT*/; + cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE | btCollisionObject::CF_STATIC_OBJECT; DefaultMotionState* motionState = new DefaultMotionState(); cinfo.m_MotionState = motionState; // we will add later the possibility to select the filter from option cinfo.m_collisionFilterMask = CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter; cinfo.m_collisionFilterGroup = CcdConstructionInfo::SensorFilter; + cinfo.m_bSensor = true; motionState->m_worldTransform.setIdentity(); motionState->m_worldTransform.setOrigin(btVector3(position[0],position[1],position[2])); @@ -1728,7 +2402,7 @@ int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl frameInB = inv * globalFrameA; bool useReferenceFrameA = true; - genericConstraint = new btGeneric6DofConstraint( + genericConstraint = new btGeneric6DofSpringConstraint( *rb0,*rb1, frameInA,frameInB,useReferenceFrameA); @@ -1752,7 +2426,7 @@ int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl frameInB = rb0->getCenterOfMassTransform() * frameInA; bool useReferenceFrameA = true; - genericConstraint = new btGeneric6DofConstraint( + genericConstraint = new btGeneric6DofSpringConstraint( *rb0,s_fixedObject2, frameInA,frameInB,useReferenceFrameA); } @@ -1907,19 +2581,20 @@ int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl PHY_IPhysicsController* CcdPhysicsEnvironment::CreateConeController(float coneradius,float coneheight) { CcdConstructionInfo cinfo; - + memset(&cinfo, 0, sizeof(cinfo)); /* avoid uninitialized values */ // we don't need a CcdShapeConstructionInfo for this shape: // it is simple enough for the standard copy constructor (see CcdPhysicsController::GetReplica) cinfo.m_collisionShape = new btConeShape(coneradius,coneheight); cinfo.m_MotionState = 0; cinfo.m_physicsEnv = this; - cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE; + cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE | btCollisionObject::CF_STATIC_OBJECT; DefaultMotionState* motionState = new DefaultMotionState(); cinfo.m_MotionState = motionState; // we will add later the possibility to select the filter from option cinfo.m_collisionFilterMask = CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter; cinfo.m_collisionFilterGroup = CcdConstructionInfo::SensorFilter; + cinfo.m_bSensor = true; motionState->m_worldTransform.setIdentity(); // motionState->m_worldTransform.setOrigin(btVector3(position[0],position[1],position[2])); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h index 74384dd8cf2..e087eac32c5 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h @@ -20,6 +20,7 @@ subject to the following restrictions: #include <vector> #include <set> class CcdPhysicsController; +class CcdGraphicController; #include "LinearMath/btVector3.h" #include "LinearMath/btTransform.h" @@ -40,6 +41,7 @@ class btDispatcher; class WrapperVehicle; class btPersistentManifold; class btBroadphaseInterface; +struct btDbvtBroadphase; class btOverlappingPairCache; class btIDebugDraw; class PHY_IVehicle; @@ -58,7 +60,10 @@ protected: btIDebugDraw* m_debugDrawer; class btDefaultCollisionConfiguration* m_collisionConfiguration; - class btBroadphaseInterface* m_broadphase; + class btBroadphaseInterface* m_broadphase; // broadphase for dynamic world + // for culling only + btOverlappingPairCache* m_cullingCache; + struct btDbvtBroadphase* m_cullingTree; // broadphase for culling //solver iterations int m_numIterations; @@ -77,7 +82,7 @@ protected: void processFhSprings(double curTime,float timeStep); public: - CcdPhysicsEnvironment(btDispatcher* dispatcher=0, btOverlappingPairCache* pairCache=0); + CcdPhysicsEnvironment(bool useDbvtCulling, btDispatcher* dispatcher=0, btOverlappingPairCache* pairCache=0); virtual ~CcdPhysicsEnvironment(); @@ -109,7 +114,9 @@ protected: virtual void beginFrame(); virtual void endFrame() {}; /// Perform an integration step of duration 'timeStep'. - virtual bool proceedDeltaTime(double curTime,float timeStep); + virtual bool proceedDeltaTime(double curTime,float timeStep,float interval); + + virtual void debugDrawWorld(); // virtual bool proceedDeltaTimeOneStep(float timeStep); virtual void setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep){}; @@ -142,7 +149,10 @@ protected: const btVector3& angularMaxLimits,int flags ); + virtual void setConstraintParam(int constraintId,int param,float value,float value1); + + virtual float getConstraintParam(int constraintId,int param); virtual void removeConstraint(int constraintid); @@ -165,14 +175,15 @@ protected: btTypedConstraint* getConstraintById(int constraintId); virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ); + virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes, int occlusionRes); //Methods for gamelogic collision/physics callbacks virtual void addSensor(PHY_IPhysicsController* ctrl); virtual void removeSensor(PHY_IPhysicsController* ctrl); virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user); - virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl); - virtual void removeCollisionCallback(PHY_IPhysicsController* ctrl); + virtual bool requestCollisionCallback(PHY_IPhysicsController* ctrl); + virtual bool removeCollisionCallback(PHY_IPhysicsController* ctrl); //These two methods are used *solely* to create controllers for Near/Radar sensor! Don't use for anything else virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position); virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight); @@ -196,7 +207,14 @@ protected: void enableCcdPhysicsController(CcdPhysicsController* ctrl); + void refreshCcdPhysicsController(CcdPhysicsController* ctrl); + + void addCcdGraphicController(CcdGraphicController* ctrl); + + void removeCcdGraphicController(CcdGraphicController* ctrl); + btBroadphaseInterface* getBroadphase(); + btDbvtBroadphase* getCullingTree() { return m_cullingTree; } btDispatcher* getDispatcher(); @@ -257,7 +275,11 @@ protected: bool m_scalingPropagated; - +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:CcdPhysicsEnvironment"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //CCDPHYSICSENVIRONMENT diff --git a/source/gameengine/Physics/Bullet/Makefile b/source/gameengine/Physics/Bullet/Makefile index d5570e75833..433d1df3d2f 100644 --- a/source/gameengine/Physics/Bullet/Makefile +++ b/source/gameengine/Physics/Bullet/Makefile @@ -39,8 +39,17 @@ CPPFLAGS += -I$(NAN_BULLET2)/include CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_GLEW)/include +CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) CPPFLAGS += -I../../../kernel/gen_system CPPFLAGS += -I../../Physics/common CPPFLAGS += -I../../Physics/Dummy CPPFLAGS += -I../../Rasterizer +CPPFLAGS += -I../../Ketsji +CPPFLAGS += -I../../Expressions +CPPFLAGS += -I../../GameLogic +CPPFLAGS += -I../../SceneGraph +CPPFLAGS += -I../../../../source/blender/makesdna +CPPFLAGS += -I../../../../source/blender/blenkernel +CPPFLAGS += -I../../../../source/blender/blenlib diff --git a/source/gameengine/Physics/Bullet/SConscript b/source/gameengine/Physics/Bullet/SConscript index 0936d45197a..49f2af1b001 100644 --- a/source/gameengine/Physics/Bullet/SConscript +++ b/source/gameengine/Physics/Bullet/SConscript @@ -1,15 +1,24 @@ #!/usr/bin/python Import ('env') -sources = 'CcdPhysicsEnvironment.cpp CcdPhysicsController.cpp' +sources = 'CcdPhysicsEnvironment.cpp CcdPhysicsController.cpp CcdGraphicController.cpp' -incs = '. ../common #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/Rasterizer' +incs = '. ../common' +incs += ' #source/kernel/gen_system' +incs += ' #intern/string' +incs += ' #intern/moto/include' +incs += ' #extern/glew/include' +incs += ' #source/gameengine/Rasterizer' +incs += ' #source/gameengine/Ketsji' +incs += ' #source/gameengine/Expressions' +incs += ' #source/gameengine/GameLogic' +incs += ' #source/gameengine/SceneGraph' +incs += ' #source/blender/makesdna' +incs += ' #source/blender/blenkernel' +incs += ' #source/blender/blenlib' +incs += ' #intern/guardedalloc' incs += ' ' + env['BF_BULLET_INC'] +incs += ' ' + env['BF_PYTHON_INC'] -cflags = [] -if env['OURPLATFORM']=='win32-vc': - cflags.append('/GR') - cflags.append('/O2') - -env.BlenderLib ( 'bf_bullet', Split(sources), Split(incs), [], libtype=['game','player'], priority=[15,90] ) +env.BlenderLib ( 'bf_bullet', Split(sources), Split(incs), [], libtype=['core','player'], priority=[350,50], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/Physics/Dummy/CMakeLists.txt b/source/gameengine/Physics/Dummy/CMakeLists.txt index 4bd29e7779b..d613bf8fd14 100644 --- a/source/gameengine/Physics/Dummy/CMakeLists.txt +++ b/source/gameengine/Physics/Dummy/CMakeLists.txt @@ -27,8 +27,8 @@ SET(SRC DummyPhysicsEnvironment.cpp) SET(INC - . - ../common + . + ../common ) BLENDERLIB(bf_dummy "${SRC}" "${INC}") diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp index ba196b5cf55..e41574ff181 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp @@ -57,7 +57,7 @@ void DummyPhysicsEnvironment::endFrame() -bool DummyPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep) +bool DummyPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep,float interval) { //step physics simulation, typically perform diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h index a92b1e7f4a6..28440ebdad4 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h @@ -48,7 +48,7 @@ public: virtual void beginFrame(); virtual void endFrame(); // Perform an integration step of duration 'timeStep'. - virtual bool proceedDeltaTime(double curTime,float timeStep); + virtual bool proceedDeltaTime(double curTime,float timeStep,float interval); virtual void setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep); virtual float getFixedTimeStep(); @@ -70,6 +70,7 @@ public: } virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ); + virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes, int occlusionRes) { return false; } //gamelogic callbacks @@ -78,8 +79,8 @@ public: virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user) { } - virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl) {} - virtual void removeCollisionCallback(PHY_IPhysicsController* ctrl) {} + virtual bool requestCollisionCallback(PHY_IPhysicsController* ctrl) { return false; } + virtual bool removeCollisionCallback(PHY_IPhysicsController* ctrl) { return false;} virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position) {return 0;} virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight) { return 0;} @@ -87,6 +88,17 @@ public: { } + virtual float getConstraintParam(int constraintId,int param) + { + return 0.f; + } + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:DummyPhysicsEnvironment"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //_DUMMYPHYSICSENVIRONMENT diff --git a/source/gameengine/Physics/Dummy/Makefile b/source/gameengine/Physics/Dummy/Makefile index b0c1b855322..0e36266ae09 100644 --- a/source/gameengine/Physics/Dummy/Makefile +++ b/source/gameengine/Physics/Dummy/Makefile @@ -39,7 +39,7 @@ CPPFLAGS += -I$(OPENGL_HEADERS) CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) -CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO)/include -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I../../Physics/common CPPFLAGS += -I../../Physics/Dummy diff --git a/source/gameengine/Physics/Dummy/SConscript b/source/gameengine/Physics/Dummy/SConscript index e24b150531f..dc76e8046a0 100644 --- a/source/gameengine/Physics/Dummy/SConscript +++ b/source/gameengine/Physics/Dummy/SConscript @@ -5,4 +5,4 @@ sources = 'DummyPhysicsEnvironment.cpp' incs = '. ../common' -env.BlenderLib ( 'bf_dummy', Split(sources), Split(incs), [], libtype=['game','player'], priority=[10,100] ) +env.BlenderLib ( 'bf_dummy', Split(sources), Split(incs), [], libtype=['core','player'], priority=[350,60] ) diff --git a/source/gameengine/Physics/Makefile b/source/gameengine/Physics/Makefile index b192e497f35..da0d4cafd2e 100644 --- a/source/gameengine/Physics/Makefile +++ b/source/gameengine/Physics/Makefile @@ -32,7 +32,6 @@ include nan_definitions.mk SOURCEDIR = source/gameengine/Physics DIR = $(OCGDIR)/gameengine/blphys -DIRS = common Sumo Dummy Bullet -#DIRS += BlOde +DIRS = common Dummy Bullet include nan_subdirs.mk diff --git a/source/gameengine/Physics/Sumo/CMakeLists.txt b/source/gameengine/Physics/Sumo/CMakeLists.txt deleted file mode 100644 index c57a4af6706..00000000000 --- a/source/gameengine/Physics/Sumo/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -# $Id$ -# ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# The Original Code is Copyright (C) 2006, Blender Foundation -# All rights reserved. -# -# The Original Code is: all of this file. -# -# Contributor(s): Jacques Beaurain. -# -# ***** END GPL LICENSE BLOCK ***** - -SET(SRC - SumoPHYCallbackBridge.cpp - SumoPhysicsController.cpp - SumoPhysicsEnvironment.cpp - Fuzzics/src/SM_FhObject.cpp - Fuzzics/src/SM_Object.cpp - Fuzzics/src/SM_Scene.cpp - Fuzzics/src/SM_MotionState.cpp -) - -SET(INC - . - ../common - Fuzzics/include - ../../../../intern/moto/include - ../../../../extern/solid -) - -BLENDERLIB(bf_sumo "${SRC}" "${INC}") -#env.BlenderLib ( 'bf_sumo', sources, incs, [], libtype=['game2','player'], priority=[30, 70] , compileflags=cflags) diff --git a/source/gameengine/Physics/Sumo/Fuzzics/Makefile b/source/gameengine/Physics/Sumo/Fuzzics/Makefile deleted file mode 100644 index 5ed2c31a1d0..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# -# $Id$ -# -# ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** -# -# Bounces make to subdirectories. - -SOURCEDIR = source/gameengine/Physics/Sumo/Fuzzics -DIRS = src - -include nan_subdirs.mk diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Callback.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Callback.h deleted file mode 100644 index 42b5ab48ab6..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Callback.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef SM_CALLBACK_H -#define SM_CALLBACK_H - -class SM_Callback { -public: - virtual void do_me() = 0; - virtual ~SM_Callback() {} -}; - -#endif - diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_ClientObjectInfo.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_ClientObjectInfo.h deleted file mode 100644 index 6749e7957ec..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_ClientObjectInfo.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __SM_CLIENTOBJECT_INFO_H -#define __SM_CLIENTOBJECT_INFO_H - -/** - * Client Type and Additional Info. This structure can be use instead of a bare void* pointer, for safeness, and additional info for callbacks - */ - -struct SM_ClientObjectInfo -{ - int m_type; - void* m_clientobject1; - void* m_auxilary_info; -}; - -#endif //__SM_CLIENTOBJECT_INFO_H - diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Debug.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Debug.h deleted file mode 100644 index 48d5906e53d..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Debug.h +++ /dev/null @@ -1,26 +0,0 @@ - - -#ifndef __SM_DEBUG_H__ -#define __SM_DEBUG_H__ - -/* Comment this to disable all SUMO debugging printfs */ - -#define SM_DEBUG - -#ifdef SM_DEBUG - -#include <stdio.h> - -/* Uncomment this to printf all ray casts */ -//#define SM_DEBUG_RAYCAST - -/* Uncomment this to printf collision callbacks */ -//#define SM_DEBUG_BOING - -/* Uncomment this to printf Xform matrix calculations */ -//#define SM_DEBUG_XFORM - -#endif /* SM_DEBUG */ - -#endif /* __SM_DEBUG_H__ */ - diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_MotionState.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_MotionState.h deleted file mode 100644 index fdc45af5225..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_MotionState.h +++ /dev/null @@ -1,77 +0,0 @@ -/** - * $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ -#ifndef SM_MOTIONSTATE_H -#define SM_MOTIONSTATE_H - -#include "MT_Transform.h" - -class SM_MotionState { -public: - SM_MotionState() : - m_time(0.0), - m_pos(0.0, 0.0, 0.0), - m_orn(0.0, 0.0, 0.0, 1.0), - m_lin_vel(0.0, 0.0, 0.0), - m_ang_vel(0.0, 0.0, 0.0) - {} - - void setPosition(const MT_Point3& pos) { m_pos = pos; } - void setOrientation(const MT_Quaternion& orn) { m_orn = orn; } - void setLinearVelocity(const MT_Vector3& lin_vel) { m_lin_vel = lin_vel; } - void setAngularVelocity(const MT_Vector3& ang_vel) { m_ang_vel = ang_vel; } - void setTime(MT_Scalar time) { m_time = time; } - - const MT_Point3& getPosition() const { return m_pos; } - const MT_Quaternion& getOrientation() const { return m_orn; } - const MT_Vector3& getLinearVelocity() const { return m_lin_vel; } - const MT_Vector3& getAngularVelocity() const { return m_ang_vel; } - - MT_Scalar getTime() const { return m_time; } - - void integrateMidpoint(MT_Scalar timeStep, const SM_MotionState &prev_state, const MT_Vector3 &velocity, const MT_Quaternion& ang_vel); - void integrateBackward(MT_Scalar timeStep, const MT_Vector3 &velocity, const MT_Quaternion& ang_vel); - void integrateForward(MT_Scalar timeStep, const SM_MotionState &prev_state); - - void lerp(const SM_MotionState &prev, const SM_MotionState &next); - void lerp(MT_Scalar t, const SM_MotionState &other); - - virtual MT_Transform getTransform() const { - return MT_Transform(m_pos, m_orn); - } - -protected: - MT_Scalar m_time; - MT_Point3 m_pos; - MT_Quaternion m_orn; - MT_Vector3 m_lin_vel; - MT_Vector3 m_ang_vel; -}; - -#endif - diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Object.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Object.h deleted file mode 100644 index 2d748a0f251..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Object.h +++ /dev/null @@ -1,393 +0,0 @@ -/** - * $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ -#ifndef SM_OBJECT_H -#define SM_OBJECT_H - -#include <vector> - -#include <SOLID/SOLID.h> - -#include "SM_Callback.h" -#include "SM_MotionState.h" -#include <stdio.h> - -class SM_FhObject; - -/** Properties of dynamic objects */ -struct SM_ShapeProps { - MT_Scalar m_mass; ///< Total mass - MT_Scalar m_radius; ///< Bound sphere size - MT_Vector3 m_inertia; ///< Inertia, should be a tensor some time - MT_Scalar m_lin_drag; ///< Linear drag (air, water) 0 = concrete, 1 = vacuum - MT_Scalar m_ang_drag; ///< Angular drag - MT_Scalar m_friction_scaling[3]; ///< Scaling for anisotropic friction. Component in range [0, 1] - bool m_do_anisotropic; ///< Should I do anisotropic friction? - bool m_do_fh; ///< Should the object have a linear Fh spring? - bool m_do_rot_fh; ///< Should the object have an angular Fh spring? -}; - - -/** Properties of collidable objects (non-ghost objects) */ -struct SM_MaterialProps { - MT_Scalar m_restitution; ///< restitution of energy after a collision 0 = inelastic, 1 = elastic - MT_Scalar m_friction; ///< Coulomb friction (= ratio between the normal en maximum friction force) - MT_Scalar m_fh_spring; ///< Spring constant (both linear and angular) - MT_Scalar m_fh_damping; ///< Damping factor (linear and angular) in range [0, 1] - MT_Scalar m_fh_distance; ///< The range above the surface where Fh is active. - bool m_fh_normal; ///< Should the object slide off slopes? -}; - -class SM_ClientObject -{ -public: - SM_ClientObject() {} - virtual ~SM_ClientObject() {} - - virtual bool hasCollisionCallback() = 0; -}; - -/** - * SM_Object is an internal part of the Sumo physics engine. - * - * It encapsulates an object in the physics scene, and is responsible - * for calculating the collision response of objects. - */ -class SM_Object -{ -public: - SM_Object() ; - SM_Object( - DT_ShapeHandle shape, - const SM_MaterialProps *materialProps, - const SM_ShapeProps *shapeProps, - SM_Object *dynamicParent - ); - virtual ~SM_Object(); - - bool isDynamic() const; - - /* nzc experimental. There seem to be two places where kinematics - * are evaluated: proceedKinematic (called from SM_Scene) and - * proceed() in this object. I'll just try and bunge these out for - * now. */ - - void suspend(void); - void resume(void); - - void suspendDynamics(); - - void restoreDynamics(); - - bool isGhost() const; - - void suspendMaterial(); - - void restoreMaterial(); - - SM_FhObject *getFhObject() const; - - void registerCallback(SM_Callback& callback); - - void calcXform(); - void notifyClient(); - void updateInvInertiaTensor(); - - - // Save the current state information for use in the - // velocity computation in the next frame. - - void proceedKinematic(MT_Scalar timeStep); - - void saveReactionForce(MT_Scalar timeStep) ; - - void clearForce() ; - - void clearMomentum() ; - - void setMargin(MT_Scalar margin) ; - - MT_Scalar getMargin() const ; - - const SM_MaterialProps *getMaterialProps() const ; - - const SM_ShapeProps *getShapeProps() const ; - - void setPosition(const MT_Point3& pos); - void setOrientation(const MT_Quaternion& orn); - void setScaling(const MT_Vector3& scaling); - - /** - * set an external velocity. This velocity complements - * the physics velocity. So setting it does not override the - * physics velocity. It is your responsibility to clear - * this external velocity. This velocity is not subject to - * friction or damping. - */ - void setExternalLinearVelocity(const MT_Vector3& lin_vel) ; - void addExternalLinearVelocity(const MT_Vector3& lin_vel) ; - - /** Override the physics velocity */ - void addLinearVelocity(const MT_Vector3& lin_vel); - void setLinearVelocity(const MT_Vector3& lin_vel); - - /** - * Set an external angular velocity. This velocity complemetns - * the physics angular velocity so does not override it. It is - * your responsibility to clear this velocity. This velocity - * is not subject to friction or damping. - */ - void setExternalAngularVelocity(const MT_Vector3& ang_vel) ; - void addExternalAngularVelocity(const MT_Vector3& ang_vel); - - /** Override the physics angular velocity */ - void addAngularVelocity(const MT_Vector3& ang_vel); - void setAngularVelocity(const MT_Vector3& ang_vel); - - /** Clear the external velocities */ - void clearCombinedVelocities(); - - /** - * Tell the physics system to combine the external velocity - * with the physics velocity. - */ - void resolveCombinedVelocities( - const MT_Vector3 & lin_vel, - const MT_Vector3 & ang_vel - ) ; - - - - MT_Scalar getInvMass() const; - - const MT_Vector3& getInvInertia() const ; - - const MT_Matrix3x3& getInvInertiaTensor() const; - - void applyForceField(const MT_Vector3& accel) ; - - void applyCenterForce(const MT_Vector3& force) ; - - void applyTorque(const MT_Vector3& torque) ; - - /** - * Apply an impulse to the object. The impulse will be split into - * angular and linear components. - * @param attach point to apply the impulse to (in world coordinates) - */ - void applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse) ; - - /** - * Applies an impulse through the center of this object. (ie the angular - * velocity will not change. - */ - void applyCenterImpulse(const MT_Vector3& impulse); - /** - * Applies an angular impulse. - */ - void applyAngularImpulse(const MT_Vector3& impulse); - - MT_Point3 getWorldCoord(const MT_Point3& local) const; - MT_Point3 getLocalCoord(const MT_Point3& world) const; - - MT_Vector3 getVelocity(const MT_Point3& local) const; - - - const MT_Vector3& getReactionForce() const ; - - void getMatrix(double *m) const ; - - const double *getMatrix() const ; - - // Still need this??? - const MT_Transform& getScaledTransform() const; - - DT_ObjectHandle getObjectHandle() const ; - DT_ShapeHandle getShapeHandle() const ; - - SM_Object *getDynamicParent() ; - - void integrateForces(MT_Scalar timeStep); - void integrateMomentum(MT_Scalar timeSteo); - - void setRigidBody(bool is_rigid_body) ; - - bool isRigidBody() const ; - - // This is the callback for handling collisions of dynamic objects - static - DT_Bool - boing( - void *client_data, - void *object1, - void *object2, - const DT_CollData *coll_data - ); - - static - DT_Bool - fix( - void *client_data, - void *object1, - void *object2, - const DT_CollData *coll_data - ); - - - SM_ClientObject *getClientObject() { return m_client_object; } - void setClientObject(SM_ClientObject *client_object) { m_client_object = client_object; } - void setPhysicsClientObject(void* physicsClientObject) - { - m_physicsClientObject = physicsClientObject; - } - void* getPhysicsClientObject() { - return m_physicsClientObject; - } - void relax(); - - SM_MotionState &getCurrentFrame(); - SM_MotionState &getPreviousFrame(); - SM_MotionState &getNextFrame(); - - const SM_MotionState &getCurrentFrame() const; - const SM_MotionState &getPreviousFrame() const; - const SM_MotionState &getNextFrame() const; - - // Motion state functions - const MT_Point3& getPosition() const; - const MT_Quaternion& getOrientation() const; - const MT_Vector3& getLinearVelocity() const; - const MT_Vector3& getAngularVelocity() const; - - MT_Scalar getTime() const; - - void setTime(MT_Scalar time); - - void interpolate(MT_Scalar timeStep); - void endFrame(); - -private: - friend class Contact; - // Tweak parameters - static MT_Scalar ImpulseThreshold; - - // return the actual linear_velocity of this object this - // is the addition of m_combined_lin_vel and m_lin_vel. - - const - MT_Vector3 - actualLinVelocity( - ) const ; - - const - MT_Vector3 - actualAngVelocity( - ) const ; - - void dynamicCollision(const MT_Point3 &local2, - const MT_Vector3 &normal, - MT_Scalar dist, - const MT_Vector3 &rel_vel, - MT_Scalar restitution, - MT_Scalar friction_factor, - MT_Scalar invMass - ); - - typedef std::vector<SM_Callback *> T_CallbackList; - - - T_CallbackList m_callbackList; // Each object can have multiple callbacks from the client (=game engine) - SM_Object *m_dynamicParent; // Collisions between parent and children are ignored - - // as the collision callback now has only information - // on an SM_Object, there must be a way that the SM_Object client - // can identify it's clientdata after a collision - SM_ClientObject *m_client_object; - - void* m_physicsClientObject; - - DT_ShapeHandle m_shape; // Shape for collision detection - - // Material and shape properties are not owned by this class. - - const SM_MaterialProps *m_materialProps; - const SM_MaterialProps *m_materialPropsBackup; // Backup in case the object temporarily becomes a ghost. - const SM_ShapeProps *m_shapeProps; - const SM_ShapeProps *m_shapePropsBackup; // Backup in case the object's dynamics is temporarily suspended - DT_ObjectHandle m_object; // A handle to the corresponding object in SOLID. - MT_Scalar m_margin; // Offset for the object's shape (also for collision detection) - MT_Vector3 m_scaling; // Non-uniform scaling of the object's shape - - double m_ogl_matrix[16]; // An OpenGL-type 4x4 matrix - MT_Transform m_xform; // The object's local coordinate system - MT_Transform m_prev_xform; // The object's local coordinate system in the previous frame - SM_MotionState m_prev_state; // The object's motion state in the previous frame - MT_Scalar m_timeStep; // The duration of the last frame - - MT_Vector3 m_reaction_impulse; // The accumulated impulse resulting from collisions - MT_Vector3 m_reaction_force; // The reaction force derived from the reaction impulse - - MT_Vector3 m_lin_mom; // Linear momentum (linear velocity times mass) - MT_Vector3 m_ang_mom; // Angular momentum (angualr velocity times inertia) - MT_Vector3 m_force; // Force on center of mass (afffects linear momentum) - MT_Vector3 m_torque; // Torque around center of mass (affects angular momentum) - - SM_MotionState m_frames[3]; - - MT_Vector3 m_error; // Error in position:- amount object must be moved to prevent intersection with scene - - // Here are the values of externally set linear and angular - // velocity. These are updated from the outside - // (actuators and python) each frame and combined with the - // physics values. At the end of each frame (at the end of a - // call to proceed) they are set to zero. This allows the - // outside world to contribute to the velocity of an object - // but still have it react to physics. - - MT_Vector3 m_combined_lin_vel; - MT_Vector3 m_combined_ang_vel; - - // The force and torque are the accumulated forces and torques applied by the client (game logic, python). - - SM_FhObject *m_fh_object; // The ray object used for Fh - bool m_suspended; // Is this object frozen? - - // Mass properties - MT_Scalar m_inv_mass; // 1/mass - MT_Vector3 m_inv_inertia; // [1/inertia_x, 1/inertia_y, 1/inertia_z] - MT_Matrix3x3 m_inv_inertia_tensor; // Inverse Inertia Tensor - - bool m_kinematic; // Have I been displaced (translated, rotated, scaled) in this frame? - bool m_prev_kinematic; // Have I been displaced (translated, rotated, scaled) in the previous frame? - bool m_is_rigid_body; // Should friction give me a change in angular momentum? - int m_static; // temporarily static. - -}; - -#endif - diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Props.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Props.h deleted file mode 100644 index 81b4cb55b45..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Props.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ -#ifndef SM_PROPSH -#define SM_PROPSH - -#include <MT_Scalar.h> - -// Properties of dynamic objects -struct SM_ShapeProps { - MT_Scalar m_mass; // Total mass - MT_Scalar m_inertia; // Inertia, should be a tensor some time - MT_Scalar m_lin_drag; // Linear drag (air, water) 0 = concrete, 1 = vacuum - MT_Scalar m_ang_drag; // Angular drag - MT_Scalar m_friction_scaling[3]; // Scaling for anisotropic friction. Component in range [0, 1] - bool m_do_anisotropic; // Should I do anisotropic friction? - bool m_do_fh; // Should the object have a linear Fh spring? - bool m_do_rot_fh; // Should the object have an angular Fh spring? -}; - - -// Properties of collidable objects (non-ghost objects) -struct SM_MaterialProps { - MT_Scalar m_restitution; // restitution of energie after a collision 0 = inelastic, 1 = elastic - MT_Scalar m_friction; // Coulomb friction (= ratio between the normal en maximum friction force) - MT_Scalar m_fh_spring; // Spring constant (both linear and angular) - MT_Scalar m_fh_damping; // Damping factor (linear and angular) in range [0, 1] - MT_Scalar m_fh_distance; // The range above the surface where Fh is active. - bool m_fh_normal; // Should the object slide off slopes? -}; - -#endif //SM_PROPSH - diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Scene.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Scene.h deleted file mode 100644 index 2326bdee523..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Scene.h +++ /dev/null @@ -1,172 +0,0 @@ -/** - * $Id$ - * Copyright (C) 2001 NaN Technologies B.V. - * The physics scene. - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ -#ifndef SM_SCENE_H -#define SM_SCENE_H - -#ifdef WIN32 -#pragma warning (disable : 4786) -#endif - -#include <vector> -#include <set> -#include <utility> //needed for pair - -#include <SOLID/SOLID.h> - -#include "MT_Vector3.h" -#include "MT_Point3.h" - -#include "SM_Object.h" - -typedef enum -{ - FH_RESPONSE, - SENSOR_RESPONSE, /* Touch Sensors */ - CAMERA_RESPONSE, /* Visibility Culling */ - OBJECT_RESPONSE, /* Object Dynamic Geometry Response */ - STATIC_RESPONSE, /* Static Geometry Response */ - - NUM_RESPONSE -}; - -class SM_Scene { -public: - SM_Scene(); - - ~SM_Scene(); - - DT_RespTableHandle getRespTableHandle() const { - return m_respTable; - } - - const MT_Vector3& getForceField() const { - return m_forceField; - } - - MT_Vector3& getForceField() { - return m_forceField; - } - - void setForceField(const MT_Vector3& forceField) { - m_forceField = forceField; - } - - void addTouchCallback(int response_class, DT_ResponseCallback callback, void *user); - - void addSensor(SM_Object& object); - void add(SM_Object& object); - void remove(SM_Object& object); - - void notifyCollision(SM_Object *obj1, SM_Object *obj2); - - void setSecondaryRespTable(DT_RespTableHandle secondaryRespTable); - DT_RespTableHandle getSecondaryRespTable() { return m_secondaryRespTable; } - - void requestCollisionCallback(SM_Object &object); - - void beginFrame(); - void endFrame(); - - // Perform an integration step of duration 'timeStep'. - // 'subSampling' is the maximum duration of a substep, i.e., - // The maximum time interval between two collision checks. - // 'subSampling' can be used to control aliasing effects - // (fast moving objects traversing through walls and such). - bool proceed(MT_Scalar curtime, MT_Scalar ticrate); - void proceed(MT_Scalar subStep); - - /** - * Test whether any objects lie on the line defined by from and - * to. The search returns the first such bject starting at from, - * or NULL if there was none. - * @returns A reference to the object, or NULL if there was none. - * @param ignore_client Do not look for collisions with this - * object. This can be useful to avoid self-hits if - * starting from the location of an object. - * @param from The start point, in world coordinates, of the search. - * @param to The end point, in world coordinates, of the search. - * @param result A store to return the point where intersection - * took place (if there was an intersection). - * @param normal A store to return the normal of the hit object on - * the location of the intersection, if it took place. - */ - SM_Object *rayTest(void *ignore_client, - const MT_Point3& from, const MT_Point3& to, - MT_Point3& result, MT_Vector3& normal) const; - -private: - - // Clear the user set velocities. - void clearObjectCombinedVelocities(); - // This is the callback for handling collisions of dynamic objects - static - DT_Bool - boing( - void *client_data, - void *object1, - void *object2, - const DT_CollData *coll_data - ); - - /** internal type */ - typedef std::vector<SM_Object *> T_ObjectList; - - /** Handle to the scene in SOLID */ - DT_SceneHandle m_scene; - /** Following response table contains the callbacks for the dynmics */ - DT_RespTableHandle m_respTable; - DT_ResponseClass m_ResponseClass[NUM_RESPONSE]; - /** - * Following response table contains callbacks for the client (= - * game engine) */ - DT_RespTableHandle m_secondaryRespTable; // Handle - DT_ResponseClass m_secondaryResponseClass[NUM_RESPONSE]; - - /** - * Following resposne table contains callbacks for fixing the simulation - * ie making sure colliding objects do not intersect. - */ - DT_RespTableHandle m_fixRespTable; - DT_ResponseClass m_fixResponseClass[NUM_RESPONSE]; - - /** The acceleration from the force field */ - MT_Vector3 m_forceField; - - /** - * The list of objects that receive motion updates and do - * collision tests. */ - T_ObjectList m_objectList; - - unsigned int m_frames; -}; - -#endif - diff --git a/source/gameengine/Physics/Sumo/Fuzzics/sample/Makefile b/source/gameengine/Physics/Sumo/Fuzzics/sample/Makefile deleted file mode 100644 index 672dff39028..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/sample/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# -# $Id$ -# Copyright (C) 2001 NaN Technologies B.V. - -DIR = $(OCGDIR)/sumo -ALLTARGETS = $(OBJS) $(DIR)/$(DEBUG_DIR)particle $(DIR)/$(DEBUG_DIR)particle0 - -include nan_compile.mk - -CPPFLAGS = -I../../include -I../include -I$(NAN_MOTO)/include -CPPFLAGS += -I$(OPENGL_HEADERS) - -clean:: - @$(RM) $(DIR)/particle $(DIR)/particle0 - @$(RM) $(DIR)/debug/particle $(DIR)/debug/particle0 - -LDFLAGS = -L$(DIR) -L/usr/X11R6/lib -OGL_LDLIBS = -lglut -lGLU -lGL -pthread -LDLIBS = -lfuzzics -lsolid $(NAN_MOTO)/lib/libmoto.a $(OGL_LDLIBS) - -$(DIR)/$(DEBUG_DIR)particle: particle.o $(DIR)/$(DEBUG_DIR)libfuzzics.a $(DIR)/$(DEBUG_DIR)libsolid.a - $(CCC) $(CCFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ $(LDLIBS) - -$(DIR)/$(DEBUG_DIR)particle0: particle0.o $(DIR)/$(DEBUG_DIR)libfuzzics.a $(DIR)/$(DEBUG_DIR)libsolid.a - $(CCC) $(CCFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ $(LDLIBS) diff --git a/source/gameengine/Physics/Sumo/Fuzzics/sample/particle.cpp b/source/gameengine/Physics/Sumo/Fuzzics/sample/particle.cpp deleted file mode 100644 index d7aca326b42..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/sample/particle.cpp +++ /dev/null @@ -1,709 +0,0 @@ -//#define FAKE_IT -#define USE_COMPLEX -#define QUADS - -#include <algorithm> -#include <new> -#include <GL/glut.h> - -#include "MT_MinMax.h" -#include "MT_Point3.h" -#include "MT_Vector3.h" -#include "MT_Quaternion.h" -#include "MT_Matrix3x3.h" -#include "MT_Transform.h" - -#include "SM_Object.h" -#include "SM_FhObject.h" -#include "SM_Scene.h" - -#include <SOLID/SOLID.h> - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -const MT_Scalar bowl_curv = 0.10; -const MT_Scalar timeStep = 0.02; -const MT_Scalar ground_margin = 0.0; -const MT_Scalar sphere_radius = 0.5; - -const MT_Vector3 gravity(0, -9.8, 0); - -static MT_Scalar DISTANCE = 5; - -static MT_Scalar ele = 0, azi = 0; -static MT_Point3 eye(0, 0, DISTANCE); -static MT_Point3 center(0, 0, 0); - -inline double irnd() { return 2 * MT_random() - 1; } - -static const double SCALE_BOTTOM = 0.5; -static const double SCALE_FACTOR = 2.0; - -SM_ShapeProps g_shapeProps = { - 1.0, // mass - 1.0, // inertia - 0.1, // linear drag - 0.1, // angular drag - { 1.0, 0.0, 0.0 }, // anisotropic friction - false, // do anisotropic friction? - true, // do fh? - true // do rot fh? -}; - -SM_MaterialProps g_materialProps = { - 0.7, // restitution - 0.0, // friction - 10.0, // Fh spring constant - 1.0, // Fh damping - 0.5, // Fh distance - true // Fh leveling -}; - - -void toggleIdle(); - - -void newRandom(); - -void coordSystem() { - glDisable(GL_LIGHTING); - glBegin(GL_LINES); - glColor3f(1, 0, 0); - glVertex3d(0, 0, 0); - glVertex3d(10, 0, 0); - glColor3f(0, 1, 0); - glVertex3d(0, 0, 0); - glVertex3d(0, 10, 0); - glColor3f(0, 0, 1); - glVertex3d(0, 0, 0); - glVertex3d(0, 0, 10); - glEnd(); - glEnable(GL_LIGHTING); -} - - -void display_bbox(const MT_Point3& min, const MT_Point3& max) { - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glColor3f(0, 1, 1); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glBegin(GL_QUAD_STRIP); - glVertex3d(min[0], min[1], min[2]); - glVertex3d(min[0], min[1], max[2]); - glVertex3d(max[0], min[1], min[2]); - glVertex3d(max[0], min[1], max[2]); - glVertex3d(max[0], max[1], min[2]); - glVertex3d(max[0], max[1], max[2]); - glVertex3d(min[0], max[1], min[2]); - glVertex3d(min[0], max[1], max[2]); - glVertex3d(min[0], min[1], min[2]); - glVertex3d(min[0], min[1], max[2]); - glEnd(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glEnable(GL_LIGHTING); - glEnable(GL_DEPTH_TEST); -} - - - - -class GLShape { -public: - virtual void paint(GLdouble *m) const = 0; -}; - - -class GLSphere : public GLShape { - MT_Scalar radius; -public: - GLSphere(MT_Scalar r) : radius(r) {} - - void paint(GLdouble *m) const { - glPushMatrix(); - glLoadMatrixd(m); - coordSystem(); - glutSolidSphere(radius, 20, 20); - glPopMatrix(); - } -}; - - -class GLBox : public GLShape { - MT_Vector3 extent; -public: - GLBox(MT_Scalar x, MT_Scalar y, MT_Scalar z) : - extent(x, y, z) {} - - void paint(GLdouble *m) const { - glPushMatrix(); - glLoadMatrixd(m); - coordSystem(); - glPushMatrix(); - glScaled(extent[0], extent[1], extent[2]); - glutSolidCube(1.0); - glPopMatrix(); - glPopMatrix(); - } -}; - - -class GLCone : public GLShape { - MT_Scalar bottomRadius; - MT_Scalar height; - mutable GLuint displayList; - -public: - GLCone(MT_Scalar r, MT_Scalar h) : - bottomRadius(r), - height(h), - displayList(0) {} - - void paint(GLdouble *m) const { - glPushMatrix(); - glLoadMatrixd(m); - coordSystem(); - if (displayList) glCallList(displayList); - else { - GLUquadricObj *quadObj = gluNewQuadric(); - displayList = glGenLists(1); - glNewList(displayList, GL_COMPILE_AND_EXECUTE); - glPushMatrix(); - glRotatef(-90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, 0.0, -1.0); - gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL); - gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH); - gluCylinder(quadObj, bottomRadius, 0, height, 15, 10); - glPopMatrix(); - glEndList(); - } - glPopMatrix(); - } -}; - -class GLCylinder : public GLShape { - MT_Scalar radius; - MT_Scalar height; - mutable GLuint displayList; - -public: - GLCylinder(MT_Scalar r, MT_Scalar h) : - radius(r), - height(h), - displayList(0) {} - - void paint(GLdouble *m) const { - glPushMatrix(); - glLoadMatrixd(m); - coordSystem(); - if (displayList) glCallList(displayList); - else { - GLUquadricObj *quadObj = gluNewQuadric(); - displayList = glGenLists(1); - glNewList(displayList, GL_COMPILE_AND_EXECUTE); - glPushMatrix(); - glRotatef(-90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, 0.0, -1.0); - gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL); - gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH); - gluCylinder(quadObj, radius, radius, height, 15, 10); - glPopMatrix (); - glEndList(); - } - glPopMatrix(); - } -}; - -class Object; - -class Callback : public SM_Callback { -public: - Callback(Object& object) : m_object(object) {} - - virtual void do_me(); - -private: - Object& m_object; -}; - - -class Object { -public: - Object(GLShape *gl_shape, SM_Object& object) : - m_gl_shape(gl_shape), - m_object(object), - m_callback(*this) - { - m_object.registerCallback(m_callback); - } - - ~Object() {} - - void paint() { - if (m_gl_shape) { - m_gl_shape->paint(m); - // display_bbox(m_bbox.lower(), m_bbox.upper()); - } - } - - void print_reaction_force() const { - std::cout << m_object.getReactionForce() << std::endl; - } - - MT_Vector3 getAhead() { - return MT_Vector3(&m[4]); - } - - MT_Vector3 getUp() { - return MT_Vector3(&m[8]); - } - - void clearMomentum() { - m_object.clearMomentum(); - } - - void setMargin(MT_Scalar margin) { - m_object.setMargin(margin); - } - - void setScaling(const MT_Vector3& scaling) { - m_object.setScaling(scaling); - } - - const MT_Point3& getPosition() { - return m_object.getPosition(); - } - - void setPosition(const MT_Point3& pos) { - m_object.setPosition(pos); - } - - void setOrientation(const MT_Quaternion& orn) { - m_object.setOrientation(orn); - } - - void applyCenterForce(const MT_Vector3& force) { - m_object.applyCenterForce(force); - } - - void applyTorque(const MT_Vector3& torque) { - m_object.applyTorque(torque); - } - - MT_Point3 getWorldCoord(const MT_Point3& local) const { - return m_object.getWorldCoord(local); - } - - MT_Vector3 getLinearVelocity() const { - return m_object.getLinearVelocity(); - } - - MT_Vector3 getAngularVelocity() const { - return m_object.getAngularVelocity(); - } - - void setMatrix() { - m_object.calcXform(); - m_object.getMatrix(m); - } - - const double *getMatrix() { - m_object.calcXform(); - return m_object.getMatrix(); - } - -private: - GLShape *m_gl_shape; - SM_Object& m_object; - DT_Scalar m[16]; - Callback m_callback; -}; - - - -const MT_Scalar SPACE_SIZE = 2; - -static GLSphere gl_sphere(sphere_radius); -static GLBox gl_ground(50.0, 0.0, 50.0); - - - -#ifdef USE_COMPLEX - -const int GRID_SCALE = 10; -const MT_Scalar GRID_UNIT = 25.0 / GRID_SCALE; - -DT_ShapeHandle createComplex() { - DT_ShapeHandle shape = DT_NewComplexShape(); - for (int i0 = -GRID_SCALE; i0 != GRID_SCALE; ++i0) { - for (int j0 = -GRID_SCALE; j0 != GRID_SCALE; ++j0) { - int i1 = i0 + 1; - int j1 = j0 + 1; -#ifdef QUADS - DT_Begin(); - DT_Vertex(GRID_UNIT * i0, bowl_curv * i0*i0, GRID_UNIT * j0); - DT_Vertex(GRID_UNIT * i0, bowl_curv * i0*i0, GRID_UNIT * j1); - DT_Vertex(GRID_UNIT * i1, bowl_curv * i1*i1, GRID_UNIT * j1); - DT_Vertex(GRID_UNIT * i1, bowl_curv * i1*i1, GRID_UNIT * j0); - DT_End(); -#else - DT_Begin(); - DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j0); - DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j1); - DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j1); - DT_End(); - - DT_Begin(); - DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j1); - DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j1); - DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j0); - DT_End(); -#endif - - } - } - DT_EndComplexShape(); - return shape; -} - - -static DT_ShapeHandle ground_shape = createComplex(); - -#else - -static DT_ShapeHandle ground_shape = DT_Box(50, 0, 50); - -#endif - -static SM_Object sm_ground(ground_shape, &g_materialProps, 0, 0); -static Object ground(&gl_ground, sm_ground); - -static SM_Object sm_sphere(DT_Sphere(0.0), &g_materialProps, &g_shapeProps, 0); -static Object object(&gl_sphere, sm_sphere); - - -static SM_Scene g_scene; - - -bool g_hit = false; -MT_Point3 g_spot; -MT_Vector3 g_normal; - - -void Callback::do_me() -{ - m_object.setMatrix(); - m_object.print_reaction_force(); -} - -void myinit(void) { - - GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; - GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; - GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; - - /* light_position is NOT default value */ - GLfloat light_position0[] = { 1.0, 1.0, 1.0, 0.0 }; - GLfloat light_position1[] = { -1.0, -1.0, -1.0, 0.0 }; - - glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT0, GL_POSITION, light_position0); - - glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT1, GL_POSITION, light_position1); - - - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); - - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - // glEnable(GL_CULL_FACE); - // glCullFace(GL_BACK); - - ground.setPosition(MT_Point3(0, -10, 0)); - ground.setOrientation(MT_Quaternion(0, 0, 0, 1)); - ground.setMatrix(); - center.setValue(0.0, 0.0, 0.0); - sm_ground.setMargin(ground_margin); - - g_scene.setForceField(gravity); - g_scene.add(sm_ground); - - object.setMargin(sphere_radius); - - g_scene.add(sm_sphere); - - - newRandom(); -} - - -//MT_Point3 cp1, cp2; -//bool intersection; - -void display(void) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - ground.paint(); - object.paint(); - - if (g_hit) { - glDisable(GL_LIGHTING); - glColor3f(1, 0, 0); - - glPointSize(5); - glBegin(GL_POINTS); - glVertex3d(g_spot[0], g_spot[1], g_spot[2]); - glEnd(); - glPointSize(1); - - glColor3f(1, 1, 0); - glBegin(GL_LINES); - glVertex3d(g_spot[0], g_spot[1], g_spot[2]); - glVertex3d(g_spot[0] + g_normal[0], - g_spot[1] + g_normal[1], - g_spot[2] + g_normal[2]); - glEnd(); - glEnable(GL_LIGHTING); - } - - - -#ifdef COLLISION - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glColor3f(1, 1, 0); - if (intersection) { - glPointSize(5); - glBegin(GL_POINTS); - glVertex3d(cp1[0], cp1[1], cp1[2]); - glEnd(); - glPointSize(1); - } - else { - glBegin(GL_LINES); - glVertex3d(cp1[0], cp1[1], cp1[2]); - glVertex3d(cp2[0], cp2[1], cp2[2]); - glEnd(); - } - glEnable(GL_LIGHTING); - glEnable(GL_DEPTH_TEST); -#endif - - glFlush(); - glutSwapBuffers(); -} - - - - - -void newRandom() { - object.setPosition(MT_Point3(0, 0, 0)); - object.setOrientation(MT_Quaternion::random()); - object.clearMomentum(); - object.setMatrix(); - - display(); -} - -void moveAndDisplay() { - g_scene.proceed(timeStep, 0.01); - - display(); - g_hit = false; -} - - -void turn_left() { - object.applyTorque(5.0 * object.getUp()); -} - -void turn_right() { - object.applyTorque(-5.0 * object.getUp()); -} - -void forward() { - object.applyCenterForce(10.0 * object.getAhead()); -} - -void backward() { - object.applyCenterForce(-10.0 * object.getAhead()); -} - -void jump() { - object.applyCenterForce(MT_Vector3(0.0, 200.0, 0.0)); -} - - -void toggleIdle() { - static bool idle = true; - if (idle) { - glutIdleFunc(moveAndDisplay); - idle = false; - } - else { - glutIdleFunc(NULL); - idle = true; - } -} - - -void setCamera() { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 200.0); - MT_Scalar rele = MT_radians(ele); - MT_Scalar razi = MT_radians(azi); - eye.setValue(DISTANCE * sin(razi) * cos(rele), - DISTANCE * sin(rele), - DISTANCE * cos(razi) * cos(rele)); - gluLookAt(eye[0], eye[1], eye[2], - center[0], center[1], center[2], - 0, 1, 0); - glMatrixMode(GL_MODELVIEW); - display(); -} - -const MT_Scalar STEPSIZE = 5; - -void stepLeft() { azi -= STEPSIZE; if (azi < 0) azi += 360; setCamera(); } -void stepRight() { azi += STEPSIZE; if (azi >= 360) azi -= 360; setCamera(); } -void stepFront() { ele += STEPSIZE; if (azi >= 360) azi -= 360; setCamera(); } -void stepBack() { ele -= STEPSIZE; if (azi < 0) azi += 360; setCamera(); } -void zoomIn() { DISTANCE -= 1; setCamera(); } -void zoomOut() { DISTANCE += 1; setCamera(); } - - -void myReshape(int w, int h) { - glViewport(0, 0, w, h); - setCamera(); -} - -void myKeyboard(unsigned char key, int x, int y) -{ - switch (key) - { - case 'w': forward(); break; - case 's': backward(); break; - case 'a': turn_left(); break; - case 'd': turn_right(); break; - case 'e': jump(); break; - case 'l' : stepLeft(); break; - case 'r' : stepRight(); break; - case 'f' : stepFront(); break; - case 'b' : stepBack(); break; - case 'z' : zoomIn(); break; - case 'x' : zoomOut(); break; - case 'i' : toggleIdle(); break; - case ' ' : newRandom(); break; - default: -// std::cout << "unused key : " << key << std::endl; - break; - } -} - -void mySpecial(int key, int x, int y) -{ - switch (key) - { - case GLUT_KEY_LEFT : stepLeft(); break; - case GLUT_KEY_RIGHT : stepRight(); break; - case GLUT_KEY_UP : stepFront(); break; - case GLUT_KEY_DOWN : stepBack(); break; - case GLUT_KEY_PAGE_UP : zoomIn(); break; - case GLUT_KEY_PAGE_DOWN : zoomOut(); break; - case GLUT_KEY_HOME : toggleIdle(); break; - default: -// std::cout << "unused (special) key : " << key << std::endl; - break; - } -} - -void goodbye( void) -{ - g_scene.remove(sm_ground); - g_scene.remove(sm_sphere); - - std::cout << "goodbye ..." << std::endl; - exit(0); -} - -void menu(int choice) -{ - - static int fullScreen = 0; - static int px, py, sx, sy; - - switch(choice) { - case 1: - if (fullScreen == 1) { - glutPositionWindow(px,py); - glutReshapeWindow(sx,sy); - glutChangeToMenuEntry(1,"Full Screen",1); - fullScreen = 0; - } else { - px=glutGet((GLenum)GLUT_WINDOW_X); - py=glutGet((GLenum)GLUT_WINDOW_Y); - sx=glutGet((GLenum)GLUT_WINDOW_WIDTH); - sy=glutGet((GLenum)GLUT_WINDOW_HEIGHT); - glutFullScreen(); - glutChangeToMenuEntry(1,"Close Full Screen",1); - fullScreen = 1; - } - break; - case 2: - toggleIdle(); - break; - case 3: - goodbye(); - break; - default: - break; - } -} - -void createMenu() -{ - glutCreateMenu(menu); - glutAddMenuEntry("Full Screen", 1); - glutAddMenuEntry("Toggle Idle (Start/Stop)", 2); - glutAddMenuEntry("Quit", 3); - glutAttachMenu(GLUT_RIGHT_BUTTON); -} - -int main(int argc, char **argv) { - glutInit(&argc, argv); - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); - glutInitWindowPosition(0, 0); - glutInitWindowSize(500, 500); - glutCreateWindow("Physics demo"); - - myinit(); - glutKeyboardFunc(myKeyboard); - glutSpecialFunc(mySpecial); - glutReshapeFunc(myReshape); - createMenu(); - glutIdleFunc(NULL); - - glutDisplayFunc(display); - glutMainLoop(); - return 0; -} - - - - - - - diff --git a/source/gameengine/Physics/Sumo/Fuzzics/sample/particle0.cpp b/source/gameengine/Physics/Sumo/Fuzzics/sample/particle0.cpp deleted file mode 100644 index cdf0a2d8f64..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/sample/particle0.cpp +++ /dev/null @@ -1,695 +0,0 @@ -//#define FAKE_IT -#define USE_COMPLEX -#define QUADS - -#include <algorithm> -#include <new> -#include <GL/glut.h> - -#include "MT_MinMax.h" -#include "MT_Point3.h" -#include "MT_Vector3.h" -#include "MT_Quaternion.h" -#include "MT_Matrix3x3.h" -#include "MT_Transform.h" - -#include "SM_Object.h" -#include "SM_Scene.h" - -#include "solid.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -const MT_Scalar bowl_curv = 0.10; -const MT_Scalar timeStep = 0.04; -const MT_Scalar ground_margin = 0.0; -const MT_Scalar sphere_radius = 0.5; - -const MT_Vector3 gravity(0, -9.8, 0); - -static MT_Scalar DISTANCE = 5; - -static MT_Scalar ele = 0, azi = 0; -static MT_Point3 eye(0, 0, DISTANCE); -static MT_Point3 center(0, 0, 0); - -inline double irnd() { return 2 * MT_random() - 1; } - -static const double SCALE_BOTTOM = 0.5; -static const double SCALE_FACTOR = 2.0; - -SM_ShapeProps g_shapeProps = { - 1.0, // mass - 1.0, // inertia - 0.9, // linear drag - 0.9 // angular drag -}; - -SM_MaterialProps g_materialProps = { - 0.7, // restitution - 0.0, // friction - 0.0, // spring constant - 0.0 // damping -}; - - -void toggleIdle(); - - -void newRandom(); - -void coordSystem() { - glDisable(GL_LIGHTING); - glBegin(GL_LINES); - glColor3f(1, 0, 0); - glVertex3d(0, 0, 0); - glVertex3d(10, 0, 0); - glColor3f(0, 1, 0); - glVertex3d(0, 0, 0); - glVertex3d(0, 10, 0); - glColor3f(0, 0, 1); - glVertex3d(0, 0, 0); - glVertex3d(0, 0, 10); - glEnd(); - glEnable(GL_LIGHTING); -} - - -void display_bbox(const MT_Point3& min, const MT_Point3& max) { - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glColor3f(0, 1, 1); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glBegin(GL_QUAD_STRIP); - glVertex3d(min[0], min[1], min[2]); - glVertex3d(min[0], min[1], max[2]); - glVertex3d(max[0], min[1], min[2]); - glVertex3d(max[0], min[1], max[2]); - glVertex3d(max[0], max[1], min[2]); - glVertex3d(max[0], max[1], max[2]); - glVertex3d(min[0], max[1], min[2]); - glVertex3d(min[0], max[1], max[2]); - glVertex3d(min[0], min[1], min[2]); - glVertex3d(min[0], min[1], max[2]); - glEnd(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glEnable(GL_LIGHTING); - glEnable(GL_DEPTH_TEST); -} - - - - -class GLShape { -public: - virtual void paint(GLdouble *m) const = 0; -}; - - -class GLSphere : public GLShape { - MT_Scalar radius; -public: - GLSphere(MT_Scalar r) : radius(r) {} - - void paint(GLdouble *m) const { - glPushMatrix(); - glLoadMatrixd(m); - coordSystem(); - glutSolidSphere(radius, 20, 20); - glPopMatrix(); - } -}; - - -class GLBox : public GLShape { - MT_Vector3 extent; -public: - GLBox(MT_Scalar x, MT_Scalar y, MT_Scalar z) : - extent(x, y, z) {} - - void paint(GLdouble *m) const { - glPushMatrix(); - glLoadMatrixd(m); - coordSystem(); - glPushMatrix(); - glScaled(extent[0], extent[1], extent[2]); - glutSolidCube(1.0); - glPopMatrix(); - glPopMatrix(); - } -}; - - -class GLCone : public GLShape { - MT_Scalar bottomRadius; - MT_Scalar height; - mutable GLuint displayList; - -public: - GLCone(MT_Scalar r, MT_Scalar h) : - bottomRadius(r), - height(h), - displayList(0) {} - - void paint(GLdouble *m) const { - glPushMatrix(); - glLoadMatrixd(m); - coordSystem(); - if (displayList) glCallList(displayList); - else { - GLUquadricObj *quadObj = gluNewQuadric(); - displayList = glGenLists(1); - glNewList(displayList, GL_COMPILE_AND_EXECUTE); - glPushMatrix(); - glRotatef(-90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, 0.0, -1.0); - gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL); - gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH); - gluCylinder(quadObj, bottomRadius, 0, height, 15, 10); - glPopMatrix(); - glEndList(); - } - glPopMatrix(); - } -}; - -class GLCylinder : public GLShape { - MT_Scalar radius; - MT_Scalar height; - mutable GLuint displayList; - -public: - GLCylinder(MT_Scalar r, MT_Scalar h) : - radius(r), - height(h), - displayList(0) {} - - void paint(GLdouble *m) const { - glPushMatrix(); - glLoadMatrixd(m); - coordSystem(); - if (displayList) glCallList(displayList); - else { - GLUquadricObj *quadObj = gluNewQuadric(); - displayList = glGenLists(1); - glNewList(displayList, GL_COMPILE_AND_EXECUTE); - glPushMatrix(); - glRotatef(-90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, 0.0, -1.0); - gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL); - gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH); - gluCylinder(quadObj, radius, radius, height, 15, 10); - glPopMatrix (); - glEndList(); - } - glPopMatrix(); - } -}; - -class Object; - -class Callback : public SM_Callback { -public: - Callback(Object& object) : m_object(object) {} - - virtual void do_me(); - -private: - Object& m_object; -}; - - -class Object { -public: - Object(GLShape *gl_shape, SM_Object& object) : - m_gl_shape(gl_shape), - m_object(object), - m_callback(*this) - { - m_object.registerCallback(m_callback); - } - - ~Object() {} - - void paint() { - m_gl_shape->paint(m); - // display_bbox(m_bbox.lower(), m_bbox.upper()); - } - - MT_Vector3 getAhead() { - return MT_Vector3(-m[8], -m[9], -m[10]); - } - - void clearMomentum() { - m_object.clearMomentum(); - } - - void setMargin(MT_Scalar margin) { - m_object.setMargin(margin); - } - - void setScaling(const MT_Vector3& scaling) { - m_object.setScaling(scaling); - } - - void setPosition(const MT_Point3& pos) { - m_object.setPosition(pos); - } - - void setOrientation(const MT_Quaternion& orn) { - m_object.setOrientation(orn); - } - - void applyCenterForce(const MT_Vector3& force) { - m_object.applyCenterForce(force); - } - - void applyTorque(const MT_Vector3& torque) { - m_object.applyTorque(torque); - } - - MT_Point3 getWorldCoord(const MT_Point3& local) const { - return m_object.getWorldCoord(local); - } - - MT_Vector3 getLinearVelocity() const { - return m_object.getLinearVelocity(); - } - - void setMatrix() { - m_object.getMatrix(m); - } - -private: - GLShape *m_gl_shape; - SM_Object& m_object; - DT_Scalar m[16]; - Callback m_callback; -}; - - -void Callback::do_me() -{ - m_object.setMatrix(); -} - - -const MT_Scalar SPACE_SIZE = 2; - -static GLSphere gl_sphere(sphere_radius); -static GLBox gl_ground(50.0, 0.0, 50.0); - - - -#ifdef USE_COMPLEX - -const int GRID_SCALE = 10; -const MT_Scalar GRID_UNIT = 25.0 / GRID_SCALE; - -DT_ShapeHandle createComplex() { - DT_ShapeHandle shape = DT_NewComplexShape(); - for (int i0 = -GRID_SCALE; i0 != GRID_SCALE; ++i0) { - for (int j0 = -GRID_SCALE; j0 != GRID_SCALE; ++j0) { - int i1 = i0 + 1; - int j1 = j0 + 1; -#ifdef QUADS - DT_Begin(); - DT_Vertex(GRID_UNIT * i0, bowl_curv * i0*i0, GRID_UNIT * j0); - DT_Vertex(GRID_UNIT * i0, bowl_curv * i0*i0, GRID_UNIT * j1); - DT_Vertex(GRID_UNIT * i1, bowl_curv * i1*i1, GRID_UNIT * j1); - DT_Vertex(GRID_UNIT * i1, bowl_curv * i1*i1, GRID_UNIT * j0); - DT_End(); -#else - DT_Begin(); - DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j0); - DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j1); - DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j1); - DT_End(); - - DT_Begin(); - DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j1); - DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j1); - DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j0); - DT_End(); -#endif - - } - } - DT_EndComplexShape(); - return shape; -} - - -static DT_ShapeHandle ground_shape = createComplex(); - -#else - -static DT_ShapeHandle ground_shape = DT_Box(50, 0, 50); - -#endif - -static SM_Object sm_ground(ground_shape, &g_materialProps, 0, 0); -static Object ground(&gl_ground, sm_ground); - -static SM_Object sm_sphere(DT_Sphere(0.0), &g_materialProps, &g_shapeProps, 0); -static Object object(&gl_sphere, sm_sphere); - - -static SM_Object sm_ray(DT_Ray(0.0, -1.0, 0.0), 0, 0, 0); - -static SM_Scene g_scene; - - -void myinit(void) { - - GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; - GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; - GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; - - /* light_position is NOT default value */ - GLfloat light_position0[] = { 1.0, 1.0, 1.0, 0.0 }; - GLfloat light_position1[] = { -1.0, -1.0, -1.0, 0.0 }; - - glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT0, GL_POSITION, light_position0); - - glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); - glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); - glLightfv(GL_LIGHT1, GL_POSITION, light_position1); - - - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); - - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - // glEnable(GL_CULL_FACE); - // glCullFace(GL_BACK); - - g_scene.setForceField(gravity); - g_scene.add(sm_ground); - sm_ground.setMargin(ground_margin); - - new(&object) Object(&gl_sphere, sm_sphere); - - - object.setMargin(sphere_radius); - - g_scene.add(sm_sphere); - - ground.setPosition(MT_Point3(0, -10, 0)); - ground.setOrientation(MT_Quaternion(0, 0, 0, 1)); - ground.setMatrix(); - center.setValue(0.0, 0.0, 0.0); - - newRandom(); -} - - -//MT_Point3 cp1, cp2; -//bool intersection; - -bool g_hit = false; -MT_Point3 g_spot; -MT_Vector3 g_normal; - - -void display(void) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - ground.paint(); - object.paint(); - - if (g_hit) { - glPointSize(5); - glBegin(GL_POINTS); - glVertex3d(g_spot[0], g_spot[1], g_spot[2]); - glEnd(); - glPointSize(1); - } - - - -#ifdef COLLISION - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glColor3f(1, 1, 0); - if (intersection) { - glPointSize(5); - glBegin(GL_POINTS); - glVertex3d(cp1[0], cp1[1], cp1[2]); - glEnd(); - glPointSize(1); - } - else { - glBegin(GL_LINES); - glVertex3d(cp1[0], cp1[1], cp1[2]); - glVertex3d(cp2[0], cp2[1], cp2[2]); - glEnd(); - } - glEnable(GL_LIGHTING); - glEnable(GL_DEPTH_TEST); -#endif - - glFlush(); - glutSwapBuffers(); -} - - - - - -void newRandom() { - object.setPosition(MT_Point3(0, 0, 0)); - object.clearMomentum(); - object.setMatrix(); - - display(); -} - -void moveAndDisplay() { - g_scene.proceed(timeStep, 0.01); - - MT_Vector3 normal(0, 1, 0); - - MT_Point3 from = object.getWorldCoord(MT_Point3(0, 0, 0)); - MT_Point3 to = from - normal * 10.0; - - g_hit = DT_ObjectRayTest(sm_ground.getObjectHandle(), - from.getValue(), - to.getValue(), g_spot.getValue(), - g_normal.getValue()); - - // Scrap -#define DO_FH -#ifdef DO_FH - MT_Scalar dist = MT_distance(from, g_spot); - if (dist < 5.0) { - MT_Vector3 lin_vel = object.getLinearVelocity(); - MT_Scalar lin_vel_normal = lin_vel.dot(normal); - - MT_Scalar spring_extent = dist + lin_vel_normal * (timeStep * 0.5); - - MT_Scalar f_spring = (5.0 - spring_extent) * 3.0; - object.applyCenterForce(normal * f_spring); - object.applyCenterForce(-lin_vel_normal * normal); - } - -#endif - - - display(); -} - - -void turn_left() { - object.applyTorque(MT_Vector3(0.0, 10.0, 0.0)); -} - -void turn_right() { - object.applyTorque(MT_Vector3(0.0, -10.0, 0.0)); -} - -void forward() { - object.applyCenterForce(20.0 * object.getAhead()); -} - -void backward() { - object.applyCenterForce(-20.0 * object.getAhead()); -} - -void jump() { - object.applyCenterForce(MT_Vector3(0.0, 200.0, 0.0)); -} - - -void toggleIdle() { - static bool idle = true; - if (idle) { - glutIdleFunc(moveAndDisplay); - idle = false; - } - else { - glutIdleFunc(NULL); - idle = true; - } -} - - -void setCamera() { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 200.0); - MT_Scalar rele = MT_radians(ele); - MT_Scalar razi = MT_radians(azi); - eye.setValue(DISTANCE * sin(razi) * cos(rele), - DISTANCE * sin(rele), - DISTANCE * cos(razi) * cos(rele)); - gluLookAt(eye[0], eye[1], eye[2], - center[0], center[1], center[2], - 0, 1, 0); - glMatrixMode(GL_MODELVIEW); - display(); -} - -const MT_Scalar STEPSIZE = 5; - -void stepLeft() { azi -= STEPSIZE; if (azi < 0) azi += 360; setCamera(); } -void stepRight() { azi += STEPSIZE; if (azi >= 360) azi -= 360; setCamera(); } -void stepFront() { ele += STEPSIZE; if (azi >= 360) azi -= 360; setCamera(); } -void stepBack() { ele -= STEPSIZE; if (azi < 0) azi += 360; setCamera(); } -void zoomIn() { DISTANCE -= 1; setCamera(); } -void zoomOut() { DISTANCE += 1; setCamera(); } - - -void myReshape(int w, int h) { - glViewport(0, 0, w, h); - setCamera(); -} - -void myKeyboard(unsigned char key, int x, int y) -{ - switch (key) - { - case 'w': forward(); break; - case 's': backward(); break; - case 'a': turn_left(); break; - case 'd': turn_right(); break; - case 'e': jump(); break; - case 'l' : stepLeft(); break; - case 'r' : stepRight(); break; - case 'f' : stepFront(); break; - case 'b' : stepBack(); break; - case 'z' : zoomIn(); break; - case 'x' : zoomOut(); break; - case 'i' : toggleIdle(); break; - case ' ' : newRandom(); break; - default: -// std::cout << "unused key : " << key << std::endl; - break; - } -} - -void mySpecial(int key, int x, int y) -{ - switch (key) - { - case GLUT_KEY_LEFT : stepLeft(); break; - case GLUT_KEY_RIGHT : stepRight(); break; - case GLUT_KEY_UP : stepFront(); break; - case GLUT_KEY_DOWN : stepBack(); break; - case GLUT_KEY_PAGE_UP : zoomIn(); break; - case GLUT_KEY_PAGE_DOWN : zoomOut(); break; - case GLUT_KEY_HOME : toggleIdle(); break; - default: -// std::cout << "unused (special) key : " << key << std::endl; - break; - } -} - -void goodbye( void) -{ - g_scene.remove(sm_ground); - g_scene.remove(sm_sphere); - - std::cout << "goodbye ..." << std::endl; - exit(0); -} - -void menu(int choice) -{ - - static int fullScreen = 0; - static int px, py, sx, sy; - - switch(choice) { - case 1: - if (fullScreen == 1) { - glutPositionWindow(px,py); - glutReshapeWindow(sx,sy); - glutChangeToMenuEntry(1,"Full Screen",1); - fullScreen = 0; - } else { - px=glutGet((GLenum)GLUT_WINDOW_X); - py=glutGet((GLenum)GLUT_WINDOW_Y); - sx=glutGet((GLenum)GLUT_WINDOW_WIDTH); - sy=glutGet((GLenum)GLUT_WINDOW_HEIGHT); - glutFullScreen(); - glutChangeToMenuEntry(1,"Close Full Screen",1); - fullScreen = 1; - } - break; - case 2: - toggleIdle(); - break; - case 3: - goodbye(); - break; - default: - break; - } -} - -void createMenu() -{ - glutCreateMenu(menu); - glutAddMenuEntry("Full Screen", 1); - glutAddMenuEntry("Toggle Idle (Start/Stop)", 2); - glutAddMenuEntry("Quit", 3); - glutAttachMenu(GLUT_RIGHT_BUTTON); -} - -int main(int argc, char **argv) { - glutInit(&argc, argv); - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); - glutInitWindowPosition(0, 0); - glutInitWindowSize(500, 500); - glutCreateWindow("Physics demo"); - - myinit(); - glutKeyboardFunc(myKeyboard); - glutSpecialFunc(mySpecial); - glutReshapeFunc(myReshape); - createMenu(); - glutIdleFunc(NULL); - - glutDisplayFunc(display); - glutMainLoop(); - return 0; -} - - - - - - - diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/Makefile b/source/gameengine/Physics/Sumo/Fuzzics/src/Makefile deleted file mode 100644 index b2744c5496a..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/src/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# $Id$ -# Copyright (C) 2001 NaN Technologies B.V. - -LIBNAME = fuzzics -DIR = $(OCGDIR)/gameengine/blphys/$(LIBNAME) - -include nan_compile.mk - -CCFLAGS += $(LEVEL_1_CPP_WARNINGS) - -CPPFLAGS += -I../include -I$(NAN_MOTO)/include -I../../include -CPPFLAGS += -I$(NAN_SOLID)/include - diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_FhObject.cpp b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_FhObject.cpp deleted file mode 100644 index d866cdb4922..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_FhObject.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/** - * $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ -#include "SM_FhObject.h" -#include "MT_MinMax.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -SM_FhObject::SM_FhObject(DT_ShapeHandle rayshape, MT_Vector3 ray, SM_Object *parent_object) : - SM_Object(rayshape, NULL, NULL, NULL), - m_ray(ray), - m_ray_direction(ray.normalized()), - m_parent_object(parent_object) -{ -} - -SM_FhObject::~SM_FhObject() -{ - DT_DeleteShape(getShapeHandle()); -} - -DT_Bool SM_FhObject::ray_hit(void *client_data, - void *client_object1, - void *client_object2, - const DT_CollData *coll_data) -{ - - SM_FhObject *fh_object = dynamic_cast<SM_FhObject *>((SM_Object *)client_object2); - if (!fh_object) - { - std::swap(client_object1, client_object2); - fh_object = dynamic_cast<SM_FhObject *>((SM_Object *)client_object2); - } - - SM_Object *hit_object = (SM_Object *)client_object1; - const SM_MaterialProps *matProps = hit_object->getMaterialProps(); - - if ((matProps == 0) || (matProps->m_fh_distance < MT_EPSILON)) { - return DT_CONTINUE; - } - - SM_Object *cl_object = fh_object->getParentObject(); - - assert(fh_object); - - if (hit_object == cl_object) { - // Shot myself in the foot... - return DT_CONTINUE; - } - - const SM_ShapeProps *shapeProps = cl_object->getShapeProps(); - - // Exit if the client object is not dynamic. - if (shapeProps == 0) { - return DT_CONTINUE; - } - - MT_Point3 lspot; - MT_Vector3 normal; - - DT_Vector3 from, to, dnormal; - DT_Scalar dlspot; - fh_object->getPosition().getValue(from); - fh_object->getSpot().getValue(to); - - - if (DT_ObjectRayCast(hit_object->getObjectHandle(), - from, - to, - 1., - &dlspot, - dnormal)) { - - lspot = fh_object->getPosition() + (fh_object->getSpot() - fh_object->getPosition()) * dlspot; - const MT_Vector3& ray_dir = fh_object->getRayDirection(); - MT_Scalar dist = MT_distance(fh_object->getPosition(), lspot) - - cl_object->getMargin() - shapeProps->m_radius; - - normal = MT_Vector3(dnormal).safe_normalized(); - - if (dist < matProps->m_fh_distance) { - - if (shapeProps->m_do_fh) { - lspot -= hit_object->getPosition(); - MT_Vector3 rel_vel = cl_object->getLinearVelocity() - hit_object->getVelocity(lspot); - MT_Scalar rel_vel_ray = ray_dir.dot(rel_vel); - MT_Scalar spring_extent = 1.0 - dist / matProps->m_fh_distance; - - MT_Scalar i_spring = spring_extent * matProps->m_fh_spring; - MT_Scalar i_damp = rel_vel_ray * matProps->m_fh_damping; - - cl_object->addLinearVelocity(-(i_spring + i_damp) * ray_dir); - if (matProps->m_fh_normal) { - cl_object->addLinearVelocity( - (i_spring + i_damp) * - (normal - normal.dot(ray_dir) * ray_dir)); - } - - MT_Vector3 lateral = rel_vel - rel_vel_ray * ray_dir; - const SM_ShapeProps *shapeProps = cl_object->getShapeProps(); - - if (shapeProps->m_do_anisotropic) { - MT_Matrix3x3 lcs(cl_object->getOrientation()); - MT_Vector3 loc_lateral = lateral * lcs; - const MT_Vector3& friction_scaling = - shapeProps->m_friction_scaling; - - loc_lateral.scale(friction_scaling[0], - friction_scaling[1], - friction_scaling[2]); - lateral = lcs * loc_lateral; - } - - - MT_Scalar rel_vel_lateral = lateral.length(); - - if (rel_vel_lateral > MT_EPSILON) { - MT_Scalar friction_factor = matProps->m_friction; - MT_Scalar max_friction = friction_factor * MT_max(MT_Scalar(0.0), i_spring); - - MT_Scalar rel_mom_lateral = rel_vel_lateral / - cl_object->getInvMass(); - - MT_Vector3 friction = - (rel_mom_lateral > max_friction) ? - -lateral * (max_friction / rel_vel_lateral) : - -lateral; - - cl_object->applyCenterImpulse(friction); - } - } - - if (shapeProps->m_do_rot_fh) { - const double *ogl_mat = cl_object->getMatrix(); - MT_Vector3 up(&ogl_mat[8]); - MT_Vector3 t_spring = up.cross(normal) * matProps->m_fh_spring; - MT_Vector3 ang_vel = cl_object->getAngularVelocity(); - - // only rotations that tilt relative to the normal are damped - ang_vel -= ang_vel.dot(normal) * normal; - - MT_Vector3 t_damp = ang_vel * matProps->m_fh_damping; - - cl_object->addAngularVelocity(t_spring - t_damp); - } - } - } - - return DT_CONTINUE; -} - - - diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_MotionState.cpp b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_MotionState.cpp deleted file mode 100644 index b8f4e0c591c..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_MotionState.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/** - * $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ -#include <MT_Scalar.h> -#include <MT_Vector3.h> -#include <MT_Quaternion.h> - -#include "SM_MotionState.h" - -void SM_MotionState::integrateMidpoint(MT_Scalar timeStep, const SM_MotionState &prev_state, const MT_Vector3 &velocity, const MT_Quaternion& ang_vel) -{ - m_pos += (prev_state.getLinearVelocity() + velocity) * (timeStep * 0.5); - m_orn += (prev_state.getAngularVelocity() * prev_state.getOrientation() + ang_vel * m_orn) * (timeStep * 0.25); - m_orn.normalize(); -} - -void SM_MotionState::integrateBackward(MT_Scalar timeStep, const MT_Vector3 &velocity, const MT_Quaternion& ang_vel) -{ - m_pos += velocity * timeStep; - m_orn += ang_vel * m_orn * (timeStep * 0.5); - m_orn.normalize(); -} - -void SM_MotionState::integrateForward(MT_Scalar timeStep, const SM_MotionState &prev_state) -{ - m_pos += prev_state.getLinearVelocity() * timeStep; - m_orn += prev_state.getAngularVelocity() * m_orn * (timeStep * 0.5); - m_orn.normalize(); -} - -/* -// Newtonian lerp: interpolate based on Newtonian motion -void SM_MotionState::nlerp(const SM_MotionState &prev, const SM_MotionState &next) -{ - MT_Scalar dt = next.getTime() - prev.getTime(); - MT_Scalar t = getTime() - prev.getTime(); - MT_Vector3 dx = next.getPosition() - prev.getPosition(); - MT_Vector3 a = dx/(dt*dt) - prev.getLinearVelocity()/dt; - - m_pos = prev.getPosition() + prev.getLinearVelocity()*t + a*t*t; -} -*/ - -void SM_MotionState::lerp(const SM_MotionState &prev, const SM_MotionState &next) -{ - MT_Scalar dt = next.getTime() - prev.getTime(); - if (MT_fuzzyZero(dt)) - { - *this = next; - return; - } - - MT_Scalar x = (getTime() - prev.getTime())/dt; - - m_pos = x*next.getPosition() + (1-x)*prev.getPosition(); - - m_orn = prev.getOrientation().slerp(next.getOrientation(), 1-x); - - m_lin_vel = x*next.getLinearVelocity() + (1-x)*prev.getLinearVelocity(); - m_ang_vel = x*next.getAngularVelocity() + (1-x)*prev.getAngularVelocity(); -} - -void SM_MotionState::lerp(MT_Scalar t, const SM_MotionState &other) -{ - MT_Scalar x = (t - getTime())/(other.getTime() - getTime()); - m_pos = (1-x)*m_pos + x*other.getPosition(); - - m_orn = other.getOrientation().slerp(m_orn, x); - - m_lin_vel = (1-x)*m_lin_vel + x*other.getLinearVelocity(); - m_ang_vel = (1-x)*m_ang_vel + x*other.getAngularVelocity(); - - m_time = t; -} - diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Object.cpp b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Object.cpp deleted file mode 100644 index 4b2c7cae008..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Object.cpp +++ /dev/null @@ -1,1298 +0,0 @@ -/** - * $Id$ - * Copyright (C) 2001 NaN Technologies B.V. - * The basic physics object. - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef WIN32 -// This warning tells us about truncation of __long__ stl-generated names. -// It can occasionally cause DevStudio to have internal compiler warnings. -#pragma warning( disable : 4786 ) -#endif - -#include "MT_assert.h" - -#include "SM_Object.h" -#include "SM_Scene.h" -#include "SM_FhObject.h" -#include "SM_Debug.h" - -#include "MT_MinMax.h" - -MT_Scalar SM_Object::ImpulseThreshold = -1.0; - -struct Contact -{ - SM_Object *obj1; - SM_Object *obj2; - MT_Vector3 normal; - MT_Point3 pos; - - // Sort objects by height - bool operator()(const Contact *a, const Contact *b) - { - return a->pos[2] < b->pos[2]; - } - - Contact(SM_Object *o1, SM_Object *o2, const MT_Vector3 nor, const MT_Point3 p) - : obj1(o1), - obj2(o2), - normal(nor), - pos(p) - { - } - - Contact() - { - } - - void resolve() - { - if (obj1->m_static || obj2->m_static) - { - if (obj1->isDynamic()) - { - if (obj1->m_static && obj2->m_static) - { - if (obj1->m_static < obj2->m_static) - { - obj2->m_error -= normal; - obj2->m_static = obj1->m_static + 1; - } - else - { - obj1->m_error += normal; - obj1->m_static = obj2->m_static + 1; - } - } - else - { - if (obj1->m_static) - { - obj2->m_error -= normal; - obj2->m_static = obj1->m_static + 1; - } - else - { - obj1->m_error += normal; - obj1->m_static = obj2->m_static + 1; - } - } - } - else - { - obj2->m_error -= normal; - obj2->m_static = 1; - } - } - else - { - // This distinction between dynamic and non-dynamic objects should not be - // necessary. Non-dynamic objects are assumed to have infinite mass. - if (obj1->isDynamic()) { - MT_Vector3 error = normal * 0.5f; - obj1->m_error += error; - obj2->m_error -= error; - } - else { - // Same again but now obj1 is non-dynamic - obj2->m_error -= normal; - obj2->m_static = obj1->m_static + 1; - } - } - - } - - - typedef std::set<Contact*, Contact> Set; -}; - -static Contact::Set contacts; - -SM_Object::SM_Object( - DT_ShapeHandle shape, - const SM_MaterialProps *materialProps, - const SM_ShapeProps *shapeProps, - SM_Object *dynamicParent) : - - m_dynamicParent(dynamicParent), - m_client_object(0), - m_physicsClientObject(0), - m_shape(shape), - m_materialProps(materialProps), - m_materialPropsBackup(0), - m_shapeProps(shapeProps), - m_shapePropsBackup(0), - m_margin(0.0), - m_scaling(1.0, 1.0, 1.0), - m_reaction_impulse(0.0, 0.0, 0.0), - m_reaction_force(0.0, 0.0, 0.0), - m_lin_mom(0.0, 0.0, 0.0), - m_ang_mom(0.0, 0.0, 0.0), - m_force(0.0, 0.0, 0.0), - m_torque(0.0, 0.0, 0.0), - m_error(0.0, 0.0, 0.0), - m_combined_lin_vel (0.0, 0.0, 0.0), - m_combined_ang_vel (0.0, 0.0, 0.0), - m_fh_object(0), - m_inv_mass(0.0), - m_inv_inertia(0., 0., 0.), - m_kinematic(false), - m_prev_kinematic(false), - m_is_rigid_body(false), - m_static(0) -{ - m_object = DT_CreateObject(this, shape); - m_xform.setIdentity(); - m_xform.getValue(m_ogl_matrix); - if (shapeProps) - { - if (shapeProps->m_do_fh || shapeProps->m_do_rot_fh) - { - DT_Vector3 zero = {0., 0., 0.}, ray = {0.0, 0.0, -10.0}; - m_fh_object = new SM_FhObject(DT_NewLineSegment(zero, ray), MT_Vector3(ray), this); - //printf("SM_Object:: WARNING! fh disabled.\n"); - } - m_inv_mass = 1. / shapeProps->m_mass; - m_inv_inertia = MT_Vector3(1./shapeProps->m_inertia[0], 1./shapeProps->m_inertia[1], 1./shapeProps->m_inertia[2]); - } - updateInvInertiaTensor(); - m_suspended = false; -} - - - void -SM_Object:: -integrateForces( - MT_Scalar timeStep -){ - if (!m_suspended) { - m_prev_state = getNextFrame(); - m_prev_state.setLinearVelocity(actualLinVelocity()); - m_prev_state.setAngularVelocity(actualAngVelocity()); - if (isDynamic()) { - // Integrate momentum (forward Euler) - m_lin_mom += m_force * timeStep; - m_ang_mom += m_torque * timeStep; - // Drain momentum because of air/water resistance - m_lin_mom *= pow(m_shapeProps->m_lin_drag, timeStep); - m_ang_mom *= pow(m_shapeProps->m_ang_drag, timeStep); - // Set velocities according momentum - getNextFrame().setLinearVelocity(m_lin_mom * m_inv_mass); - getNextFrame().setAngularVelocity(m_inv_inertia_tensor * m_ang_mom); - } - } - -}; - - void -SM_Object:: -integrateMomentum( - MT_Scalar timeStep -){ - // Integrate position and orientation - - // only do it for objects with linear and/or angular velocity - // else clients with hierarchies may get into trouble - if (!actualLinVelocity().fuzzyZero() || !actualAngVelocity().fuzzyZero()) - { - - // those MIDPOINT and BACKWARD integration methods are - // in this form not ok with some testfiles ! - // For a release build please use forward euler unless completely tested - -//#define MIDPOINT -//#define BACKWARD -#ifdef MIDPOINT -// Midpoint rule - getNextFrame().integrateMidpoint(timeStep, m_prev_state, actualLinVelocity(), actualAngVelocity()); -#elif defined BACKWARD -// Backward Euler - getNextFrame().integrateBackward(timeStep, actualLinVelocity(), actualAngVelocity()); -#else -// Forward Euler - getNextFrame().integrateForward(timeStep, m_prev_state); -#endif - - calcXform(); - notifyClient(); - - } -} - -/** - * dynamicCollision computes the response to a collision. - * - * @param local2 the contact point in local coordinates. - * @param normal the contact normal. - * @param dist the penetration depth of the contact. (unused) - * @param rel_vel the relative velocity of the objects - * @param restitution the amount of momentum conserved in the collision. Range: 0.0 - 1.0 - * @param friction_factor the amount of friction between the two surfaces. - * @param invMass the inverse mass of the collision objects (1.0 / mass) - */ -void SM_Object::dynamicCollision(const MT_Point3 &local2, - const MT_Vector3 &normal, - MT_Scalar dist, - const MT_Vector3 &rel_vel, - MT_Scalar restitution, - MT_Scalar friction_factor, - MT_Scalar invMass -) -{ - /** - * rel_vel_normal is the relative velocity in the contact normal direction. - */ - MT_Scalar rel_vel_normal = normal.dot(rel_vel); - - /** - * if rel_vel_normal > 0, the objects are moving apart! - */ - if (rel_vel_normal < -MT_EPSILON) { - /** - * if rel_vel_normal < ImpulseThreshold, scale the restitution down. - * This should improve the simulation where the object is stacked. - */ - restitution *= MT_min(MT_Scalar(1.0), rel_vel_normal/ImpulseThreshold); - - MT_Scalar impulse = -(1.0 + restitution) * rel_vel_normal; - - if (isRigidBody()) - { - MT_Vector3 temp = getInvInertiaTensor() * local2.cross(normal); - impulse /= invMass + normal.dot(temp.cross(local2)); - - /** - * Apply impulse at the collision point. - * Take rotational inertia into account. - */ - applyImpulse(local2 + getNextFrame().getPosition(), impulse * normal); - } else { - /** - * Apply impulse through object center. (no rotation.) - */ - impulse /= invMass; - applyCenterImpulse( impulse * normal ); - } - - MT_Vector3 external = m_combined_lin_vel + m_combined_ang_vel.cross(local2); - MT_Vector3 lateral = rel_vel - external - normal * (rel_vel_normal - external.dot(normal)); -#if 0 - // test - only do friction on the physics part of the - // velocity. - vel1 -= obj1->m_combined_lin_vel; - vel2 -= obj2->m_combined_lin_vel; - - // This should look familiar.... - rel_vel = vel2 - vel1; - rel_vel_normal = normal.dot(rel_vel); -#endif - /** - * The friction part starts here!!!!!!!! - * - * Compute the lateral component of the relative velocity - * lateral actually points in the opposite direction, i.e., - * into the direction of the friction force. - */ - if (m_shapeProps->m_do_anisotropic) { - - /** - * For anisotropic friction we scale the lateral component, - * rather than compute a direction-dependent fricition - * factor. For this the lateral component is transformed to - * local coordinates. - */ - - MT_Matrix3x3 lcs(getNextFrame().getOrientation()); - - /** - * We cannot use m_xform.getBasis() for the matrix, since - * it might contain a non-uniform scaling. - * OPT: it's a bit daft to compute the matrix since the - * quaternion itself can be used to do the transformation. - */ - MT_Vector3 loc_lateral = lateral * lcs; - - /** - * lcs is orthogonal so lcs.inversed() == lcs.transposed(), - * and lcs.transposed() * lateral == lateral * lcs. - */ - const MT_Vector3& friction_scaling = - m_shapeProps->m_friction_scaling; - - // Scale the local lateral... - loc_lateral.scale(friction_scaling[0], - friction_scaling[1], - friction_scaling[2]); - // ... and transform it back to global coordinates - lateral = lcs * loc_lateral; - } - - /** - * A tiny Coulomb friction primer: - * The Coulomb friction law states that the magnitude of the - * maximum possible friction force depends linearly on the - * magnitude of the normal force. - * - * \f[ - F_max_friction = friction_factor * F_normal - \f] - * - * (NB: independent of the contact area!!) - * - * The friction factor depends on the material. - * We use impulses rather than forces but let us not be - * bothered by this. - */ - MT_Scalar rel_vel_lateral = lateral.length(); - - if (rel_vel_lateral > MT_EPSILON) { - lateral /= rel_vel_lateral; - - // Compute the maximum friction impulse - MT_Scalar max_friction = - friction_factor * MT_max(MT_Scalar(0.0), impulse); - - // I guess the GEN_max is not necessary, so let's check it - - MT_assert(impulse >= 0.0); - - /** - * Here's the trick. We compute the impulse to make the - * lateral velocity zero. (Make the objects stick together - * at the contact point. If this impulse is larger than - * the maximum possible friction impulse, then shrink its - * magnitude to the maximum friction. - */ - - if (isRigidBody()) { - - /** - * For rigid bodies we take the inertia into account, - * since the friction impulse is going to change the - * angular momentum as well. - */ - MT_Vector3 temp = getInvInertiaTensor() * local2.cross(lateral); - MT_Scalar impulse_lateral = rel_vel_lateral / - (invMass + lateral.dot(temp.cross(local2))); - - MT_Scalar friction = MT_min(impulse_lateral, max_friction); - applyImpulse(local2 + getNextFrame().getPosition(), -lateral * friction); - } - else { - MT_Scalar impulse_lateral = rel_vel_lateral / invMass; - - MT_Scalar friction = MT_min(impulse_lateral, max_friction); - applyCenterImpulse( -friction * lateral); - } - - - } - - //calcXform(); - //notifyClient(); - - } -} - -static void AddCallback(SM_Scene *scene, SM_Object *obj1, SM_Object *obj2) -{ - // If we have callbacks on either of the client objects, do a collision test - // and add a callback if they intersect. - DT_Vector3 v; - if ((obj1->getClientObject() && obj1->getClientObject()->hasCollisionCallback()) || - (obj2->getClientObject() && obj2->getClientObject()->hasCollisionCallback()) && - DT_GetIntersect(obj1->getObjectHandle(), obj2->getObjectHandle(), v)) - scene->notifyCollision(obj1, obj2); -} - -DT_Bool SM_Object::boing( - void *client_data, - void *object1, - void *object2, - const DT_CollData *coll_data -){ - SM_Scene *scene = (SM_Scene *)client_data; - SM_Object *obj1 = (SM_Object *)object1; - SM_Object *obj2 = (SM_Object *)object2; - - // at this point it is unknown whether we are really intersecting (broad phase) - - DT_Vector3 p1, p2; - if (!obj2->isDynamic()) { - std::swap(obj1, obj2); - } - - // If one of the objects is a ghost then ignore it for the dynamics - if (obj1->isGhost() || obj2->isGhost()) { - AddCallback(scene, obj1, obj2); - return DT_CONTINUE; - } - - // Objects do not collide with parent objects - if (obj1->getDynamicParent() == obj2 || obj2->getDynamicParent() == obj1) { - AddCallback(scene, obj1, obj2); - return DT_CONTINUE; - } - - if (!obj2->isDynamic()) { - AddCallback(scene, obj1, obj2); - return DT_CONTINUE; - } - - // Get collision data from SOLID - if (!DT_GetPenDepth(obj1->getObjectHandle(), obj2->getObjectHandle(), p1, p2)) - return DT_CONTINUE; - - MT_Point3 local1(p1), local2(p2); - MT_Vector3 normal(local2 - local1); - MT_Scalar dist = normal.length(); - - if (dist < MT_EPSILON) - return DT_CONTINUE; - - // Now we are definitely intersecting. - - // Set callbacks for game engine. - if ((obj1->getClientObject() && obj1->getClientObject()->hasCollisionCallback()) || - (obj2->getClientObject() && obj2->getClientObject()->hasCollisionCallback())) - scene->notifyCollision(obj1, obj2); - - local1 -= obj1->getNextFrame().getPosition(); - local2 -= obj2->getNextFrame().getPosition(); - - // Calculate collision parameters - MT_Vector3 rel_vel = obj1->getVelocity(local1) - obj2->getVelocity(local2); - - MT_Scalar restitution = - MT_min(obj1->getMaterialProps()->m_restitution, - obj2->getMaterialProps()->m_restitution); - - MT_Scalar friction_factor = - MT_min(obj1->getMaterialProps()->m_friction, - obj2->getMaterialProps()->m_friction); - - MT_Scalar invMass = obj1->getInvMass() + obj2->getInvMass(); - - normal /= dist; - - // Calculate reactions - if (obj1->isDynamic()) - obj1->dynamicCollision(local1, normal, dist, rel_vel, restitution, friction_factor, invMass); - - if (obj2->isDynamic()) - { - obj2->dynamicCollision(local2, -normal, dist, -rel_vel, restitution, friction_factor, invMass); - if (!obj1->isDynamic() || obj1->m_static) - obj2->m_static = obj1->m_static + 1; - } - - return DT_CONTINUE; -} - -DT_Bool SM_Object::fix( - void *client_data, - void *object1, - void *object2, - const DT_CollData *coll_data -){ - SM_Object *obj1 = (SM_Object *)object1; - SM_Object *obj2 = (SM_Object *)object2; - - // If one of the objects is a ghost then ignore it for the dynamics - if (obj1->isGhost() || obj2->isGhost()) { - return DT_CONTINUE; - } - - if (obj1->getDynamicParent() == obj2 || obj2->getDynamicParent() == obj1) { - return DT_CONTINUE; - } - - if (!obj2->isDynamic()) { - std::swap(obj1, obj2); - } - - if (!obj2->isDynamic()) { - return DT_CONTINUE; - } - - // obj1 points to a dynamic object - DT_Vector3 p1, p2; - if (!DT_GetPenDepth(obj1->getObjectHandle(), obj2->getObjectHandle(), p1, p2)) - return DT_CONTINUE; - MT_Point3 local1(p1), local2(p2); - // Get collision data from SOLID - MT_Vector3 normal(local2 - local1); - - MT_Scalar dist = normal.dot(normal); - if (dist < MT_EPSILON || dist > obj2->m_shapeProps->m_radius*obj2->m_shapeProps->m_radius) - return DT_CONTINUE; - - - if ((obj1->m_static || !obj1->isDynamic()) && obj1->m_static < obj2->m_static) - { - obj2->m_static = obj1->m_static + 1; - } else if (obj2->m_static && obj2->m_static < obj1->m_static) - { - obj1->m_static = obj2->m_static + 1; - } - - contacts.insert(new Contact(obj1, obj2, normal, MT_Point3(local1 + 0.5*(local2 - local1)))); - - - return DT_CONTINUE; -} - -void SM_Object::relax(void) -{ - for (Contact::Set::iterator csit = contacts.begin() ; csit != contacts.end(); ++csit) - { - (*csit)->resolve(); - delete (*csit); - } - - contacts.clear(); - if (m_error.fuzzyZero()) - return; - //std::cout << "SM_Object::relax: { " << m_error << " }" << std::endl; - - getNextFrame().setPosition(getNextFrame().getPosition() + m_error); - m_error.setValue(0., 0., 0.); - //calcXform(); - //notifyClient(); -} - -SM_Object::SM_Object() : - m_dynamicParent(0), - m_client_object(0), - m_physicsClientObject(0), - m_shape(0), - m_materialProps(0), - m_materialPropsBackup(0), - m_shapeProps(0), - m_shapePropsBackup(0), - m_object(0), - m_margin(0.0), - m_scaling(1.0, 1.0, 1.0), - m_reaction_impulse(0.0, 0.0, 0.0), - m_reaction_force(0.0, 0.0, 0.0), - m_lin_mom(0.0, 0.0, 0.0), - m_ang_mom(0.0, 0.0, 0.0), - m_force(0.0, 0.0, 0.0), - m_torque(0.0, 0.0, 0.0), - m_error(0.0, 0.0, 0.0), - m_combined_lin_vel (0.0, 0.0, 0.0), - m_combined_ang_vel (0.0, 0.0, 0.0), - m_fh_object(0), - m_kinematic(false), - m_prev_kinematic(false), - m_is_rigid_body(false) -{ - // warning no initialization of variables done by moto. -} - -SM_Object:: -~SM_Object() { - if (m_fh_object) - delete m_fh_object; - - DT_DestroyObject(m_object); - m_object = NULL; -} - - bool -SM_Object:: -isDynamic( -) const { - return m_shapeProps != 0; -} - -/* nzc experimental. There seem to be two places where kinematics - * are evaluated: proceedKinematic (called from SM_Scene) and - * proceed() in this object. I'll just try and bunge these out for - * now. */ - void -SM_Object:: -suspend( -){ - if (!m_suspended) { - m_suspended = true; - suspendDynamics(); - } -} - - void -SM_Object:: -resume( -) { - if (m_suspended) { - m_suspended = false; - restoreDynamics(); - } -} - - void -SM_Object:: -suspendDynamics( -) { - if (m_shapeProps) { - m_shapePropsBackup = m_shapeProps; - m_shapeProps = 0; - } -} - - void -SM_Object:: -restoreDynamics( -) { - if (m_shapePropsBackup) { - m_shapeProps = m_shapePropsBackup; - m_shapePropsBackup = 0; - } -} - - bool -SM_Object:: -isGhost( -) const { - return m_materialProps == 0; -} - - void -SM_Object:: -suspendMaterial( -) { - if (m_materialProps) { - m_materialPropsBackup = m_materialProps; - m_materialProps = 0; - } -} - - void -SM_Object:: -restoreMaterial( -) { - if (m_materialPropsBackup) { - m_materialProps = m_materialPropsBackup; - m_materialPropsBackup = 0; - } -} - - SM_FhObject * -SM_Object:: -getFhObject( -) const { - return m_fh_object; -} - - void -SM_Object:: -registerCallback( - SM_Callback& callback -) { - m_callbackList.push_back(&callback); -} - -// Set the local coordinate system according to the current state - void -SM_Object:: -calcXform() { -#ifdef SM_DEBUG_XFORM - printf("SM_Object::calcXform m_pos = { %-0.5f, %-0.5f, %-0.5f }\n", - m_pos[0], m_pos[1], m_pos[2]); - printf(" m_orn = { %-0.5f, %-0.5f, %-0.5f, %-0.5f }\n", - m_orn[0], m_orn[1], m_orn[2], m_orn[3]); - printf(" m_scaling = { %-0.5f, %-0.5f, %-0.5f }\n", - m_scaling[0], m_scaling[1], m_scaling[2]); -#endif - m_xform.setOrigin(getNextFrame().getPosition()); - m_xform.setBasis(MT_Matrix3x3(getNextFrame().getOrientation(), m_scaling)); - m_xform.getValue(m_ogl_matrix); - - /* Blender has been known to crash here. - This usually means SM_Object *this has been deleted more than once. */ - DT_SetMatrixd(m_object, m_ogl_matrix); - if (m_fh_object) { - m_fh_object->setPosition(getNextFrame().getPosition()); - m_fh_object->calcXform(); - } - updateInvInertiaTensor(); -#ifdef SM_DEBUG_XFORM - printf("\n | %-0.5f %-0.5f %-0.5f %-0.5f |\n", - m_ogl_matrix[0], m_ogl_matrix[4], m_ogl_matrix[ 8], m_ogl_matrix[12]); - printf( " | %-0.5f %-0.5f %-0.5f %-0.5f |\n", - m_ogl_matrix[1], m_ogl_matrix[5], m_ogl_matrix[ 9], m_ogl_matrix[13]); - printf( "m_ogl_matrix = | %-0.5f %-0.5f %-0.5f %-0.5f |\n", - m_ogl_matrix[2], m_ogl_matrix[6], m_ogl_matrix[10], m_ogl_matrix[14]); - printf( " | %-0.5f %-0.5f %-0.5f %-0.5f |\n\n", - m_ogl_matrix[3], m_ogl_matrix[7], m_ogl_matrix[11], m_ogl_matrix[15]); -#endif -} - - void -SM_Object::updateInvInertiaTensor() -{ - m_inv_inertia_tensor = m_xform.getBasis().scaled(m_inv_inertia[0], m_inv_inertia[1], m_inv_inertia[2]) * m_xform.getBasis().transposed(); -} - -// Call callbacks to notify the client of a change of placement - void -SM_Object:: -notifyClient() { - T_CallbackList::iterator i; - for (i = m_callbackList.begin(); i != m_callbackList.end(); ++i) { - (*i)->do_me(); - } -} - - -// Save the current state information for use in the velocity computation in the next frame. - void -SM_Object:: -proceedKinematic( - MT_Scalar timeStep -) { - /* nzc: need to bunge this for the logic bubbling as well? */ - if (!m_suspended) { - m_prev_kinematic = m_kinematic; - if (m_kinematic) { - m_prev_xform = m_xform; - m_timeStep = timeStep; - calcXform(); - m_kinematic = false; - } - } -} - - void -SM_Object:: -saveReactionForce( - MT_Scalar timeStep -) { - if (isDynamic()) { - m_reaction_force = m_reaction_impulse / timeStep; - m_reaction_impulse.setValue(0.0, 0.0, 0.0); - } -} - - void -SM_Object:: -clearForce( -) { - m_force.setValue(0.0, 0.0, 0.0); - m_torque.setValue(0.0, 0.0, 0.0); -} - - void -SM_Object:: -clearMomentum( -) { - m_lin_mom.setValue(0.0, 0.0, 0.0); - m_ang_mom.setValue(0.0, 0.0, 0.0); -} - - void -SM_Object:: -setMargin( - MT_Scalar margin -) { - m_margin = margin; - DT_SetMargin(m_object, margin); -} - - MT_Scalar -SM_Object:: -getMargin( -) const { - return m_margin; -} - -const - SM_MaterialProps * -SM_Object:: -getMaterialProps( -) const { - return m_materialProps; -} - -const - SM_ShapeProps * -SM_Object:: -getShapeProps( -) const { - return m_shapeProps; -} - - void -SM_Object:: -setPosition( - const MT_Point3& pos -){ - m_kinematic = true; - getNextFrame().setPosition(pos); - endFrame(); -} - - void -SM_Object:: -setOrientation( - const MT_Quaternion& orn -){ - MT_assert(!orn.fuzzyZero()); - m_kinematic = true; - getNextFrame().setOrientation(orn); - endFrame(); -} - - void -SM_Object:: -setScaling( - const MT_Vector3& scaling -){ - m_kinematic = true; - m_scaling = scaling; -} - -/** - * Functions to handle linear velocity - */ - - void -SM_Object:: -setExternalLinearVelocity( - const MT_Vector3& lin_vel -) { - m_combined_lin_vel=lin_vel; -} - - void -SM_Object:: -addExternalLinearVelocity( - const MT_Vector3& lin_vel -) { - m_combined_lin_vel+=lin_vel; -} - - void -SM_Object:: -addLinearVelocity( - const MT_Vector3& lin_vel -){ - setLinearVelocity(getNextFrame().getLinearVelocity() + lin_vel); -} - - void -SM_Object:: -setLinearVelocity( - const MT_Vector3& lin_vel -){ - getNextFrame().setLinearVelocity(lin_vel); - if (m_shapeProps) { - m_lin_mom = getNextFrame().getLinearVelocity() * m_shapeProps->m_mass; - } -} - -/** - * Functions to handle angular velocity - */ - - void -SM_Object:: -setExternalAngularVelocity( - const MT_Vector3& ang_vel -) { - m_combined_ang_vel = ang_vel; -} - - void -SM_Object:: -addExternalAngularVelocity( - const MT_Vector3& ang_vel -) { - m_combined_ang_vel += ang_vel; -} - - void -SM_Object:: -setAngularVelocity( - const MT_Vector3& ang_vel -) { - getNextFrame().setAngularVelocity(ang_vel); - if (m_shapeProps) { - m_ang_mom = getNextFrame().getAngularVelocity() * m_shapeProps->m_inertia; - } -} - - void -SM_Object:: -addAngularVelocity( - const MT_Vector3& ang_vel -) { - setAngularVelocity(getNextFrame().getAngularVelocity() + ang_vel); -} - - - void -SM_Object:: -clearCombinedVelocities( -) { - m_combined_lin_vel = MT_Vector3(0,0,0); - m_combined_ang_vel = MT_Vector3(0,0,0); -} - - void -SM_Object:: -resolveCombinedVelocities( - const MT_Vector3 & lin_vel, - const MT_Vector3 & ang_vel -) { - - // Different behaviours for dynamic and non-dynamic - // objects. For non-dynamic we just set the velocity to - // zero. For dynmic the physics velocity has to be - // taken into account. We must make an arbitrary decision - // on how to resolve the 2 velocities. Choices are - // Add the physics velocity to the linear velocity. Objects - // will just keep on moving in the direction they were - // last set in - untill external forces affect them. - // Set the combinbed linear and physics velocity to zero. - // Set the physics velocity in the direction of the set velocity - // zero. - if (isDynamic()) { - -#if 1 - getNextFrame().setLinearVelocity(getNextFrame().getLinearVelocity() + lin_vel); - getNextFrame().setAngularVelocity(getNextFrame().getAngularVelocity() + ang_vel); -#else - - //compute the component of the physics velocity in the - // direction of the set velocity and set it to zero. - MT_Vector3 lin_vel_norm = lin_vel.normalized(); - - setLinearVelocity(getNextFrame().getLinearVelocity() - (getNextFrame().getLinearVelocity().dot(lin_vel_norm) * lin_vel_norm)); -#endif - m_lin_mom = getNextFrame().getLinearVelocity() * m_shapeProps->m_mass; - m_ang_mom = getNextFrame().getAngularVelocity() * m_shapeProps->m_inertia; - clearCombinedVelocities(); - - } - -} - - - MT_Scalar -SM_Object:: -getInvMass( -) const { - return m_inv_mass; - // OPT: cache the result of this division rather than compute it each call -} - - const MT_Vector3& -SM_Object:: -getInvInertia( -) const { - return m_inv_inertia; - // OPT: cache the result of this division rather than compute it each call -} - - const MT_Matrix3x3& -SM_Object:: -getInvInertiaTensor( -) const { - return m_inv_inertia_tensor; -} - - void -SM_Object:: -applyForceField( - const MT_Vector3& accel -) { - if (m_shapeProps) { - m_force += m_shapeProps->m_mass * accel; // F = m * a - } -} - - void -SM_Object:: -applyCenterForce( - const MT_Vector3& force -) { - m_force += force; -} - - void -SM_Object:: -applyTorque( - const MT_Vector3& torque -) { - m_torque += torque; -} - - void -SM_Object:: -applyImpulse( - const MT_Point3& attach, const MT_Vector3& impulse -) { - applyCenterImpulse(impulse); // Change in linear momentum - applyAngularImpulse((attach - getNextFrame().getPosition()).cross(impulse)); // Change in angular momentump -} - - void -SM_Object:: -applyCenterImpulse( - const MT_Vector3& impulse -) { - if (m_shapeProps) { - m_lin_mom += impulse; - m_reaction_impulse += impulse; - getNextFrame().setLinearVelocity(m_lin_mom * m_inv_mass); - - // The linear velocity is immedialtely updated since otherwise - // simultaneous collisions will get a double impulse. - } -} - - void -SM_Object:: -applyAngularImpulse( - const MT_Vector3& impulse -) { - if (m_shapeProps) { - m_ang_mom += impulse; - getNextFrame().setAngularVelocity( m_inv_inertia_tensor * m_ang_mom); - } -} - - MT_Point3 -SM_Object:: -getWorldCoord( - const MT_Point3& local -) const { - return m_xform(local); -} - - MT_Vector3 -SM_Object:: -getVelocity( - const MT_Point3& local -) const { - if (m_prev_kinematic && !isDynamic()) - { - // For displaced objects the velocity is faked using the previous state. - // Dynamic objects get their own velocity, not the faked velocity. - // (Dynamic objects shouldn't be displaced in the first place!!) - return (m_xform(local) - m_prev_xform(local)) / m_timeStep; - } - - // NB: m_xform.getBasis() * local == m_xform(local) - m_xform.getOrigin() - return actualLinVelocity() + actualAngVelocity().cross(local); -} - - -const - MT_Vector3& -SM_Object:: -getReactionForce( -) const { - return m_reaction_force; -} - - void -SM_Object:: -getMatrix( - double *m -) const { - std::copy(&m_ogl_matrix[0], &m_ogl_matrix[16], &m[0]); -} - -const - double * -SM_Object:: -getMatrix( -) const { - return m_ogl_matrix; -} - -// Still need this??? -const - MT_Transform& -SM_Object:: -getScaledTransform( -) const { - return m_xform; -} - - DT_ObjectHandle -SM_Object:: -getObjectHandle( -) const { - return m_object; -} - - DT_ShapeHandle -SM_Object:: -getShapeHandle( -) const { - return m_shape; -} - - SM_Object * -SM_Object:: -getDynamicParent( -) { - return m_dynamicParent; -} - - void -SM_Object:: -setRigidBody( - bool is_rigid_body -) { - m_is_rigid_body = is_rigid_body; -} - - bool -SM_Object:: -isRigidBody( -) const { - return m_is_rigid_body; -} - -const - MT_Vector3 -SM_Object:: -actualLinVelocity( -) const { - return m_combined_lin_vel + getNextFrame().getLinearVelocity(); -}; - -const - MT_Vector3 -SM_Object:: -actualAngVelocity( -) const { - return m_combined_ang_vel + getNextFrame().getAngularVelocity(); -} - - -SM_MotionState& -SM_Object:: -getCurrentFrame() -{ - return m_frames[1]; -} - -SM_MotionState& -SM_Object:: -getPreviousFrame() -{ - return m_frames[0]; -} - -SM_MotionState & -SM_Object:: -getNextFrame() -{ - return m_frames[2]; -} - -const SM_MotionState & -SM_Object:: -getCurrentFrame() const -{ - return m_frames[1]; -} - -const SM_MotionState & -SM_Object:: -getPreviousFrame() const -{ - return m_frames[0]; -} - -const SM_MotionState & -SM_Object:: -getNextFrame() const -{ - return m_frames[2]; -} - - -const MT_Point3& -SM_Object:: -getPosition() const -{ - return m_frames[1].getPosition(); -} - -const MT_Quaternion& -SM_Object:: -getOrientation() const -{ - return m_frames[1].getOrientation(); -} - -const MT_Vector3& -SM_Object:: -getLinearVelocity() const -{ - return m_frames[1].getLinearVelocity(); -} - -const MT_Vector3& -SM_Object:: -getAngularVelocity() const -{ - return m_frames[1].getAngularVelocity(); -} - -void -SM_Object:: -interpolate(MT_Scalar timeStep) -{ - if (!actualLinVelocity().fuzzyZero() || !actualAngVelocity().fuzzyZero()) - { - getCurrentFrame().setTime(timeStep); - getCurrentFrame().lerp(getPreviousFrame(), getNextFrame()); - notifyClient(); - } -} - -void -SM_Object:: -endFrame() -{ - getPreviousFrame() = getNextFrame(); - getCurrentFrame() = getNextFrame(); - m_static = 0; -} diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp deleted file mode 100644 index f0791bbf89f..00000000000 --- a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/** - * $Id$ - * Copyright (C) 2001 NaN Technologies B.V. - * The physics scene. - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef WIN32 -#pragma warning(disable : 4786) // shut off 255 char limit debug template warning -#endif - -#include "SM_Scene.h" -#include "SM_Object.h" -#include "SM_FhObject.h" - -#include "SM_Debug.h" - -#include <algorithm> - -SM_Scene::SM_Scene() : - m_scene(DT_CreateScene()), - m_respTable(DT_CreateRespTable()), - m_secondaryRespTable(DT_CreateRespTable()), - m_fixRespTable(DT_CreateRespTable()), - m_forceField(0.0, 0.0, 0.0), - m_frames(0) -{ - for (int i = 0 ; i < NUM_RESPONSE; i++) - { - m_ResponseClass[i] = DT_GenResponseClass(m_respTable); - m_secondaryResponseClass[i] = DT_GenResponseClass(m_secondaryRespTable); - m_fixResponseClass[i] = DT_GenResponseClass(m_fixRespTable); - } - - /* Sensor */ - DT_AddPairResponse(m_respTable, m_ResponseClass[SENSOR_RESPONSE], m_ResponseClass[SENSOR_RESPONSE], 0, DT_NO_RESPONSE, this); - DT_AddPairResponse(m_respTable, m_ResponseClass[SENSOR_RESPONSE], m_ResponseClass[STATIC_RESPONSE], SM_Scene::boing, DT_SIMPLE_RESPONSE, this); - DT_AddPairResponse(m_respTable, m_ResponseClass[SENSOR_RESPONSE], m_ResponseClass[OBJECT_RESPONSE], SM_Scene::boing, DT_SIMPLE_RESPONSE, this); - DT_AddPairResponse(m_respTable, m_ResponseClass[SENSOR_RESPONSE], m_ResponseClass[FH_RESPONSE], 0, DT_NO_RESPONSE, this); - - /* Static */ - DT_AddPairResponse(m_respTable, m_ResponseClass[STATIC_RESPONSE], m_ResponseClass[SENSOR_RESPONSE], SM_Scene::boing, DT_SIMPLE_RESPONSE, this); - DT_AddPairResponse(m_respTable, m_ResponseClass[STATIC_RESPONSE], m_ResponseClass[STATIC_RESPONSE], 0, DT_NO_RESPONSE, this); - DT_AddPairResponse(m_respTable, m_ResponseClass[STATIC_RESPONSE], m_ResponseClass[OBJECT_RESPONSE], SM_Object::boing, DT_BROAD_RESPONSE, this); - DT_AddPairResponse(m_respTable, m_ResponseClass[STATIC_RESPONSE], m_ResponseClass[FH_RESPONSE], SM_FhObject::ray_hit, DT_SIMPLE_RESPONSE, this); - - /* Object */ - DT_AddPairResponse(m_respTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[SENSOR_RESPONSE], SM_Scene::boing, DT_SIMPLE_RESPONSE, this); - DT_AddPairResponse(m_respTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[STATIC_RESPONSE], SM_Object::boing, DT_BROAD_RESPONSE, this); - DT_AddPairResponse(m_respTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[OBJECT_RESPONSE], SM_Object::boing, DT_BROAD_RESPONSE, this); - DT_AddPairResponse(m_respTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[FH_RESPONSE], SM_FhObject::ray_hit, DT_SIMPLE_RESPONSE, this); - - /* Fh Object */ - DT_AddPairResponse(m_respTable, m_ResponseClass[FH_RESPONSE], m_ResponseClass[SENSOR_RESPONSE], 0, DT_NO_RESPONSE, this); - DT_AddPairResponse(m_respTable, m_ResponseClass[FH_RESPONSE], m_ResponseClass[STATIC_RESPONSE], SM_FhObject::ray_hit, DT_SIMPLE_RESPONSE, this); - DT_AddPairResponse(m_respTable, m_ResponseClass[FH_RESPONSE], m_ResponseClass[OBJECT_RESPONSE], SM_FhObject::ray_hit, DT_SIMPLE_RESPONSE, this); - DT_AddPairResponse(m_respTable, m_ResponseClass[FH_RESPONSE], m_ResponseClass[FH_RESPONSE], 0, DT_NO_RESPONSE, this); - - /* Object (Fix Pass) */ - DT_AddPairResponse(m_fixRespTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[SENSOR_RESPONSE], 0, DT_NO_RESPONSE, this); - DT_AddPairResponse(m_fixRespTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[STATIC_RESPONSE], SM_Object::fix, DT_BROAD_RESPONSE, this); - DT_AddPairResponse(m_fixRespTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[OBJECT_RESPONSE], SM_Object::fix, DT_BROAD_RESPONSE, this); - DT_AddPairResponse(m_fixRespTable, m_ResponseClass[OBJECT_RESPONSE], m_ResponseClass[FH_RESPONSE], 0, DT_NO_RESPONSE, this); -} - -void SM_Scene::addTouchCallback(int response_class, DT_ResponseCallback callback, void *user) -{ - DT_AddClassResponse(m_secondaryRespTable, m_secondaryResponseClass[response_class], callback, DT_BROAD_RESPONSE, user); -} - -void SM_Scene::addSensor(SM_Object& object) -{ - T_ObjectList::iterator i = - std::find(m_objectList.begin(), m_objectList.end(), &object); - if (i == m_objectList.end()) - { - object.calcXform(); - m_objectList.push_back(&object); - DT_AddObject(m_scene, object.getObjectHandle()); - DT_SetResponseClass(m_respTable, object.getObjectHandle(), m_ResponseClass[SENSOR_RESPONSE]); - DT_SetResponseClass(m_secondaryRespTable, object.getObjectHandle(), m_secondaryResponseClass [SENSOR_RESPONSE]); - DT_SetResponseClass(m_fixRespTable, object.getObjectHandle(), m_fixResponseClass[SENSOR_RESPONSE]); - } -} - -void SM_Scene::add(SM_Object& object) { - object.calcXform(); - m_objectList.push_back(&object); - DT_AddObject(m_scene, object.getObjectHandle()); - if (object.isDynamic()) { - DT_SetResponseClass(m_respTable, object.getObjectHandle(), m_ResponseClass[OBJECT_RESPONSE]); - DT_SetResponseClass(m_secondaryRespTable, object.getObjectHandle(), m_secondaryResponseClass[OBJECT_RESPONSE]); - DT_SetResponseClass(m_fixRespTable, object.getObjectHandle(), m_fixResponseClass[OBJECT_RESPONSE]); - } else { - DT_SetResponseClass(m_respTable, object.getObjectHandle(), m_ResponseClass[STATIC_RESPONSE]); - DT_SetResponseClass(m_secondaryRespTable, object.getObjectHandle(), m_secondaryResponseClass[STATIC_RESPONSE]); - DT_SetResponseClass(m_fixRespTable, object.getObjectHandle(), m_fixResponseClass[STATIC_RESPONSE]); - } - - SM_FhObject *fh_object = object.getFhObject(); - - if (fh_object) { - DT_AddObject(m_scene, fh_object->getObjectHandle()); - DT_SetResponseClass(m_respTable, fh_object->getObjectHandle(), m_ResponseClass[FH_RESPONSE]); - DT_SetResponseClass(m_secondaryRespTable, fh_object->getObjectHandle(), m_secondaryResponseClass[FH_RESPONSE]); - DT_SetResponseClass(m_fixRespTable, fh_object->getObjectHandle(), m_fixResponseClass[FH_RESPONSE]); - } -} - -void SM_Scene::requestCollisionCallback(SM_Object &object) -{ - DT_SetResponseClass(m_respTable, object.getObjectHandle(), m_ResponseClass[OBJECT_RESPONSE]); - DT_SetResponseClass(m_secondaryRespTable, object.getObjectHandle(), m_secondaryResponseClass[OBJECT_RESPONSE]); -// DT_SetResponseClass(m_fixRespTable, object.getObjectHandle(), m_fixResponseClass[OBJECT_RESPONSE]); -} - -void SM_Scene::remove(SM_Object& object) { - //std::cout << "SM_Scene::remove this =" << this << "object = " << &object << std::endl; - T_ObjectList::iterator i = - std::find(m_objectList.begin(), m_objectList.end(), &object); - if (!(i == m_objectList.end())) - { - std::swap(*i, m_objectList.back()); - m_objectList.pop_back(); - DT_RemoveObject(m_scene, object.getObjectHandle()); - - SM_FhObject *fh_object = object.getFhObject(); - - if (fh_object) { - DT_RemoveObject(m_scene, fh_object->getObjectHandle()); - } - } - else { - // tried to remove an object that is not in the scene - //assert(false); - } -} - -void SM_Scene::beginFrame() -{ - T_ObjectList::iterator i; - // Apply a forcefield (such as gravity) - for (i = m_objectList.begin(); i != m_objectList.end(); ++i) - (*i)->applyForceField(m_forceField); - -} - -void SM_Scene::endFrame() -{ - T_ObjectList::iterator i; - for (i = m_objectList.begin(); i != m_objectList.end(); ++i) - (*i)->clearForce(); -} - -bool SM_Scene::proceed(MT_Scalar curtime, MT_Scalar ticrate) -{ - if (!m_frames) - { - if (ticrate > 0.) - m_frames = (unsigned int)(curtime*ticrate) + 1.0; - else - m_frames = (unsigned int)(curtime*65536.0); - } - - // Divide the timeStep into a number of subsamples of size roughly - // equal to subS (might be a little smaller). - MT_Scalar subStep; - int num_samples; - int frames = m_frames; - - // Compute the number of steps to do this update. - if (ticrate > 0.0) - { - // Fixed time step - subStep = 1.0/ticrate; - num_samples = (unsigned int)(curtime*ticrate + 1.0) - m_frames; - - if (num_samples > 4) - { - std::cout << "Dropping physics frames! frames:" << num_samples << " substep: " << subStep << std::endl; - MT_Scalar tr = ticrate; - do - { - frames = frames / 2; - tr = tr / 2.0; - num_samples = (unsigned int)(curtime*tr + 1.0) - frames; - subStep *= 2.0; - } while (num_samples > 8); - std::cout << " frames:" << num_samples << " substep: " << subStep << std::endl; - } - } - else - { - // Variable time step. (old update) - // Integrate at least 100 Hz - MT_Scalar timeStep = curtime - m_frames/65536.0; - subStep = timeStep > 0.01 ? 0.01 : timeStep; - num_samples = int(timeStep * 0.01); - if (num_samples < 1) - num_samples = 1; - } - - // Do a physics timestep. - T_ObjectList::iterator i; - if (num_samples > 0) - { - // Do the integration steps per object. - for (int step = 0; step != num_samples; ++step) - { - MT_Scalar time; - if (ticrate > 0.) - time = MT_Scalar(frames + step + 1) * subStep; - else - time = MT_Scalar(m_frames)/65536.0 + MT_Scalar(step + 1)*subStep; - - for (i = m_objectList.begin(); i != m_objectList.end(); ++i) { - (*i)->endFrame(); - // Apply a forcefield (such as gravity) - (*i)->integrateForces(subStep); - // And second we update the object positions by performing - // an integration step for each object - (*i)->integrateMomentum(subStep); - } - - // So now first we let the physics scene respond to - // new forces, velocities set externally. - // The collsion and friction impulses are computed here. - // Collision phase - DT_Test(m_scene, m_respTable); - - // Contact phase - DT_Test(m_scene, m_fixRespTable); - - // Finish this timestep by saving al state information for the next - // timestep and clearing the accumulated forces. - for (i = m_objectList.begin(); i != m_objectList.end(); ++i) { - (*i)->relax(); - (*i)->proceedKinematic(subStep); - (*i)->saveReactionForce(subStep); - (*i)->getNextFrame().setTime(time); - //(*i)->clearForce(); - } - } - } - - if (ticrate > 0) - { - // Interpolate between time steps. - for (i = m_objectList.begin(); i != m_objectList.end(); ++i) - (*i)->interpolate(curtime); - - //only update the m_frames after an actual physics timestep - if (num_samples) - { - m_frames = (unsigned int)(curtime*ticrate) + 1.0; - } - } - else - { - m_frames = (unsigned int)(curtime*65536.0); - } - - return num_samples != 0; -} - -void SM_Scene::notifyCollision(SM_Object *obj1, SM_Object *obj2) -{ - // For each pair of object that collided, call the corresponding callback. - if (m_secondaryRespTable) - DT_CallResponse(m_secondaryRespTable, obj1->getObjectHandle(), obj2->getObjectHandle(), 0); -} - - -SM_Object *SM_Scene::rayTest(void *ignore_client, - const MT_Point3& from, const MT_Point3& to, - MT_Point3& result, MT_Vector3& normal) const { -#ifdef SM_DEBUG_RAYCAST - std::cout << "ray: { " << from << " } - { " << to << " }" << std::endl; -#endif - - DT_Vector3 n, dfrom, dto; - DT_Scalar param; - from.getValue(dfrom); - to.getValue(dto); - SM_Object *hit_object = (SM_Object *) - DT_RayCast(m_scene, ignore_client, dfrom, dto, 1., ¶m, n); - - if (hit_object) { - //result = hit_object->getWorldCoord(from + (to - from)*param); - result = from + (to - from) * param; - normal.setValue(n); -#ifdef SM_DEBUG_RAYCAST - std::cout << "ray: { " << from << " } -> { " << to << " }: { " << result - << " } (" << param << "), normal = { " << normal << " }" << std::endl; -#endif - } - - return hit_object; -} - -void SM_Scene::clearObjectCombinedVelocities() { - - T_ObjectList::iterator i; - - for (i = m_objectList.begin(); i != m_objectList.end(); ++i) { - - (*i)->clearCombinedVelocities(); - - } - -} - - -void SM_Scene::setSecondaryRespTable(DT_RespTableHandle secondaryRespTable) { - m_secondaryRespTable = secondaryRespTable; -} - - -DT_Bool SM_Scene::boing( - void *client_data, - void *object1, - void *object2, - const DT_CollData * -){ - SM_Scene *scene = (SM_Scene *)client_data; - SM_Object *obj1 = (SM_Object *)object1; - SM_Object *obj2 = (SM_Object *)object2; - - scene->notifyCollision(obj1, obj2); // Record this collision for client callbacks - -#ifdef SM_DEBUG_BOING - printf("SM_Scene::boing\n"); -#endif - - return DT_CONTINUE; -} - -SM_Scene::~SM_Scene() -{ - //std::cout << "SM_Scene::~ SM_Scene(): destroy " << this << std::endl; -// if (m_objectList.begin() != m_objectList.end()) -// std::cout << "SM_Scene::~SM_Scene: There are still objects in the Sumo scene!" << std::endl; - for (T_ObjectList::iterator it = m_objectList.begin() ; it != m_objectList.end() ; it++) - delete *it; - - DT_DestroyRespTable(m_respTable); - DT_DestroyRespTable(m_secondaryRespTable); - DT_DestroyRespTable(m_fixRespTable); - DT_DestroyScene(m_scene); -} diff --git a/source/gameengine/Physics/Sumo/SConscript b/source/gameengine/Physics/Sumo/SConscript deleted file mode 100644 index 86e8db5919f..00000000000 --- a/source/gameengine/Physics/Sumo/SConscript +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/python -Import ('env') - -sources = ['SumoPHYCallbackBridge.cpp', - 'SumoPhysicsController.cpp', - 'SumoPhysicsEnvironment.cpp', - 'Fuzzics/src/SM_FhObject.cpp', - 'Fuzzics/src/SM_Object.cpp', - 'Fuzzics/src/SM_Scene.cpp', - 'Fuzzics/src/SM_MotionState.cpp' - ] - -incs =['.', - '../common', - 'Fuzzics/include', - '#/intern/moto/include' - ] -incs += [env['BF_SOLID_INC']] - -cflags = [] -if env['OURPLATFORM']=='win32-vc': - cflags.append('/GR') - cflags.append('/O1') - -env.BlenderLib ( 'bf_sumo', sources, incs, [], libtype=['game2','player'], priority=[30, 70] , compileflags=cflags) diff --git a/source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.cpp b/source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.cpp deleted file mode 100644 index 1992bbe3421..00000000000 --- a/source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "SumoPHYCallbackBridge.h" -#include "PHY_IPhysicsController.h" -#include "SM_Object.h" - - -SumoPHYCallbackBridge::SumoPHYCallbackBridge(void* clientData,PHY_ResponseCallback phyCallback) -:m_orgClientData(clientData), -m_phyCallback(phyCallback) -{ - -} -DT_Bool SumoPHYCallbackBridge::StaticSolidToPHYCallback(void *client_data, - void *client_object1, - void *client_object2, - const DT_CollData *coll_data) -{ - SumoPHYCallbackBridge* bridge = static_cast<SumoPHYCallbackBridge*>(client_data); - bridge->SolidToPHY(client_object1,client_object2,coll_data); - return false; -} - -DT_Bool SumoPHYCallbackBridge::SolidToPHY(void *client_object1, - void *client_object2, - const DT_CollData *coll_data) -{ - - SM_Object* smObject1 = static_cast<SM_Object*>(client_object1); - SM_Object* smObject2 = static_cast<SM_Object*>(client_object2); - - PHY_IPhysicsController* ctrl1 = static_cast<PHY_IPhysicsController*>(smObject1->getPhysicsClientObject()); - PHY_IPhysicsController* ctrl2 = static_cast<PHY_IPhysicsController*>(smObject2->getPhysicsClientObject()); - - if (!ctrl1 || !ctrl2) - { - //todo: check which objects are not linked up properly - return false; - } - if (coll_data) - { - PHY_CollData phyCollData; - - phyCollData.m_point1[0] = coll_data->point1[0]; - phyCollData.m_point1[1] = coll_data->point1[1]; - phyCollData.m_point1[2] = coll_data->point1[2]; - phyCollData.m_point1[3] = 0.f; - - phyCollData.m_point2[0] = coll_data->point2[0]; - phyCollData.m_point2[1] = coll_data->point2[1]; - phyCollData.m_point2[2] = coll_data->point2[2]; - phyCollData.m_point2[3] = 0.f; - - phyCollData.m_normal[0] = coll_data->normal[0]; - phyCollData.m_normal[1] = coll_data->normal[1]; - phyCollData.m_normal[2] = coll_data->normal[2]; - phyCollData.m_normal[3] = 0.f; - - - return m_phyCallback(m_orgClientData, - ctrl1,ctrl2,&phyCollData); - } - - return m_phyCallback(m_orgClientData, - ctrl1,ctrl2,0); - -} - diff --git a/source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.h b/source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.h deleted file mode 100644 index cc980f3961d..00000000000 --- a/source/gameengine/Physics/Sumo/SumoPHYCallbackBridge.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef SUMO_PHY_CALLBACK_BRIDGE_H -#define SUMO_PHY_CALLBACK_BRIDGE_H - -#include <SOLID/SOLID.h> -#include "PHY_DynamicTypes.h" - -class SumoPHYCallbackBridge -{ - void* m_orgClientData; - PHY_ResponseCallback m_phyCallback; - -public: - - SumoPHYCallbackBridge(void* clientData,PHY_ResponseCallback phyCallback); - - static DT_Bool StaticSolidToPHYCallback(void *client_data, - void *client_object1, - void *client_object2, - const DT_CollData *coll_data); - - DT_Bool SolidToPHY(void *client_object1, - void *client_object2, - const DT_CollData *coll_data); - - -}; - -#endif //SUMO_PHY_CALLBACK_BRIDGE_H diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsController.cpp b/source/gameengine/Physics/Sumo/SumoPhysicsController.cpp deleted file mode 100644 index 3451e6c3ec8..00000000000 --- a/source/gameengine/Physics/Sumo/SumoPhysicsController.cpp +++ /dev/null @@ -1,490 +0,0 @@ -/** - * @file $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ - -#include "SumoPhysicsController.h" -#include "PHY_IMotionState.h" -#include "SM_Object.h" -#include "MT_Quaternion.h" - - -SumoPhysicsController::SumoPhysicsController( - class SM_Scene* sumoScene, - class SM_Object* sumoObj, - class PHY_IMotionState* motionstate, - - bool dyna) - : - m_sumoObj(sumoObj) , - m_sumoScene(sumoScene), - m_bFirstTime(true), - m_bDyna(dyna), - m_MotionState(motionstate) -{ - if (m_sumoObj) - { - - PHY__Vector3 pos1; - getPosition(pos1); - MT_Point3 pos(pos1); - - //temp debugging check - //assert(pos.length() < 100000.f); - - //need this to do the upcast after the solid/sumo collision callback - m_sumoObj->setPhysicsClientObject(this); - //if it is a dyna, register for a callback - m_sumoObj->registerCallback(*this); - } -}; - - - -SumoPhysicsController::~SumoPhysicsController() -{ - if (m_sumoObj) - { - m_sumoScene->remove(*m_sumoObj); - - delete m_sumoObj; - m_sumoObj = NULL; - } -} - -float SumoPhysicsController::getMass() -{ - if (m_sumoObj) - { - const SM_ShapeProps *shapeprops = m_sumoObj->getShapeProps(); - if(shapeprops!=NULL) return shapeprops->m_mass; - } - return 0.f; -} - -bool SumoPhysicsController::SynchronizeMotionStates(float) -{ - if (m_bFirstTime) - { - setSumoTransform(!m_bFirstTime); - m_bFirstTime = false; - } - return false; -} - - - - -void SumoPhysicsController::GetWorldOrientation(MT_Matrix3x3& mat) -{ - float orn[4]; - m_MotionState->getWorldOrientation(orn[0],orn[1],orn[2],orn[3]); - MT_Quaternion quat(orn); - mat.setRotation(quat); - -} - -void SumoPhysicsController::getPosition(PHY__Vector3& pos) const -{ - assert(m_sumoObj); - - pos[0] = m_sumoObj->getPosition()[0]; - pos[1] = m_sumoObj->getPosition()[0]; - pos[2] = m_sumoObj->getPosition()[0]; - - //m_MotionState->getWorldPosition(pos[0],pos[1],pos[2]); -} - -void SumoPhysicsController::GetWorldPosition(MT_Point3& pos) -{ -// assert(m_sumoObj); - -// pos[0] = m_sumoObj->getPosition()[0]; -// pos[1] = m_sumoObj->getPosition()[0]; -// pos[2] = m_sumoObj->getPosition()[0]; - - float worldpos[3]; - m_MotionState->getWorldPosition(worldpos[0],worldpos[1],worldpos[2]); - pos[0]=worldpos[0]; - pos[1]=worldpos[1]; - pos[2]=worldpos[2]; -} - -void SumoPhysicsController::GetWorldScaling(MT_Vector3& scale) -{ - float worldscale[3]; - m_MotionState->getWorldScaling(worldscale[0],worldscale[1],worldscale[2]); - scale[0]=worldscale[0]; - scale[1]=worldscale[1]; - scale[2]=worldscale[2]; -} - - - // kinematic methods -void SumoPhysicsController::RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local) -{ - if (m_sumoObj) - { - MT_Matrix3x3 mat; - GetWorldOrientation(mat); - MT_Vector3 dloc(dlocX,dlocY,dlocZ); - - MT_Point3 newpos = m_sumoObj->getPosition(); - - newpos += (local ? mat * dloc : dloc); - m_sumoObj->setPosition(newpos); - } - -} -void SumoPhysicsController::RelativeRotate(const float drot[12],bool local) -{ - if (m_sumoObj ) - { - MT_Matrix3x3 drotmat(drot); - MT_Matrix3x3 currentOrn; - GetWorldOrientation(currentOrn); - - m_sumoObj->setOrientation(m_sumoObj->getOrientation()*(local ? - drotmat : (currentOrn.inverse() * drotmat * currentOrn)).getRotation()); - } - -} -void SumoPhysicsController::setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal) -{ - m_sumoObj->setOrientation(MT_Quaternion(quatImag0,quatImag1,quatImag2,quatReal)); -} - -void SumoPhysicsController::getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal) -{ - const MT_Quaternion& q = m_sumoObj->getOrientation(); - quatImag0 = q[0]; - quatImag1 = q[1]; - quatImag2 = q[2]; - quatReal = q[3]; -} - -void SumoPhysicsController::setPosition(float posX,float posY,float posZ) -{ - m_sumoObj->setPosition(MT_Point3(posX,posY,posZ)); -} - -void SumoPhysicsController::setScaling(float scaleX,float scaleY,float scaleZ) -{ - if (!m_bDyna) - m_sumoObj->setScaling(MT_Vector3(scaleX,scaleY,scaleZ)); -} - - // physics methods -void SumoPhysicsController::ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local) -{ - if (m_sumoObj) - { - MT_Vector3 torque(torqueX,torqueY,torqueZ); - - MT_Matrix3x3 orn; - GetWorldOrientation(orn); - m_sumoObj->applyTorque(local ? - orn * torque : - torque); - } -} - -void SumoPhysicsController::ApplyForce(float forceX,float forceY,float forceZ,bool local) -{ - if (m_sumoObj) - { - MT_Vector3 force(forceX,forceY,forceZ); - - MT_Matrix3x3 orn; - GetWorldOrientation(orn); - - m_sumoObj->applyCenterForce(local ? - orn * force : - force); - } -} - -void SumoPhysicsController::SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local) -{ - if (m_sumoObj) - { - MT_Vector3 ang_vel(ang_velX,ang_velY,ang_velZ); - - MT_Matrix3x3 orn; - GetWorldOrientation(orn); - - m_sumoObj->setExternalAngularVelocity(local ? - orn * ang_vel : - ang_vel); - } -} - -void SumoPhysicsController::SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local) -{ - if (m_sumoObj ) - { - MT_Matrix3x3 orn; - GetWorldOrientation(orn); - - MT_Vector3 lin_vel(lin_velX,lin_velY,lin_velZ); - m_sumoObj->setExternalLinearVelocity(local ? - orn * lin_vel : - lin_vel); - } -} - -void SumoPhysicsController::resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) -{ - if (m_sumoObj) - m_sumoObj->resolveCombinedVelocities(MT_Vector3(linvelX,linvelY,linvelZ),MT_Vector3(angVelX,angVelY,angVelZ)); -} - - - - -void SumoPhysicsController::applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ) -{ - if (m_sumoObj) - { - MT_Point3 attach(attachX,attachY,attachZ); - MT_Vector3 impulse(impulseX,impulseY,impulseZ); - m_sumoObj->applyImpulse(attach,impulse); - } - -} - -void SumoPhysicsController::SuspendDynamics() -{ - m_suspendDynamics=true; - - if (m_sumoObj) - { - m_sumoObj->suspendDynamics(); - m_sumoObj->setLinearVelocity(MT_Vector3(0,0,0)); - m_sumoObj->setAngularVelocity(MT_Vector3(0,0,0)); - m_sumoObj->calcXform(); - } -} - -void SumoPhysicsController::RestoreDynamics() -{ - m_suspendDynamics=false; - - if (m_sumoObj) - { - m_sumoObj->restoreDynamics(); - } -} - - -/** - reading out information from physics -*/ -void SumoPhysicsController::GetLinearVelocity(float& linvX,float& linvY,float& linvZ) -{ - if (m_sumoObj) - { - // get velocity from the physics object (m_sumoObj) - const MT_Vector3& vel = m_sumoObj->getLinearVelocity(); - linvX = vel[0]; - linvY = vel[1]; - linvZ = vel[2]; - } - else - { - linvX = 0.f; - linvY = 0.f; - linvZ = 0.f; - } -} - -/** - GetVelocity parameters are in geometric coordinates (Origin is not center of mass!). -*/ -void SumoPhysicsController::GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ) -{ - if (m_sumoObj) - { - MT_Point3 pos(posX,posY,posZ); - // get velocity from the physics object (m_sumoObj) - const MT_Vector3& vel = m_sumoObj->getVelocity(pos); - linvX = vel[0]; - linvY = vel[1]; - linvZ = vel[2]; - } - else - { - linvX = 0.f; - linvY = 0.f; - linvZ = 0.f; - - } -} - -void SumoPhysicsController::getReactionForce(float& forceX,float& forceY,float& forceZ) -{ - const MT_Vector3& force = m_sumoObj->getReactionForce(); - forceX = force[0]; - forceY = force[1]; - forceZ = force[2]; -} - -void SumoPhysicsController::setRigidBody(bool rigid) -{ - m_sumoObj->setRigidBody(rigid); -} - -void SumoPhysicsController::PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl) -{ - m_MotionState = motionstate; - - SM_Object* dynaparent=0; - SumoPhysicsController* sumoparentctrl = (SumoPhysicsController* )parentctrl; - - if (sumoparentctrl) - { - dynaparent = sumoparentctrl->GetSumoObject(); - } - - SM_Object* orgsumoobject = m_sumoObj; - - - m_sumoObj = new SM_Object( - orgsumoobject->getShapeHandle(), - orgsumoobject->getMaterialProps(), - orgsumoobject->getShapeProps(), - dynaparent); - - m_sumoObj->setRigidBody(orgsumoobject->isRigidBody()); - - m_sumoObj->setMargin(orgsumoobject->getMargin()); - m_sumoObj->setPosition(orgsumoobject->getPosition()); - m_sumoObj->setOrientation(orgsumoobject->getOrientation()); - //if it is a dyna, register for a callback - m_sumoObj->registerCallback(*this); - - m_sumoScene->add(* (m_sumoObj)); -} - -void SumoPhysicsController::SetSimulatedTime(float) -{ -} - - -void SumoPhysicsController::WriteMotionStateToDynamics(bool) -{ - -} -// this is the actual callback from sumo, and the position/orientation -//is written to the scenegraph, using the motionstate abstraction - -void SumoPhysicsController::do_me() -{ - MT_assert(m_sumoObj); - const MT_Point3& pos = m_sumoObj->getPosition(); - const MT_Quaternion& orn = m_sumoObj->getOrientation(); - - MT_assert(m_MotionState); - m_MotionState->setWorldPosition(pos[0],pos[1],pos[2]); - m_MotionState->setWorldOrientation(orn[0],orn[1],orn[2],orn[3]); -} - - -void SumoPhysicsController::setSumoTransform(bool nondynaonly) -{ - if (!nondynaonly || !m_bDyna) - { - if (m_sumoObj) - { - MT_Point3 pos; - GetWorldPosition(pos); - - m_sumoObj->setPosition(pos); - if (m_bDyna) - { - m_sumoObj->setScaling(MT_Vector3(1,1,1)); - } else - { - MT_Vector3 scale; - GetWorldScaling(scale); - m_sumoObj->setScaling(scale); - } - MT_Matrix3x3 orn; - GetWorldOrientation(orn); - m_sumoObj->setOrientation(orn.getRotation()); - m_sumoObj->calcXform(); - } - } -} - - - // clientinfo for raycasts for example -void* SumoPhysicsController::getNewClientInfo() -{ - if (m_sumoObj) - return m_sumoObj->getClientObject(); - return 0; - -} -void SumoPhysicsController::setNewClientInfo(void* clientinfo) -{ - if (m_sumoObj) - { - SM_ClientObject* clOb = static_cast<SM_ClientObject*> (clientinfo); - m_sumoObj->setClientObject(clOb); - } - -} - -void SumoPhysicsController::calcXform() -{ - if (m_sumoObj) - m_sumoObj->calcXform(); -} - -void SumoPhysicsController::SetMargin(float margin) -{ - if (m_sumoObj) - m_sumoObj->setMargin(margin); -} - -float SumoPhysicsController::GetMargin() const -{ - if (m_sumoObj) - m_sumoObj->getMargin(); - return 0.f; -} - -float SumoPhysicsController::GetRadius() const -{ - if (m_sumoObj && m_sumoObj->getShapeProps()) - { - return m_sumoObj->getShapeProps()->m_radius; - } - return 0.f; - -} diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsController.h b/source/gameengine/Physics/Sumo/SumoPhysicsController.h deleted file mode 100644 index d8ee54935d7..00000000000 --- a/source/gameengine/Physics/Sumo/SumoPhysicsController.h +++ /dev/null @@ -1,186 +0,0 @@ -/** - * @file $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ -#ifndef __SUMO_PHYSICSCONTROLLER_H -#define __SUMO_PHYSICSCONTROLLER_H - -#include "PHY_IPhysicsController.h" -#include "SM_Scene.h" -#include "SM_Callback.h" - -/** - * Sumo Physics Controller, a special kind of a PhysicsController. - * A Physics Controller is a special kind of Scene Graph Transformation Controller. - * Each time the scene graph get's updated, the controller get's a chance - * in the 'Update' method to reflect changes. - * - * Sumo uses the SOLID library for collision detection. - */ -class SumoPhysicsController : public PHY_IPhysicsController , public SM_Callback - - -{ - - -public: - SumoPhysicsController( - class SM_Scene* sumoScene, - class SM_Object* sumoObj, - class PHY_IMotionState* motionstate, - bool dyna); - - virtual ~SumoPhysicsController(); - - /** - * @name Kinematic Methods. - */ - /*@{*/ - virtual void RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local); - /** - * @param drot a 3x4 matrix. This will treated as a 3x3 rotation matrix. - * @warning RelativeRotate expects a 3x4 matrix. The fourth column is padding. - */ - virtual void RelativeRotate(const float drot[12],bool local); - virtual void getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal); - virtual void setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal); - virtual void setPosition(float posX,float posY,float posZ); - virtual void getPosition(PHY__Vector3& pos) const; - - virtual void setScaling(float scaleX,float scaleY,float scaleZ); - /*@}*/ - - /** - * @name Physics Methods - */ - /*@{*/ - virtual void ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local); - virtual void ApplyForce(float forceX,float forceY,float forceZ,bool local); - virtual void SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local); - virtual void SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local); - virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ); - virtual void applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ); - virtual void SetActive(bool active){}; - virtual void SuspendDynamics(); - virtual void RestoreDynamics(); - /*@}*/ - - - /** - * reading out information from physics - */ - virtual void GetLinearVelocity(float& linvX,float& linvY,float& linvZ); - /** - * GetVelocity parameters are in geometric coordinates (Origin is not center of mass!). - */ - virtual void GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ); - virtual float getMass(); - virtual void getReactionForce(float& forceX,float& forceY,float& forceZ); - virtual void setRigidBody(bool rigid); - - - virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl); - - // TODO: remove next line ! - virtual void SetSimulatedTime(float time); - - virtual void WriteDynamicsToMotionState() {}; - virtual void WriteMotionStateToDynamics(bool nondynaonly); - - /** - * call from Scene Graph Node to 'update'. - */ - virtual bool SynchronizeMotionStates(float time); - - virtual void calcXform(); - virtual void SetMargin(float margin) ; - virtual float GetMargin() const; - virtual float GetRadius() const ; - virtual void SetRadius(float margin) { SetMargin(margin); } - - - // clientinfo for raycasts for example - virtual void* getNewClientInfo(); - virtual void setNewClientInfo(void* clientinfo); - - float getFriction() { return m_friction;} - float getRestitution() { return m_restitution;} - - /** - * Sumo callback - */ - virtual void do_me(); - - class SM_Object* GetSumoObject () - { - return m_sumoObj; - }; - - void GetWorldOrientation(class MT_Matrix3x3& mat); - void GetWorldPosition(MT_Point3& pos); - void GetWorldScaling(MT_Vector3& scale); - - -// void SetSumoObject(class SM_Object* sumoObj) { -// m_sumoObj = sumoObj; -// } -// void SetSumoScene(class SM_Scene* sumoScene) { -// m_sumoScene = sumoScene; -// } - - void setSumoTransform(bool nondynaonly); - - -private: - class SM_Object* m_sumoObj; - class SM_Scene* m_sumoScene; // needed for replication - bool m_bFirstTime; - bool m_bDyna; - - float m_friction; - float m_restitution; - - - bool m_suspendDynamics; - - bool m_firstTime; - bool m_bFullRigidBody; - bool m_bPhantom; // special flag for objects that are not affected by physics 'resolver' - - // data to calculate fake velocities for kinematic objects (non-dynas) - bool m_bKinematic; - bool m_bPrevKinematic; - - float m_lastTime; - - class PHY_IMotionState* m_MotionState; - - -}; - -#endif //__SUMO_PHYSICSCONTROLLER_H - diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp deleted file mode 100644 index 3be5e027345..00000000000 --- a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/** - * $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ -#include <string.h> // memset -#include "SumoPhysicsEnvironment.h" -#include "PHY_IMotionState.h" -#include "SumoPhysicsController.h" -#include "SM_Scene.h" -#include "SumoPHYCallbackBridge.h" -#include <SOLID/SOLID.h> - -SumoPhysicsEnvironment::SumoPhysicsEnvironment() -{ - m_fixedTimeStep = 1.f/60.f; - m_useFixedTimeStep = true; - m_currentTime = 0.f; - - m_sumoScene = new SM_Scene(); -} - - - -SumoPhysicsEnvironment::~SumoPhysicsEnvironment() -{ - delete m_sumoScene; -} - - - -void SumoPhysicsEnvironment::beginFrame() -{ - m_sumoScene->beginFrame(); -} - -void SumoPhysicsEnvironment::endFrame() -{ - m_sumoScene->endFrame(); -} - -void SumoPhysicsEnvironment::setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep) -{ - m_useFixedTimeStep = useFixedTimeStep; - if (m_useFixedTimeStep) - { - m_fixedTimeStep = fixedTimeStep; - } else - { - m_fixedTimeStep = 0.f; - } - //reset current time ? - m_currentTime = 0.f; -} -float SumoPhysicsEnvironment::getFixedTimeStep() -{ - return m_fixedTimeStep; -} - - -bool SumoPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep) -{ - - bool result = false; - if (m_useFixedTimeStep) - { - m_currentTime += timeStep; - float ticrate = 1.f/m_fixedTimeStep; - - result = m_sumoScene->proceed(curTime, ticrate); - } else - { - m_currentTime += timeStep; - result = m_sumoScene->proceed(m_currentTime, timeStep); - } - return result; -} - -void SumoPhysicsEnvironment::setGravity(float x,float y,float z) -{ - m_sumoScene->setForceField(MT_Vector3(x,y,z)); -} - -int SumoPhysicsEnvironment::createConstraint( - class PHY_IPhysicsController* ctrl, - class PHY_IPhysicsController* ctrl2, - PHY_ConstraintType type, - float pivotX,float pivotY,float pivotZ, - float axisX,float axisY,float axisZ, - float axis1X,float axis1Y,float axis1Z, - float axis2X,float axis2Y,float axis2Z, - int flag - ) -{ - int constraintid = 0; - return constraintid; -} - -void SumoPhysicsEnvironment::removeConstraint(int constraintid) -{ - if (constraintid) - { - } -} - -PHY_IPhysicsController* SumoPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback, - float fromX,float fromY,float fromZ, - float toX,float toY,float toZ) -{ - SumoPhysicsController* ignoreCtr = static_cast<SumoPhysicsController*> (filterCallback.m_ignoreController); - - //collision detection / raytesting - MT_Point3 hit, normal; - PHY_RayCastResult result; - - SM_Object* sm_ignore = 0; - if (ignoreCtr) - sm_ignore = ignoreCtr->GetSumoObject(); - - memset(&result, 0, sizeof(result)); - - SM_Object* smOb = m_sumoScene->rayTest(sm_ignore,MT_Point3(fromX, fromY, fromZ),MT_Point3(toX, toY, toZ), hit, normal); - if (smOb) - { - result.m_controller = (PHY_IPhysicsController *) smOb->getPhysicsClientObject(); - result.m_hitPoint[0] = hit[0]; - result.m_hitPoint[1] = hit[1]; - result.m_hitPoint[2] = hit[2]; - result.m_hitNormal[0] = normal[0]; - result.m_hitNormal[1] = normal[1]; - result.m_hitNormal[2] = normal[2]; - filterCallback.reportHit(&result); - } - return result.m_controller; -} -//gamelogic callbacks -void SumoPhysicsEnvironment::addSensor(PHY_IPhysicsController* ctrl) -{ - SumoPhysicsController* smctrl = dynamic_cast<SumoPhysicsController*>(ctrl); - SM_Object* smObject = smctrl->GetSumoObject(); - assert(smObject); - if (smObject) - { - m_sumoScene->addSensor(*smObject); - } -} -void SumoPhysicsEnvironment::removeSensor(PHY_IPhysicsController* ctrl) -{ - SumoPhysicsController* smctrl = dynamic_cast<SumoPhysicsController*>(ctrl); - SM_Object* smObject = smctrl->GetSumoObject(); - assert(smObject); - if (smObject) - { - m_sumoScene->remove(*smObject); - } -} - - -void SumoPhysicsEnvironment::addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user) -{ - - int sumoRespClass = 0; - - //map PHY_ convention into SM_ convention - switch (response_class) - { - case PHY_FH_RESPONSE: - sumoRespClass = FH_RESPONSE; - break; - case PHY_SENSOR_RESPONSE: - sumoRespClass = SENSOR_RESPONSE; - break; - case PHY_CAMERA_RESPONSE: - sumoRespClass =CAMERA_RESPONSE; - break; - case PHY_OBJECT_RESPONSE: - sumoRespClass = OBJECT_RESPONSE; - break; - case PHY_STATIC_RESPONSE: - sumoRespClass = PHY_STATIC_RESPONSE; - break; - case PHY_BROADPH_RESPONSE: - return; - default: - assert(0); - return; - } - - SumoPHYCallbackBridge* bridge = new SumoPHYCallbackBridge(user,callback); - - m_sumoScene->addTouchCallback(sumoRespClass,SumoPHYCallbackBridge::StaticSolidToPHYCallback,bridge); -} -void SumoPhysicsEnvironment::requestCollisionCallback(PHY_IPhysicsController* ctrl) -{ - SumoPhysicsController* smctrl = dynamic_cast<SumoPhysicsController*>(ctrl); - MT_assert(smctrl); - SM_Object* smObject = smctrl->GetSumoObject(); - MT_assert(smObject); - if (smObject) - { - //assert(smObject->getPhysicsClientObject() == ctrl); - smObject->setPhysicsClientObject(ctrl); - - m_sumoScene->requestCollisionCallback(*smObject); - } -} - -void SumoPhysicsEnvironment::removeCollisionCallback(PHY_IPhysicsController* ctrl) -{ - // intentionally empty -} - -PHY_IPhysicsController* SumoPhysicsEnvironment::CreateSphereController(float radius,const PHY__Vector3& position) -{ - DT_ShapeHandle shape = DT_NewSphere(0.0); - SM_Object* ob = new SM_Object(shape,0,0,0); - ob->setPosition(MT_Point3(position)); - //testing - MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(90)); - ob->setOrientation(rotquatje); - - PHY_IPhysicsController* ctrl = new SumoPhysicsController(m_sumoScene,ob,0,false); - ctrl->SetMargin(radius); - return ctrl; -} -PHY_IPhysicsController* SumoPhysicsEnvironment::CreateConeController(float coneradius,float coneheight) -{ - DT_ShapeHandle shape = DT_NewCone(coneradius,coneheight); - SM_Object* ob = new SM_Object(shape,0,0,0); - ob->setPosition(MT_Point3(0.f,0.f,0.f)); - MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(90)); - ob->setOrientation(rotquatje); - - PHY_IPhysicsController* ctrl = new SumoPhysicsController(m_sumoScene,ob,0,false); - - return ctrl; -} - diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h deleted file mode 100644 index 65b07a7a0be..00000000000 --- a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * $Id$ - * - * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** - */ -#ifndef _SUMOPhysicsEnvironment -#define _SUMOPhysicsEnvironment - -#include "MT_Scalar.h" - -#include "PHY_IPhysicsEnvironment.h" -class SumoPHYCallbackBridge; -#include <vector> -/** -* Physics Environment takes care of stepping the simulation and is a container for physics entities (rigidbodies,constraints, materials etc.) -* A derived class may be able to 'construct' entities by loading and/or converting -*/ -class SumoPhysicsEnvironment : public PHY_IPhysicsEnvironment -{ - - class SM_Scene* m_sumoScene; - float m_currentTime; - float m_fixedTimeStep; - bool m_useFixedTimeStep; - - std::vector<SumoPHYCallbackBridge*> m_callbacks; - -public: - SumoPhysicsEnvironment(); - virtual ~SumoPhysicsEnvironment(); - virtual void beginFrame(); - virtual void endFrame(); -// Perform an integration step of duration 'timeStep'. - virtual bool proceedDeltaTime(double curTime,float timeStep); - virtual void setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep); - virtual float getFixedTimeStep(); - - virtual void setGravity(float x,float y,float z); - virtual int createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type, - float pivotX,float pivotY,float pivotZ, - float axisX,float axisY,float axisZ, - float axis1X=0,float axis1Y=0,float axis1Z=0, - float axis2X=0,float axis2Y=0,float axis2Z=0,int flag=0 - - ); - - virtual void removeConstraint(int constraintid); - - //complex constraint for vehicles - virtual PHY_IVehicle* getVehicleConstraint(int constraintId) - { - return 0; - } - - virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ); - - - //gamelogic callbacks - virtual void addSensor(PHY_IPhysicsController* ctrl); - virtual void removeSensor(PHY_IPhysicsController* ctrl); - virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user); - virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl); - virtual void removeCollisionCallback(PHY_IPhysicsController* ctrl); - virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position); - virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight); - - virtual void setConstraintParam(int constraintId,int param,float value,float value1) - { - } - SM_Scene* GetSumoScene() - { - return m_sumoScene; - } - -protected: - // 60Hz (Default) - static MT_Scalar PhysicsTicRate; - -}; - -#endif //_SUMOPhysicsEnvironment - diff --git a/source/gameengine/Physics/Sumo/convert.txt b/source/gameengine/Physics/Sumo/convert.txt deleted file mode 100644 index 81f8f602cde..00000000000 --- a/source/gameengine/Physics/Sumo/convert.txt +++ /dev/null @@ -1,35 +0,0 @@ -static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj) -{ - DT_ShapeHandle shape = DT_NewComplexShape(); - int numpolys = meshobj->NumPolygons(); - int numvalidpolys = 0; - - for (int p=0; p<numpolys; p++) - { - RAS_Polygon* poly = meshobj->GetPolygon(p); - - // only add polygons that have the collisionflag set - if (poly->IsCollider()) - { - DT_Begin(); - for (int v=0; v<poly->VertexCount(); v++) { - MT_Point3 pt = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[v], - poly->GetMaterial()->GetPolyMaterial())->xyz(); - DT_Vertex(pt[0],pt[1],pt[2]); - } - DT_End(); - - numvalidpolys++; - } - } - - DT_EndComplexShape(); - - if (numvalidpolys==0) { - delete shape; - return NULL; - } else { - return shape; - } -} diff --git a/source/gameengine/Physics/Sumo/include/interpolator.h b/source/gameengine/Physics/Sumo/include/interpolator.h deleted file mode 100644 index 055c242edc7..00000000000 --- a/source/gameengine/Physics/Sumo/include/interpolator.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef INTERPOLATOR_H -#define INTERPOLATOR_H - -#include "solid_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -DT_DECLARE_HANDLE(IP_IpoHandle); - -typedef struct IP_ControlPoint { - DT_Scalar m_key; - DT_Scalar m_keyValue; -} IP_ControlPoint; - -IP_IpoHandle IP_CreateLinear(const IP_ControlPoint *cpoints, int num_cpoints); - -void IP_DeleteInterpolator(IP_IpoHandle ipo); - -DT_Scalar IP_GetValue(IP_IpoHandle ipo, DT_Scalar key); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/source/gameengine/Physics/common/CMakeLists.txt b/source/gameengine/Physics/common/CMakeLists.txt index a28fabe0c3a..a34bd19d400 100644 --- a/source/gameengine/Physics/common/CMakeLists.txt +++ b/source/gameengine/Physics/common/CMakeLists.txt @@ -24,12 +24,12 @@ # # ***** END GPL LICENSE BLOCK ***** -SET(SRC PHY_IMotionState.cpp PHY_IPhysicsController.cpp PHY_IPhysicsEnvironment.cpp PHY_IVehicle.cpp) +SET(SRC PHY_IMotionState.cpp PHY_IController.cpp PHY_IPhysicsController.cpp PHY_IGraphicController.cpp PHY_IPhysicsEnvironment.cpp PHY_IVehicle.cpp) SET(INC - . - ../Dummy - ../../../intern/moto/include + . + ../Dummy + ../../../intern/moto/include ) BLENDERLIB(bf_common "${SRC}" "${INC}") diff --git a/source/gameengine/Physics/common/Makefile b/source/gameengine/Physics/common/Makefile index e3edd426c36..f87da383520 100644 --- a/source/gameengine/Physics/common/Makefile +++ b/source/gameengine/Physics/common/Makefile @@ -37,10 +37,9 @@ CCFLAGS += $(LEVEL_1_CPP_WARNINGS) CPPFLAGS += -I$(OPENGL_HEADERS) CPPFLAGS += -I$(NAN_STRING)/include -CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) -CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO)/include -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I../../blender # these two needed because of blenkernel CPPFLAGS += -I../../blender/makesdna diff --git a/source/gameengine/Physics/common/PHY_DynamicTypes.h b/source/gameengine/Physics/common/PHY_DynamicTypes.h index 3b3e42c38d2..7ce40001af7 100644 --- a/source/gameengine/Physics/common/PHY_DynamicTypes.h +++ b/source/gameengine/Physics/common/PHY_DynamicTypes.h @@ -19,12 +19,42 @@ subject to the following restrictions: - +struct KX_ClientObjectInfo; class PHY_Shape; struct PHY__Vector3 { float m_vec[4]; + + operator const float* () const + { + return &m_vec[0]; + } + operator float* () + { + return &m_vec[0]; + } +}; + +struct PHY__Vector4 +{ + float m_vec[4]; + PHY__Vector4() {} + void setValue(const float *value) + { + m_vec[0] = *value++; + m_vec[1] = *value++; + m_vec[2] = *value++; + m_vec[3] = *value++; + } + void setValue(const double *value) + { + m_vec[0] = (float)(*value++); + m_vec[1] = (float)(*value++); + m_vec[2] = (float)(*value++); + m_vec[3] = (float)(*value++); + } + operator const float* () const { return &m_vec[0]; @@ -34,9 +64,10 @@ struct PHY__Vector3 return &m_vec[0]; } }; + //typedef float PHY__Vector3[4]; -typedef enum +enum { PHY_FH_RESPONSE, PHY_SENSOR_RESPONSE, /* Touch Sensors */ @@ -59,7 +90,7 @@ typedef enum void *client_object1, void *client_object2, const PHY_CollData *coll_data); - + typedef void (*PHY_CullingCallback)(KX_ClientObjectInfo* info, void* param); /// PHY_PhysicsType enumerates all possible Physics Entities. @@ -95,7 +126,8 @@ typedef enum PHY_ShapeType { PHY_SHAPE_CONE, PHY_SHAPE_MESH, PHY_SHAPE_POLYTOPE, - PHY_SHAPE_COMPOUND + PHY_SHAPE_COMPOUND, + PHY_SHAPE_PROXY } PHY_ShapeType; diff --git a/source/gameengine/Expressions/KX_Python_dynamic.h b/source/gameengine/Physics/common/PHY_IController.cpp index eb435bdf1c3..47fe9a9eea8 100644 --- a/source/gameengine/Expressions/KX_Python_dynamic.h +++ b/source/gameengine/Physics/common/PHY_IController.cpp @@ -26,11 +26,14 @@ * * ***** END GPL LICENSE BLOCK ***** */ -#ifndef KX_PYTHON_H -#define KX_PYTHON_H +#include "PHY_IController.h" -//#define USE_DL_EXPORT -#include "Python.h" +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif -#endif // KX_PYTHON_H +PHY_IController::~PHY_IController() +{ + +} diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_FhObject.h b/source/gameengine/Physics/common/PHY_IController.h index b03612ed15e..a053a9679b8 100644 --- a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_FhObject.h +++ b/source/gameengine/Physics/common/PHY_IController.h @@ -26,31 +26,35 @@ * * ***** END GPL LICENSE BLOCK ***** */ -#ifndef SM_FHOBJECT_H -#define SM_FHOBJECT_H +#ifndef PHY_ICONTROLLER_H +#define PHY_ICONTROLLER_H -#include "SM_Object.h" +#include "PHY_DynamicTypes.h" -class SM_FhObject : public SM_Object { -public: - virtual ~SM_FhObject(); - SM_FhObject(DT_ShapeHandle rayshape, MT_Vector3 ray, SM_Object *parent_object); - - const MT_Vector3& getRay() const { return m_ray; } - MT_Point3 getSpot() const { return getPosition() + m_ray; } - const MT_Vector3& getRayDirection() const { return m_ray_direction; } - SM_Object *getParentObject() const { return m_parent_object; } +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif - static DT_Bool ray_hit(void *client_data, - void *object1, - void *object2, - const DT_CollData *coll_data); +/** + PHY_IController is the abstract simplified Interface to objects + controlled by the physics engine. This includes the physics objects + and the graphics object for view frustrum and occlusion culling. +*/ +class PHY_IController +{ + public: + virtual ~PHY_IController(); + // clientinfo for raycasts for example + virtual void* getNewClientInfo()=0; + virtual void setNewClientInfo(void* clientinfo)=0; -private: - MT_Vector3 m_ray; - MT_Vector3 m_ray_direction; - SM_Object *m_parent_object; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:PHY_IController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; -#endif +#endif //PHY_ICONTROLLER_H diff --git a/source/gameengine/Expressions/KX_Python_static.h b/source/gameengine/Physics/common/PHY_IGraphicController.cpp index f4f31f9b058..4dccecd3d29 100644 --- a/source/gameengine/Expressions/KX_Python_static.h +++ b/source/gameengine/Physics/common/PHY_IGraphicController.cpp @@ -26,11 +26,14 @@ * * ***** END GPL LICENSE BLOCK ***** */ -#ifndef KX_PYTHON_H -#define KX_PYTHON_H +#include "PHY_IGraphicController.h" -#define USE_DL_EXPORT -#include "Python.h" +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif -#endif // KX_PYTHON_H +PHY_IGraphicController::~PHY_IGraphicController() +{ + +} diff --git a/source/gameengine/Physics/common/PHY_IGraphicController.h b/source/gameengine/Physics/common/PHY_IGraphicController.h new file mode 100644 index 00000000000..aae971ff42a --- /dev/null +++ b/source/gameengine/Physics/common/PHY_IGraphicController.h @@ -0,0 +1,62 @@ +/** + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** + */ +#ifndef PHY_IGRAPHICCONTROLLER_H +#define PHY_IGRAPHICCONTROLLER_H + +#include "PHY_IController.h" + + + +/** + PHY_IPhysicsController is the abstract simplified Interface to a physical object. + It contains the IMotionState and IDeformableMesh Interfaces. +*/ +class PHY_IGraphicController : public PHY_IController +{ + public: + virtual ~PHY_IGraphicController(); + /** + SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') + */ + virtual bool SetGraphicTransform()=0; + virtual void Activate(bool active=true)=0; + virtual void setLocalAabb(const PHY__Vector3& aabbMin,const PHY__Vector3& aabbMax)=0; + virtual void setLocalAabb(const float* aabbMin,const float* aabbMax)=0; + + virtual PHY_IGraphicController* GetReplica(class PHY_IMotionState* motionstate) {return 0;} + + +#ifdef WITH_CXX_GUARDEDALLOC + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:PHY_IController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif //PHY_IGRAPHICCONTROLLER_H + diff --git a/source/gameengine/Physics/common/PHY_IMotionState.h b/source/gameengine/Physics/common/PHY_IMotionState.h index d759b0aeff4..c3d01c010ff 100644 --- a/source/gameengine/Physics/common/PHY_IMotionState.h +++ b/source/gameengine/Physics/common/PHY_IMotionState.h @@ -29,6 +29,10 @@ #ifndef PHY__MOTIONSTATE_H #define PHY__MOTIONSTATE_H +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + /** PHY_IMotionState is the Interface to explicitly synchronize the world transformation. Default implementations for mayor graphics libraries like OpenGL and DirectX can be provided. @@ -36,18 +40,28 @@ class PHY_IMotionState { - public: - + public: virtual ~PHY_IMotionState(); virtual void getWorldPosition(float& posX,float& posY,float& posZ)=0; virtual void getWorldScaling(float& scaleX,float& scaleY,float& scaleZ)=0; virtual void getWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal)=0; + // ori = array 12 floats, [0..3] = first column + 0, [4..7] = second colum, [8..11] = third column + virtual void getWorldOrientation(float* ori)=0; + virtual void setWorldOrientation(const float* ori)=0; virtual void setWorldPosition(float posX,float posY,float posZ)=0; virtual void setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal)=0; + virtual void calculateWorldTransformations()=0; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:PHY_IMotionState"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //PHY__MOTIONSTATE_H diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h index 884e14cfb5a..664e5fddd83 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsController.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsController.h @@ -29,19 +29,18 @@ #ifndef PHY_IPHYSICSCONTROLLER_H #define PHY_IPHYSICSCONTROLLER_H -#include "PHY_DynamicTypes.h" - +#include "PHY_IController.h" +class PHY_IMotionState; /** PHY_IPhysicsController is the abstract simplified Interface to a physical object. It contains the IMotionState and IDeformableMesh Interfaces. */ -class PHY_IPhysicsController +class PHY_IPhysicsController : public PHY_IController { public: - virtual ~PHY_IPhysicsController(); /** SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') @@ -53,6 +52,7 @@ class PHY_IPhysicsController virtual void WriteMotionStateToDynamics(bool nondynaonly)=0; virtual void WriteDynamicsToMotionState()=0; + virtual class PHY_IMotionState* GetMotionState() = 0; // controller replication virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl)=0; @@ -82,9 +82,7 @@ class PHY_IPhysicsController // dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted virtual void setRigidBody(bool rigid)=0; - // clientinfo for raycasts for example - virtual void* getNewClientInfo()=0; - virtual void setNewClientInfo(void* clientinfo)=0; + virtual PHY_IPhysicsController* GetReplica() {return 0;} virtual void calcXform() =0; @@ -92,8 +90,19 @@ class PHY_IPhysicsController virtual float GetMargin() const=0; virtual float GetRadius() const=0; virtual void SetRadius(float margin) = 0; + + virtual float GetLinVelocityMin() const=0; + virtual void SetLinVelocityMin(float val) = 0; + virtual float GetLinVelocityMax() const=0; + virtual void SetLinVelocityMax(float val) = 0; + PHY__Vector3 GetWorldPosition(PHY__Vector3& localpos); +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:PHY_IPhysicsController"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //PHY_IPHYSICSCONTROLLER_H diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h index 0e9c571924c..291dac298dc 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h @@ -32,6 +32,11 @@ #include <vector> #include "PHY_DynamicTypes.h" + +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class PHY_IVehicle; class RAS_MeshObject; class PHY_IPhysicsController; @@ -76,6 +81,12 @@ public: m_faceNormal(faceNormal) { } + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:PHY_IRayCastFilterCallback"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; /** @@ -89,7 +100,9 @@ class PHY_IPhysicsEnvironment virtual void beginFrame() = 0; virtual void endFrame() = 0; /// Perform an integration step of duration 'timeStep'. - virtual bool proceedDeltaTime(double curTime,float timeStep)=0; + virtual bool proceedDeltaTime(double curTime,float timeStep,float interval)=0; + ///draw debug lines (make sure to call this during the render phase, otherwise lines are not drawn properly) + virtual void debugDrawWorld(){} virtual void setFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep)=0; //returns 0.f if no fixed timestep is used virtual float getFixedTimeStep()=0; @@ -140,19 +153,31 @@ class PHY_IPhysicsEnvironment virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ)=0; + //culling based on physical broad phase + // the plane number must be set as follow: near, far, left, right, top, botton + // the near plane must be the first one and must always be present, it is used to get the direction of the view + virtual bool cullingTest(PHY_CullingCallback callback, void *userData, PHY__Vector4* planeNormals, int planeNumber, int occlusionRes) = 0; //Methods for gamelogic collision/physics callbacks //todo: virtual void addSensor(PHY_IPhysicsController* ctrl)=0; virtual void removeSensor(PHY_IPhysicsController* ctrl)=0; virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user)=0; - virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl)=0; - virtual void removeCollisionCallback(PHY_IPhysicsController* ctrl)=0; + virtual bool requestCollisionCallback(PHY_IPhysicsController* ctrl)=0; + virtual bool removeCollisionCallback(PHY_IPhysicsController* ctrl)=0; //These two methods are *solely* used to create controllers for sensor! Don't use for anything else virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position) =0; virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight)=0; virtual void setConstraintParam(int constraintId,int param,float value,float value1) = 0; + virtual float getConstraintParam(int constraintId,int param) = 0; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:PHY_IPhysicsEnvironment"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //_IPHYSICSENVIRONMENT diff --git a/source/gameengine/Physics/common/PHY_IVehicle.h b/source/gameengine/Physics/common/PHY_IVehicle.h index 498df0dd840..261bae480f5 100644 --- a/source/gameengine/Physics/common/PHY_IVehicle.h +++ b/source/gameengine/Physics/common/PHY_IVehicle.h @@ -6,10 +6,13 @@ class PHY_IMotionState; #include "PHY_DynamicTypes.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class PHY_IVehicle { public: - virtual ~PHY_IVehicle(); virtual void AddWheel( @@ -52,6 +55,12 @@ public: virtual void SetCoordinateSystem(int rightIndex,int upIndex,int forwardIndex) =0; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:PHY_IVehicle"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //PHY_IVEHICLE_H diff --git a/source/gameengine/Physics/common/PHY_Pro.h b/source/gameengine/Physics/common/PHY_Pro.h index 32e63ac2f6d..0249fc3118a 100644 --- a/source/gameengine/Physics/common/PHY_Pro.h +++ b/source/gameengine/Physics/common/PHY_Pro.h @@ -35,9 +35,11 @@ struct PHY_ShapeProps { MT_Scalar m_mass; // Total mass MT_Scalar m_inertia; // Inertia, should be a tensor some time - MT_Scalar m_lin_drag; // Linear drag (air, water) 0 = concrete, 1 = vacuum - MT_Scalar m_ang_drag; // Angular drag + MT_Scalar m_lin_drag; // Linear drag (air, water) 0 = concrete, 1 = vacuum, inverted and called dampening in blenders UI + MT_Scalar m_ang_drag; // Angular drag, inverted and called dampening in blenders UI MT_Scalar m_friction_scaling[3]; // Scaling for anisotropic friction. Component in range [0, 1] + MT_Scalar m_clamp_vel_min; // Clamp the minimum velocity, this ensures an object moves at a minimum speed unless its stationary + MT_Scalar m_clamp_vel_max; // Clamp max velocity bool m_do_anisotropic; // Should I do anisotropic friction? bool m_do_fh; // Should the object have a linear Fh spring? bool m_do_rot_fh; // Should the object have an angular Fh spring? diff --git a/source/gameengine/Physics/common/SConscript b/source/gameengine/Physics/common/SConscript index 91c5101675e..719c028ee8f 100644 --- a/source/gameengine/Physics/common/SConscript +++ b/source/gameengine/Physics/common/SConscript @@ -1,8 +1,8 @@ #!/usr/bin/python Import ('env') -sources = 'PHY_IMotionState.cpp PHY_IPhysicsController.cpp PHY_IPhysicsEnvironment.cpp PHY_IVehicle.cpp' +sources = 'PHY_IMotionState.cpp PHY_IController.cpp PHY_IPhysicsController.cpp PHY_IGraphicController.cpp PHY_IPhysicsEnvironment.cpp PHY_IVehicle.cpp' incs = '. ../Dummy #intern/moto/include' -env.BlenderLib ( 'bf_common', Split(sources), Split(incs), [], libtype=['game', 'game2','player'], priority=[20, 35, 95] ) +env.BlenderLib ( 'bf_physics_common', Split(sources), Split(incs), [], libtype=['core','player'], priority=[360,55], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/PyDoc/API_intro.py b/source/gameengine/PyDoc/API_intro.py new file mode 100644 index 00000000000..0a687088627 --- /dev/null +++ b/source/gameengine/PyDoc/API_intro.py @@ -0,0 +1,110 @@ +# This is not a real module, it's simply an introductory text. + +""" +The Blender Game Engine Python API Reference +============================================ + + See U{release notes<http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.49/Game_Engine>} for updates, changes and new functionality in the Game Engine Python API. + + Blender Game Engine Modules: + ---------------------------- + + Modules that include methods for accessing GameEngine data and functions. + + - L{GameLogic} utility functons for game logic. + - L{GameKeys} keyboard input and event conversion. + - L{Rasterizer} display and rendering. + - L{GameTypes} contains all the python types spesific to the GameEngine. + + Undocumented modules: + --------------------- + - VideoTexture + - PhysicsConstraints + + Additional Modules: + ------------------- + + These modules have no GameEngine specific functionality but are useful in many cases. + + - L{Mathutils} + - L{Geometry} + - L{BGL} + + +Introduction: +============= + + This reference documents the Blender Python API, a growing collection of + Python modules (libraries) that give access to part of the program's internal + data and functions. + + Through scripting Blender can be extended in real-time via + U{Python <www.python.org>}, an impressive high level, multi-paradigm, open + source language. Newcomers are recommended to start with the tutorial that + comes with it. + + This opens many interesting possibilities not available with logic bricks. + + Game Engine API Stability: + -------------------------- + + When writing python scripts there are a number of situations you should avoid to prevent crashes or unstable behavior. + While the API tries to prevent problems there are some situations where error checking would be too time consuming. + + Known cases: + - Memory Limits. + + There is nothing stopping you from filling a list or making a string so big that that causes blender to run out of memory, in this case python should rasie a MemoryError, but its likely blender will crash before this point. + + - Accessing any data that has been freed. + + For instance accessing a KX_GameObject after its End Object actuator runs. + This will cause a SystemError, however for L{KX_MeshProxy}, L{KX_VertexProxy} and L{KX_VertexProxy} it will crash the blender game engine. + + See: L{GameTypes.PyObjectPlus.invalid} which many types inherit. + + - Mixing L{KX_GameObject} between scenes. + + For instance tracking/parenting an L{KX_GameObject} object to an object from other scene. + + External Modules: + ----------------- + + Since 2.49 support for importing modules has been added. + + This allows you to import any blender textblock with a .py extension. + + External python scripts may be imported as modules when the script is in the same directory as the blend file. + + The current blend files path is included in the sys.path for loading modules. + All linked libraries will also be included so you can be sure when linking in assets from another blend file the scripts will load too. + + A note to newbie script writers: + -------------------------------- + + Interpreted languages are known to be much slower than compiled code, but for + many applications the difference is negligible or acceptable. Also, with + profiling (or even simple direct timing with L{Blender.sys.time<Sys.time>}) to + identify slow areas and well thought optimizations, the speed can be + I{considerably} improved in many cases. Try some of the best BPython scripts + to get an idea of what can be done, you may be surprised. + +@author: The Blender Python Team +@requires: Blender 2.49 or newer. +@version: 2.49 +@see: U{www.blender.org<http://www.blender.org>}: documentation and forum +@see: U{blenderartists.org<http://blenderartists.org>}: user forum +@see: U{projects.blender.org<http://projects.blender.org>} +@see: U{www.python.org<http://www.python.org>} +@see: U{www.python.org/doc<http://www.python.org/doc>} +@see: U{Blending into Python<en.wikibooks.org/wiki/Blender_3D:_Blending_Into_Python>}: User contributed documentation, featuring a blender/python cookbook with many examples. + +@note: the official version of this reference guide is only updated for each + new Blender release. But you can build the current SVN + version yourself: install epydoc, grab all files in the + source/gameengine/PyDoc/ folder of Blender's SVN and use the + epy_docgen.sh script also found there to generate the html docs. + Naturally you will also need a recent Blender binary to try the new + features. If you prefer not to compile it yourself, there is a testing + builds forum at U{blender.org<http://www.blender.org>}. +""" diff --git a/source/gameengine/PyDoc/BL_ActionActuator.py b/source/gameengine/PyDoc/BL_ActionActuator.py deleted file mode 100644 index b68d3014115..00000000000 --- a/source/gameengine/PyDoc/BL_ActionActuator.py +++ /dev/null @@ -1,177 +0,0 @@ -# $Id$ -# Documentation for BL_ActionActuator -from SCA_IActuator import * - -class BL_ActionActuator(SCA_IActuator): - """ - Action Actuators apply an action to an actor. - """ - def setAction(action, reset = True): - """ - Sets the current action. - - @param action: The name of the action to set as the current action. - @type action: string - @param reset: Optional parameter indicating whether to reset the - blend timer or not. A value of 1 indicates that the - timer should be reset. A value of 0 will leave it - unchanged. If reset is not specified, the timer will - be reset. - """ - - def setStart(start): - """ - Specifies the starting frame of the animation. - - @param start: the starting frame of the animation - @type start: float - """ - - def setEnd(end): - """ - Specifies the ending frame of the animation. - - @param end: the ending frame of the animation - @type end: float - """ - def setBlendin(blendin): - """ - Specifies the number of frames of animation to generate - when making transitions between actions. - - @param blendin: the number of frames in transition. - @type blendin: float - """ - - def setPriority(priority): - """ - Sets the priority of this actuator. - - @param priority: Specifies the new priority. Actuators will lower - priority numbers will override actuators with higher - numbers. - @type priority: integer - """ - def setFrame(frame): - """ - Sets the current frame for the animation. - - @param frame: Specifies the new current frame for the animation - @type frame: float - """ - - def setProperty(prop): - """ - Sets the property to be used in FromProp playback mode. - - @param prop: the name of the property to use. - @type prop: string. - """ - - def setBlendtime(blendtime): - """ - Sets the internal frame timer. - - Allows the script to directly modify the internal timer - used when generating transitions between actions. - - @param blendtime: The new time. This parameter must be in the range from 0.0 to 1.0. - @type blendtime: float - """ - - def setType(mode): - """ - Sets the operation mode of the actuator - - @param mode: KX_ACTIONACT_PLAY, KX_ACTIONACT_PROPERTY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND - @type mode: integer - """ - - def setContinue(cont): - """ - Set the actions continue option True or False. see getContinue. - - @param cont: The continue option. - @type cont: bool - """ - - def getType(): - """ - Returns the operation mode of the actuator - - @rtype: integer - @return: KX_ACTIONACT_PLAY, KX_ACTIONACT_PROPERTY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND - """ - - def getContinue(): - """ - When True, the action will always play from where last left off, otherwise negative events to this actuator will reset it to its start frame. - - @rtype: bool - """ - - def getAction(): - """ - getAction() returns the name of the action associated with this actuator. - - @rtype: string - """ - - def getStart(): - """ - Returns the starting frame of the action. - - @rtype: float - """ - def getEnd(): - """ - Returns the last frame of the action. - - @rtype: float - """ - def getBlendin(): - """ - Returns the number of interpolation animation frames to be generated when this actuator is triggered. - - @rtype: float - """ - def getPriority(): - """ - Returns the priority for this actuator. Actuators with lower Priority numbers will - override actuators with higher numbers. - - @rtype: integer - """ - def getFrame(): - """ - Returns the current frame number. - - @rtype: float - """ - def getProperty(): - """ - Returns the name of the property to be used in FromProp mode. - - @rtype: string - """ - def setChannel(channel, matrix, mode = False): - """ - @param channel: A string specifying the name of the bone channel. - @type channel: string - @param matrix: A 4x4 matrix specifying the overriding transformation - as an offset from the bone's rest position. - @type matrix: list [[float]] - @param mode: True for armature/world space, False for bone space - @type mode: boolean - """ - def setFrameProperty(prop): - """ - @param prop: A string specifying the property of the object that will be updated with the action frame number. - @type prop: string - """ - def getFrameProperty(): - """ - Returns the name of the property that is set to the current frame number. - - @rtype: string - """ diff --git a/source/gameengine/PyDoc/BL_ShapeActionActuator.py b/source/gameengine/PyDoc/BL_ShapeActionActuator.py deleted file mode 100644 index a26b276a2da..00000000000 --- a/source/gameengine/PyDoc/BL_ShapeActionActuator.py +++ /dev/null @@ -1,167 +0,0 @@ -# $Id$ -# Documentation for BL_ShapeActionActuator -from SCA_IActuator import * - -class BL_ShapeActionActuator(SCA_IActuator): - """ - ShapeAction Actuators apply an shape action to an mesh object. - """ - def setAction(action, reset = True): - """ - Sets the current action. - - @param action: The name of the action to set as the current action. - @type action: string - @param reset: Optional parameter indicating whether to reset the - blend timer or not. A value of 1 indicates that the - timer should be reset. A value of 0 will leave it - unchanged. If reset is not specified, the timer will - be reset. - """ - - def setStart(start): - """ - Specifies the starting frame of the animation. - - @param start: the starting frame of the animation - @type start: float - """ - - def setEnd(end): - """ - Specifies the ending frame of the animation. - - @param end: the ending frame of the animation - @type end: float - """ - def setBlendin(blendin): - """ - Specifies the number of frames of animation to generate - when making transitions between actions. - - @param blendin: the number of frames in transition. - @type blendin: float - """ - - def setPriority(priority): - """ - Sets the priority of this actuator. - - @param priority: Specifies the new priority. Actuators will lower - priority numbers will override actuators with higher - numbers. - @type priority: integer - """ - def setFrame(frame): - """ - Sets the current frame for the animation. - - @param frame: Specifies the new current frame for the animation - @type frame: float - """ - - def setProperty(prop): - """ - Sets the property to be used in FromProp playback mode. - - @param prop: the name of the property to use. - @type prop: string. - """ - - def setBlendtime(blendtime): - """ - Sets the internal frame timer. - - Allows the script to directly modify the internal timer - used when generating transitions between actions. - - @param blendtime: The new time. This parameter must be in the range from 0.0 to 1.0. - @type blendtime: float - """ - - def setType(mode): - """ - Sets the operation mode of the actuator - - @param mode: KX_ACTIONACT_PLAY, KX_ACTIONACT_PROPERTY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND - @type mode: integer - """ - - def setContinue(cont): - """ - Set the actions continue option True or False. see getContinue. - - @param cont: The continue option. - @type cont: bool - """ - - def getType(): - """ - Returns the operation mode of the actuator - - @rtype: integer - @return: KX_ACTIONACT_PLAY, KX_ACTIONACT_PROPERTY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND - """ - - def getContinue(): - """ - When True, the action will always play from where last left off, otherwise negative events to this actuator will reset it to its start frame. - - @rtype: bool - """ - - def getAction(): - """ - getAction() returns the name of the action associated with this actuator. - - @rtype: string - """ - - def getStart(): - """ - Returns the starting frame of the action. - - @rtype: float - """ - def getEnd(): - """ - Returns the last frame of the action. - - @rtype: float - """ - def getBlendin(): - """ - Returns the number of interpolation animation frames to be generated when this actuator is triggered. - - @rtype: float - """ - def getPriority(): - """ - Returns the priority for this actuator. Actuators with lower Priority numbers will - override actuators with higher numbers. - - @rtype: integer - """ - def getFrame(): - """ - Returns the current frame number. - - @rtype: float - """ - def getProperty(): - """ - Returns the name of the property to be used in FromProp mode. - - @rtype: string - """ - def setFrameProperty(prop): - """ - @param prop: A string specifying the property of the object that will be updated with the action frame number. - @type prop: string - """ - def getFrameProperty(): - """ - Returns the name of the property that is set to the current frame number. - - @rtype: string - """ diff --git a/source/gameengine/PyDoc/GameKeys.py b/source/gameengine/PyDoc/GameKeys.py index 1a0a737718e..e798f6c901b 100644 --- a/source/gameengine/PyDoc/GameKeys.py +++ b/source/gameengine/PyDoc/GameKeys.py @@ -5,126 +5,6 @@ Documentation for the GameKeys module. This module holds key constants for the SCA_KeyboardSensor. -Alphabet keys -------------- - - AKEY - - BKEY - - CKEY - - DKEY - - EKEY - - FKEY - - GKEY - - HKEY - - IKEY - - JKEY - - KKEY - - LKEY - - MKEY - - NKEY - - OKEY - - PKEY - - QKEY - - RKEY - - SKEY - - TKEY - - UKEY - - VKEY - - WKEY - - XKEY - - YKEY - - ZKEY - -Number keys ------------ - - ZEROKEY - - ONEKEY - - TWOKEY - - THREEKEY - - FOURKEY - - FIVEKEY - - SIXKEY - - SEVENKEY - - EIGHTKEY - - NINEKEY - -Shift Modifiers ---------------- - - CAPSLOCKKEY - - - LEFTCTRLKEY - - LEFTALTKEY - - RIGHTALTKEY - - RIGHTCTRLKEY - - RIGHTSHIFTKEY - - LEFTSHIFTKEY - -Arrow Keys ----------- - - LEFTARROWKEY - - DOWNARROWKEY - - RIGHTARROWKEY - - UPARROWKEY - -Numberpad Keys --------------- - - PAD0 - - PAD1 - - PAD2 - - PAD3 - - PAD4 - - PAD5 - - PAD6 - - PAD7 - - PAD8 - - PAD9 - - PADPERIOD - - PADSLASHKEY - - PADASTERKEY - - PADMINUS - - PADENTER - - PADPLUSKEY - -Function Keys -------------- - - F1KEY - - F2KEY - - F3KEY - - F4KEY - - F5KEY - - F6KEY - - F7KEY - - F8KEY - - F9KEY - - F10KEY - - F11KEY - - F12KEY - -Other Keys ----------- - - ACCENTGRAVEKEY - - BACKSLASHKEY - - BACKSPACEKEY - - COMMAKEY - - DELKEY - - ENDKEY - - EQUALKEY - - ESCKEY - - HOMEKEY - - INSERTKEY - - LEFTBRACKETKEY - - LINEFEEDKEY - - MINUSKEY - - PAGEDOWNKEY - - PAGEUPKEY - - PAUSEKEY - - PERIODKEY - - QUOTEKEY - - RIGHTBRACKETKEY - - RETKEY - - SEMICOLONKEY - - SLASHKEY - - SPACEKEY - - TABKEY Example:: # Set a connected keyboard sensor to accept F1 @@ -134,26 +14,20 @@ Example:: co = GameLogic.getCurrentController() # 'Keyboard' is a keyboard sensor sensor = co.getSensor('Keyboard') - sensor.setKey(GameKeys.F1KEY) + sensor.key = GameKeys.F1KEY Example:: # Do the all keys thing import GameLogic import GameKeys - - # status: these should be added to a module somewhere - KX_NO_INPUTSTATUS = 0 - KX_JUSTACTIVATED = 1 - KX_ACTIVE = 2 - KX_JUSTRELEASED = 3 - + co = GameLogic.getCurrentController() # 'Keyboard' is a keyboard sensor sensor = co.getSensor('Keyboard') - keylist = sensor.getPressedKeys() + keylist = sensor.events for key in keylist: # key[0] == GameKeys.keycode, key[1] = status - if key[1] == KX_JUSTACTIVATED: + if key[1] == GameLogic.KX_INPUT_JUST_ACTIVATED: if key[0] == GameKeys.WKEY: # Activate Forward! if key[0] == GameKeys.SKEY: @@ -162,7 +36,120 @@ Example:: # Activate Left! if key[0] == GameKeys.DKEY: # Activate Right! - + +@group Alphabet keys: AKEY, BKEY, CKEY, DKEY, EKEY, FKEY, GKEY, HKEY, IKEY, JKEY, KKEY, LKEY, MKEY, NKEY, OKEY, PKEY, QKEY, RKEY, SKEY, TKEY, UKEY, VKEY, WKEY, XKEY, YKEY, ZKEY +@var AKEY: +@var BKEY: +@var CKEY: +@var DKEY: +@var EKEY: +@var FKEY: +@var GKEY: +@var HKEY: +@var IKEY: +@var JKEY: +@var KKEY: +@var LKEY: +@var MKEY: +@var NKEY: +@var OKEY: +@var PKEY: +@var QKEY: +@var RKEY: +@var SKEY: +@var TKEY: +@var UKEY: +@var VKEY: +@var WKEY: +@var XKEY: +@var YKEY: +@var ZKEY: + +@group Number keys: ZEROKEY, ONEKEY, TWOKEY, THREEKEY, FOURKEY, FIVEKEY, SIXKEY, SEVENKEY, EIGHTKEY, NINEKEY +@var ZEROKEY: +@var ONEKEY: +@var TWOKEY: +@var THREEKEY: +@var FOURKEY: +@var FIVEKEY: +@var SIXKEY: +@var SEVENKEY: +@var EIGHTKEY: +@var NINEKEY: + +@group Modifiers: CAPSLOCKKEY, LEFTCTRLKEY, LEFTALTKEY, RIGHTALTKEY, RIGHTCTRLKEY, RIGHTSHIFTKEY, LEFTSHIFTKEY +@var CAPSLOCKKEY: +@var LEFTCTRLKEY: +@var LEFTALTKEY: +@var RIGHTALTKEY: +@var RIGHTCTRLKEY: +@var RIGHTSHIFTKEY: +@var LEFTSHIFTKEY: + +@group Arrow Keys: LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY +@var LEFTARROWKEY: +@var DOWNARROWKEY: +@var RIGHTARROWKEY: +@var UPARROWKEY: + +@group Numberpad Keys: PAD0, PAD1, PAD2, PAD3, PAD4, PAD5, PAD6, PAD7, PAD8, PAD9, PADPERIOD, PADSLASHKEY, PADASTERKEY, PADMINUS, PADENTER, PADPLUSKEY +@var PAD0: +@var PAD1: +@var PAD2: +@var PAD3: +@var PAD4: +@var PAD5: +@var PAD6: +@var PAD7: +@var PAD8: +@var PAD9: +@var PADPERIOD: +@var PADSLASHKEY: +@var PADASTERKEY: +@var PADMINUS: +@var PADENTER: +@var PADPLUSKEY: + +@group Function Keys: F1KEY, F2KEY, F3KEY, F4KEY, F5KEY, F6KEY, F7KEY, F8KEY, F9KEY, F10KEY, F11KEY, F12KEY +@var F1KEY: +@var F2KEY: +@var F3KEY: +@var F4KEY: +@var F5KEY: +@var F6KEY: +@var F7KEY: +@var F8KEY: +@var F9KEY: +@var F10KEY: +@var F11KEY: +@var F12KEY: + +@group Other Keys: ACCENTGRAVEKEY, BACKSLASHKEY, BACKSPACEKEY, COMMAKEY, DELKEY, ENDKEY, EQUALKEY, ESCKEY, HOMEKEY, INSERTKEY, LEFTBRACKETKEY, LINEFEEDKEY, MINUSKEY, PAGEDOWNKEY, PAGEUPKEY, PAUSEKEY, PERIODKEY, QUOTEKEY, RIGHTBRACKETKEY, RETKEY, SEMICOLONKEY, SLASHKEY, SPACEKEY, TABKEY +@var ACCENTGRAVEKEY: +@var BACKSLASHKEY: +@var BACKSPACEKEY: +@var COMMAKEY: +@var DELKEY: +@var ENDKEY: +@var EQUALKEY: +@var ESCKEY: +@var HOMEKEY: +@var INSERTKEY: +@var LEFTBRACKETKEY: +@var LINEFEEDKEY: +@var MINUSKEY: +@var PAGEDOWNKEY: +@var PAGEUPKEY: +@var PAUSEKEY: +@var PERIODKEY: +@var QUOTEKEY: +@var RIGHTBRACKETKEY: +@var RETKEY: +@var SEMICOLONKEY: +@var SLASHKEY: +@var SPACEKEY: +@var TABKEY: + """ def EventToString(event): @@ -173,3 +160,15 @@ def EventToString(event): @param event: key event from GameKeys or the keyboard sensor. @rtype: string """ + +def EventToCharacter(event, shift): + """ + Return the string name of a key event. Returns an empty string if the event cant be represented as a character. + + @type event: int + @param event: key event from GameKeys or the keyboard sensor. + @type shift: bool + @param shift: set to true if shift is held. + @rtype: string + """ + diff --git a/source/gameengine/PyDoc/GameLogic.py b/source/gameengine/PyDoc/GameLogic.py index 9dab7db6081..d22b1690e74 100644 --- a/source/gameengine/PyDoc/GameLogic.py +++ b/source/gameengine/PyDoc/GameLogic.py @@ -2,77 +2,74 @@ """ Documentation for the GameLogic Module. ======================================= - - There are only three importable modules in the game engine: - - GameLogic - - L{GameKeys} - - L{Rasterizer} - - All the other modules are accessible through the methods in GameLogic. - See L{WhatsNew} for updates, changes and new functionality in the Game Engine Python API. + Module to access logic functions, imported automatically into the python controllers namespace. Examples:: # To get the controller thats running this python script: - co = GameLogic.getCurrentController() # GameLogic is automatically imported + cont = GameLogic.getCurrentController() # GameLogic is automatically imported # To get the game object this controller is on: - obj = co.getOwner() - L{KX_GameObject} and L{KX_Camera} or L{KX_Light} methods are + obj = cont.owner + L{KX_GameObject} and L{KX_Camera} or L{KX_LightObject} methods are available depending on the type of object:: # To get a sensor linked to this controller. # "sensorname" is the name of the sensor as defined in the Blender interface. # +---------------------+ +--------+ # | Sensor "sensorname" +--+ Python + # +---------------------+ +--------+ - sens = co.getSensor("sensorname") + sens = cont.sensors["sensorname"] - # To get a list of all sensors: - sensors = co.getSensors() + # To get a sequence of all sensors: + sensors = co.sensors See the sensor's reference for available methods: - - L{DelaySensor<SCA_DelaySensor.SCA_DelaySensor>} - - L{JoystickSensor<SCA_JoystickSensor.SCA_JoystickSensor>} - - L{KeyboardSensor<SCA_KeyboardSensor.SCA_KeyboardSensor>} - - L{MouseFocusSensor<KX_MouseFocusSensor.KX_MouseFocusSensor>} - - L{MouseSensor<SCA_MouseSensor.SCA_MouseSensor>} - - L{NearSensor<KX_NearSensor.KX_NearSensor>} - - L{NetworkMessageSensor<KX_NetworkMessageSensor.KX_NetworkMessageSensor>} - - L{PropertySensor<SCA_PropertySensor.SCA_PropertySensor>} - - L{RadarSensor<KX_RadarSensor.KX_RadarSensor>} - - L{RandomSensor<SCA_RandomSensor.SCA_RandomSensor>} - - L{RaySensor<KX_RaySensor.KX_RaySensor>} - - L{TouchSensor<KX_TouchSensor.KX_TouchSensor>} + - L{DelaySensor<GameTypes.SCA_DelaySensor>} + - L{JoystickSensor<GameTypes.SCA_JoystickSensor>} + - L{KeyboardSensor<GameTypes.SCA_KeyboardSensor>} + - L{MouseFocusSensor<GameTypes.KX_MouseFocusSensor>} + - L{MouseSensor<GameTypes.SCA_MouseSensor>} + - L{NearSensor<GameTypes.KX_NearSensor>} + - L{NetworkMessageSensor<GameTypes.KX_NetworkMessageSensor>} + - L{PropertySensor<GameTypes.SCA_PropertySensor>} + - L{RadarSensor<GameTypes.KX_RadarSensor>} + - L{RandomSensor<GameTypes.SCA_RandomSensor>} + - L{RaySensor<GameTypes.KX_RaySensor>} + - L{TouchSensor<GameTypes.KX_TouchSensor>} You can also access actuators linked to the controller:: # To get an actuator attached to the controller: # +--------+ +-------------------------+ # + Python +--+ Actuator "actuatorname" | # +--------+ +-------------------------+ - actuator = co.getActuator("actuatorname") + actuator = co.actuators["actuatorname"] # Activate an actuator - GameLogic.addActiveActuator(actuator, True) + controller.activate(actuator) See the actuator's reference for available methods: - - L{ActionActuator<BL_ActionActuator.BL_ActionActuator>} - - L{AddObjectActuator<KX_SCA_AddObjectActuator.KX_SCA_AddObjectActuator>} - - L{CameraActuator<KX_CameraActuator.KX_CameraActuator>} - - L{CDActuator<KX_CDActuator.KX_CDActuator>} - - L{ConstraintActuator<KX_ConstraintActuator.KX_ConstraintActuator>} - - L{EndObjectActuator<KX_SCA_EndObjectActuator.KX_SCA_EndObjectActuator>} - - L{GameActuator<KX_GameActuator.KX_GameActuator>} - - L{IpoActuator<KX_IpoActuator.KX_IpoActuator>} - - L{NetworkMessageActuator<KX_NetworkMessageActuator.KX_NetworkMessageActuator>} - - L{ObjectActuator<KX_ObjectActuator.KX_ObjectActuator>} - - L{PropertyActuator<SCA_PropertyActuator.SCA_PropertyActuator>} - - L{RandomActuator<SCA_RandomActuator.SCA_RandomActuator>} - - L{ReplaceMeshActuator<KX_SCA_ReplaceMeshActuator.KX_SCA_ReplaceMeshActuator>} - - L{SceneActuator<KX_SceneActuator.KX_SceneActuator>} - - L{SoundActuator<KX_SoundActuator.KX_SoundActuator>} - - L{TrackToActuator<KX_TrackToActuator.KX_TrackToActuator>} - - L{VisibilityActuator<KX_VisibilityActuator.KX_VisibilityActuator>} - + - L{2DFilterActuator<GameTypes.SCA_2DFilterActuator>} + - L{ActionActuator<GameTypes.BL_ActionActuator>} + - L{AddObjectActuator<GameTypes.KX_SCA_AddObjectActuator>} + - L{CameraActuator<GameTypes.KX_CameraActuator>} + - L{ConstraintActuator<GameTypes.KX_ConstraintActuator>} + - L{DynamicActuator<GameTypes.KX_SCA_DynamicActuator>} + - L{EndObjectActuator<GameTypes.KX_SCA_EndObjectActuator>} + - L{GameActuator<GameTypes.KX_GameActuator>} + - L{IpoActuator<GameTypes.KX_IpoActuator>} + - L{NetworkMessageActuator<GameTypes.KX_NetworkMessageActuator>} + - L{ObjectActuator<GameTypes.KX_ObjectActuator>} + - L{ParentActuator<GameTypes.KX_ParentActuator>} + - L{PropertyActuator<GameTypes.SCA_PropertyActuator>} + - L{RandomActuator<GameTypes.SCA_RandomActuator>} + - L{ReplaceMeshActuator<GameTypes.KX_SCA_ReplaceMeshActuator>} + - L{SceneActuator<GameTypes.KX_SceneActuator>} + - L{ShapeActionActuator<GameTypes.BL_ShapeActionActuator>} + - L{SoundActuator<GameTypes.KX_SoundActuator>} + - L{StateActuator<GameTypes.KX_StateActuator>} + - L{TrackToActuator<GameTypes.KX_TrackToActuator>} + - L{VisibilityActuator<GameTypes.KX_VisibilityActuator>} + Most logic brick's methods are accessors for the properties available in the logic buttons. Consult the logic bricks documentation for more information on how each logic brick works. @@ -84,7 +81,7 @@ Documentation for the GameLogic Module. cam = scene.active_camera Matricies as used by the game engine are B{row major}:: - matrix[row][col] = blah + matrix[row][col] = float L{KX_Camera} has some examples using matricies. @@ -92,29 +89,37 @@ Documentation for the GameLogic Module. @var KX_TRUE: True value used by some modules. @var KX_FALSE: False value used by some modules. -@group Property Sensor: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL, KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED, KX_PROPSENSOR_EXPRESSION +@group Property Sensor: KX_PROPSENSOR_* @var KX_PROPSENSOR_EQUAL: Activate when the property is equal to the sensor value. @var KX_PROPSENSOR_NOTEQUAL: Activate when the property is not equal to the sensor value. @var KX_PROPSENSOR_INTERVAL: Activate when the property is between the specified limits. @var KX_PROPSENSOR_CHANGED: Activate when the property changes @var KX_PROPSENSOR_EXPRESSION: Activate when the expression matches -@group Constraint Actuator: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY, KX_CONSTRAINTACT_LOCZ, KX_CONSTRAINTACT_ROTX, KX_CONSTRAINTACT_ROTY, KX_CONSTRAINTACT_ROTZ +@group Constraint Actuator: KX_CONSTRAINTACT_* @var KX_CONSTRAINTACT_LOCX: See L{KX_ConstraintActuator} @var KX_CONSTRAINTACT_LOCY: See L{KX_ConstraintActuator} @var KX_CONSTRAINTACT_LOCZ: See L{KX_ConstraintActuator} @var KX_CONSTRAINTACT_ROTX: See L{KX_ConstraintActuator} @var KX_CONSTRAINTACT_ROTY: See L{KX_ConstraintActuator} @var KX_CONSTRAINTACT_ROTZ: See L{KX_ConstraintActuator} +@var KX_CONSTRAINTACT_DIRNX: See L{KX_ConstraintActuator} +@var KX_CONSTRAINTACT_DIRNY: See L{KX_ConstraintActuator} +@var KX_CONSTRAINTACT_DIRPX: See L{KX_ConstraintActuator} +@var KX_CONSTRAINTACT_DIRPY: See L{KX_ConstraintActuator} +@var KX_CONSTRAINTACT_ORIX: See L{KX_ConstraintActuator} +@var KX_CONSTRAINTACT_ORIY: See L{KX_ConstraintActuator} +@var KX_CONSTRAINTACT_ORIZ: See L{KX_ConstraintActuator} -@group IPO Actuator: KX_IPOACT_PLAY, KX_IPOACT_PINGPONG, KX_IPOACT_FLIPPER, KX_IPOACT_LOOPSTOP, KX_IPOACT_LOOPEND +@group IPO Actuator: KX_IPOACT_* @var KX_IPOACT_PLAY: See L{KX_IpoActuator} @var KX_IPOACT_PINGPONG: See L{KX_IpoActuator} @var KX_IPOACT_FLIPPER: See L{KX_IpoActuator} @var KX_IPOACT_LOOPSTOP: See L{KX_IpoActuator} @var KX_IPOACT_LOOPEND: See L{KX_IpoActuator} +@var KX_IPOACT_FROM_PROP: See L{KX_IpoActuator} -@group Random Distributions: KX_RANDOMACT_BOOL_CONST, KX_RANDOMACT_BOOL_UNIFORM, KX_RANDOMACT_BOOL_BERNOUILLI, KX_RANDOMACT_INT_CONST, KX_RANDOMACT_INT_UNIFORM, KX_RANDOMACT_INT_POISSON, KX_RANDOMACT_FLOAT_CONST, KX_RANDOMACT_FLOAT_UNIFORM, KX_RANDOMACT_FLOAT_NORMAL, KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL +@group Random Distributions: KX_RANDOMACT_* @var KX_RANDOMACT_BOOL_CONST: See L{SCA_RandomActuator} @var KX_RANDOMACT_BOOL_UNIFORM: See L{SCA_RandomActuator} @var KX_RANDOMACT_BOOL_BERNOUILLI: See L{SCA_RandomActuator} @@ -126,22 +131,190 @@ Documentation for the GameLogic Module. @var KX_RANDOMACT_FLOAT_NORMAL: See L{SCA_RandomActuator} @var KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL: See L{SCA_RandomActuator} -@group Action Actuator: KX_ACTIONACT_PLAY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND, KX_ACTIONACT_PROPERTY +@group Action Actuator: KX_ACTIONACT_* @var KX_ACTIONACT_PLAY: See L{BL_ActionActuator} @var KX_ACTIONACT_FLIPPER: See L{BL_ActionActuator} @var KX_ACTIONACT_LOOPSTOP: See L{BL_ActionActuator} @var KX_ACTIONACT_LOOPEND: See L{BL_ActionActuator} @var KX_ACTIONACT_PROPERTY: See L{BL_ActionActuator} -@group Sound Actuator: KX_SOUNDACT_PLAYSTOP, KX_SOUNDACT_PLAYEND, KX_SOUNDACT_LOOPSTOP, KX_SOUNDACT_LOOPEND, KX_SOUNDACT_LOOPBIDIRECTIONAL, KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP +@group Sound Actuator: KX_SOUNDACT_* @var KX_SOUNDACT_PLAYSTOP: See L{KX_SoundActuator} @var KX_SOUNDACT_PLAYEND: See L{KX_SoundActuator} @var KX_SOUNDACT_LOOPSTOP: See L{KX_SoundActuator} @var KX_SOUNDACT_LOOPEND: See L{KX_SoundActuator} @var KX_SOUNDACT_LOOPBIDIRECTIONAL: See L{KX_SoundActuator} @var KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: See L{KX_SoundActuator} + +@group Radar Sensor: KX_RADAR_* +@var KX_RADAR_AXIS_POS_X: See L{KX_RadarSensor} +@var KX_RADAR_AXIS_POS_Y: See L{KX_RadarSensor} +@var KX_RADAR_AXIS_POS_Z: See L{KX_RadarSensor} +@var KX_RADAR_AXIS_NEG_X: See L{KX_RadarSensor} +@var KX_RADAR_AXIS_NEG_Y: See L{KX_RadarSensor} +@var KX_RADAR_AXIS_NEG_Z: See L{KX_RadarSensor} + +@group Ray Sensor: KX_RAY_* +@var KX_RAY_AXIS_POS_X: See L{KX_RaySensor} +@var KX_RAY_AXIS_POS_Y: See L{KX_RaySensor} +@var KX_RAY_AXIS_POS_Z: See L{KX_RaySensor} +@var KX_RAY_AXIS_NEG_X: See L{KX_RaySensor} +@var KX_RAY_AXIS_NEG_Y: See L{KX_RaySensor} +@var KX_RAY_AXIS_NEG_Z: See L{KX_RaySensor} + +@group Dynamic Actuator: KX_DYN_* +@var KX_DYN_RESTORE_DYNAMICS: See L{KX_SCA_DynamicActuator} +@var KX_DYN_DISABLE_DYNAMICS: See L{KX_SCA_DynamicActuator} +@var KX_DYN_ENABLE_RIGID_BODY: See L{KX_SCA_DynamicActuator} +@var KX_DYN_DISABLE_RIGID_BODY: See L{KX_SCA_DynamicActuator} +@var KX_DYN_SET_MASS: See L{KX_SCA_DynamicActuator} + +@group Game Actuator: KX_GAME_* +@var KX_GAME_LOAD: See L{KX_GameActuator} +@var KX_GAME_START: See L{KX_GameActuator} +@var KX_GAME_RESTART: See L{KX_GameActuator} +@var KX_GAME_QUIT: See L{KX_GameActuator} +@var KX_GAME_SAVECFG: See L{KX_GameActuator} +@var KX_GAME_LOADCFG: See L{KX_GameActuator} + +@group Scene Actuator: KX_SCENE_* +@var KX_SCENE_RESTART: See L{KX_SceneActuator} +@var KX_SCENE_SET_SCENE: See L{KX_SceneActuator} +@var KX_SCENE_SET_CAMERA: See L{KX_SceneActuator} +@var KX_SCENE_ADD_FRONT_SCENE: See L{KX_SceneActuator} +@var KX_SCENE_ADD_BACK_SCENE: See L{KX_SceneActuator} +@var KX_SCENE_REMOVE_SCENE: See L{KX_SceneActuator} +@var KX_SCENE_SUSPEND: See L{KX_SceneActuator} +@var KX_SCENE_RESUME: See L{KX_SceneActuator} + +@group Input Status: KX_INPUT_* +@var KX_INPUT_NONE: See L{SCA_MouseSensor} +@var KX_INPUT_JUST_ACTIVATED: See L{SCA_MouseSensor} +@var KX_INPUT_ACTIVE: See L{SCA_MouseSensor} +@var KX_INPUT_JUST_RELEASED: See L{SCA_MouseSensor} + + +@group Mouse Buttons: KX_MOUSE_BUT_* +@var KX_MOUSE_BUT_LEFT: See L{SCA_MouseSensor} +@var KX_MOUSE_BUT_MIDDLE: See L{SCA_MouseSensor} +@var KX_MOUSE_BUT_RIGHT: See L{SCA_MouseSensor} + +@group States: KX_STATE* +@var KX_STATE1: +@var KX_STATE10: +@var KX_STATE11: +@var KX_STATE12: +@var KX_STATE13: +@var KX_STATE14: +@var KX_STATE15: +@var KX_STATE16: +@var KX_STATE17: +@var KX_STATE18: +@var KX_STATE19: +@var KX_STATE2: +@var KX_STATE20: +@var KX_STATE21: +@var KX_STATE22: +@var KX_STATE23: +@var KX_STATE24: +@var KX_STATE25: +@var KX_STATE26: +@var KX_STATE27: +@var KX_STATE28: +@var KX_STATE29: +@var KX_STATE3: +@var KX_STATE30: +@var KX_STATE4: +@var KX_STATE5: +@var KX_STATE6: +@var KX_STATE7: +@var KX_STATE8: +@var KX_STATE9: +@var KX_STATE_OP_CLR: +@var KX_STATE_OP_CPY: +@var KX_STATE_OP_NEG: +@var KX_STATE_OP_SET: + +@group 2D Filter: RAS_2DFILTER_* +@var RAS_2DFILTER_BLUR: +@var RAS_2DFILTER_CUSTOMFILTER: +@var RAS_2DFILTER_DILATION: +@var RAS_2DFILTER_DISABLED: +@var RAS_2DFILTER_ENABLED: +@var RAS_2DFILTER_EROSION: +@var RAS_2DFILTER_GRAYSCALE: +@var RAS_2DFILTER_INVERT: +@var RAS_2DFILTER_LAPLACIAN: +@var RAS_2DFILTER_MOTIONBLUR: +@var RAS_2DFILTER_NOFILTER: +@var RAS_2DFILTER_PREWITT: +@var RAS_2DFILTER_SEPIA: +@var RAS_2DFILTER_SHARPEN: +@var RAS_2DFILTER_SOBEL: + +@group Constraint Actuator: KX_ACT_CONSTRAINT_* +@var KX_ACT_CONSTRAINT_DISTANCE: +@var KX_ACT_CONSTRAINT_DOROTFH: +@var KX_ACT_CONSTRAINT_FHNX: +@var KX_ACT_CONSTRAINT_FHNY: +@var KX_ACT_CONSTRAINT_FHNZ: +@var KX_ACT_CONSTRAINT_FHPX: +@var KX_ACT_CONSTRAINT_FHPY: +@var KX_ACT_CONSTRAINT_FHPZ: +@var KX_ACT_CONSTRAINT_LOCAL: +@var KX_ACT_CONSTRAINT_MATERIAL: +@var KX_ACT_CONSTRAINT_NORMAL: +@var KX_ACT_CONSTRAINT_PERMANENT: + +@group Parent Actuator: KX_PARENT_* +@var KX_PARENT_REMOVE: +@var KX_PARENT_SET: + +@group Shader: MODELMATRIX*, MODELVIEWMATRIX*, VIEWMATRIX*, CAM_POS, CONSTANT_TIMER, SHD_TANGENT +@var VIEWMATRIX: +@var VIEWMATRIX_INVERSE: +@var VIEWMATRIX_INVERSETRANSPOSE: +@var VIEWMATRIX_TRANSPOSE: +@var MODELMATRIX: +@var MODELMATRIX_INVERSE: +@var MODELMATRIX_INVERSETRANSPOSE: +@var MODELMATRIX_TRANSPOSE: +@var MODELVIEWMATRIX: +@var MODELVIEWMATRIX_INVERSE: +@var MODELVIEWMATRIX_INVERSETRANSPOSE: +@var MODELVIEWMATRIX_TRANSPOSE: +@var CAM_POS: Current camera position +@var CONSTANT_TIMER: User a timer for the uniform value. +@var SHD_TANGENT: Not yet documented. + +@group Blender Material: BL_* +@var BL_DST_ALPHA: +@var BL_DST_COLOR: +@var BL_ONE: +@var BL_ONE_MINUS_DST_ALPHA: +@var BL_ONE_MINUS_DST_COLOR: +@var BL_ONE_MINUS_SRC_ALPHA: +@var BL_ONE_MINUS_SRC_COLOR: +@var BL_SRC_ALPHA: +@var BL_SRC_ALPHA_SATURATE: +@var BL_SRC_COLOR: +@var BL_ZERO: + +@group Deprecated: addActiveActuator + +@var globalDict: A dictionary that is saved between loading blend files so you can use + it to store inventory and other variables you want to store between + scenes and blend files. It can also be written to a file and loaded + later on with the game load/save actuators. + note: only python built in types such as int/string/bool/float/tuples/lists + can be saved, GameObjects, Actuators etc will not work as expectred. """ +import GameTypes + +# TODO +# globalDict +# error def getCurrentController(): """ @@ -155,17 +328,35 @@ def getCurrentScene(): @rtype: L{KX_Scene} """ +def getSceneList(): + """ + Gets a list of the current scenes loaded in the game engine. + + @note: Scenes in your blend file that have not been converted wont be in this list. This list will only contain scenes such as overlays scenes. + + @rtype: list of L{KX_Scene} + """ def addActiveActuator(actuator, activate): """ Activates the given actuator. - @type actuator: L{SCA_IActuator} + @deprecated: Use L{GameTypes.SCA_PythonController.activate} and L{GameTypes.SCA_PythonController.deactivate} instead. + @type actuator: L{SCA_IActuator} or the actuator name as a string. @type activate: boolean @param activate: whether to activate or deactivate the given actuator. """ -def getRandomFloat(): +def sendMessage(subject, body="", to="", message_from=""): """ - Returns a random floating point value in the range [0...1) + Sends a message to sensors in any active scene. + + @param subject: The subject of the message + @type subject: string + @param body: The body of the message (optional) + @type body: string + @param to: The name of the object to send the message to (optional) + @type to: string + @param message_from: The name of the object that the message is coming from (optional) + @type message_from: string """ def setGravity(gravity): """ @@ -187,6 +378,38 @@ def stopDSP(): Only the fmod sound driver supports this. DSP can be computationally expensive. """ +def getMaxLogicFrame(): + """ + Gets the maximum number of logic frame per render frame. + + @return: The maximum number of logic frame per render frame + @rtype: interger + """ +def setMaxLogicFrame(maxlogic): + """ + Sets the maximum number of logic frame that are executed per render frame. + This does not affect the physic system that still runs at full frame rate. + + @param maxlogic: The new maximum number of logic frame per render frame. Valid values: 1..5 + @type maxlogic: integer + """ +def getMaxPhysicsFrame(): + """ + Gets the maximum number of physics frame per render frame. + + @return: The maximum number of physics frame per render frame + @rtype: interger + """ +def setMaxPhysicsFrame(maxphysics): + """ + Sets the maximum number of physics timestep that are executed per render frame. + Higher value allows physics to keep up with realtime even if graphics slows down the game. + Physics timestep is fixed and equal to 1/tickrate (see setLogicTicRate) + maxphysics/ticrate is the maximum delay of the renderer that physics can compensate. + + @param maxphysics: The new maximum number of physics timestep per render frame. Valid values: 1..5. + @type maxphysics: integer + """ def getLogicTicRate(): """ Gets the logic update frequency. @@ -199,13 +422,14 @@ def setLogicTicRate(ticrate): Sets the logic update frequency. The logic update frequency is the number of times logic bricks are executed every second. - The default is 30 Hz. + The default is 60 Hz. @param ticrate: The new logic update frequency (in Hz). @type ticrate: float """ def getPhysicsTicRate(): """ + NOT IMPLEMENTED Gets the physics update frequency @return: The physics update frequency in Hz @@ -213,6 +437,7 @@ def getPhysicsTicRate(): """ def setPhysicsTicRate(ticrate): """ + NOT IMPLEMENTED Sets the physics update frequency The physics update frequency is the number of times the physics system is executed every second. @@ -221,6 +446,8 @@ def setPhysicsTicRate(ticrate): @param ticrate: The new update frequency (in Hz). @type ticrate: float """ + +#{ Utility functions def getAverageFrameRate(): """ Gets the estimated average framerate @@ -228,7 +455,6 @@ def getAverageFrameRate(): @return: The estimed average framerate in frames per second @rtype: float """ - def expandPath(path): """ Converts a blender internal path into a proper file system path. @@ -254,3 +480,12 @@ def getBlendFileList(path = "//"): @return: A list of filenames, with no directory prefix @rtype: list """ +def PrintGLInfo(): + """ + Prints GL Extension Info into the console + """ +def getRandomFloat(): + """ + Returns a random floating point value in the range [0...1) + """ +#} diff --git a/source/gameengine/PyDoc/GameTypes.py b/source/gameengine/PyDoc/GameTypes.py new file mode 100644 index 00000000000..c391d0c3dec --- /dev/null +++ b/source/gameengine/PyDoc/GameTypes.py @@ -0,0 +1,5767 @@ +""" +Documentation for the GameTypes Module. +======================================= + +@group Base: PyObjectPlus, CValue, CPropValue, SCA_ILogicBrick, SCA_IObject, SCA_ISensor, SCA_IController, SCA_IActuator + +@group Object: KX_GameObject, KX_LightObject, KX_Camera + +@group Mesh: KX_MeshProxy, KX_PolyProxy, KX_VertexProxy + +@group Shading: KX_PolygonMaterial, KX_BlenderMaterial, BL_Shader + +@group Sensors: SCA_ActuatorSensor, SCA_AlwaysSensor, SCA_DelaySensor, SCA_JoystickSensor, SCA_KeyboardSensor, KX_MouseFocusSensor, SCA_MouseSensor, KX_NearSensor, KX_NetworkMessageSensor, SCA_PropertySensor, KX_RadarSensor, SCA_RandomSensor, KX_RaySensor, KX_TouchSensor + +@group Actuators: SCA_2DFilterActuator, BL_ActionActuator, KX_SCA_AddObjectActuator, KX_CameraActuator, KX_ConstraintActuator, KX_SCA_DynamicActuator, KX_SCA_EndObjectActuator, KX_GameActuator, KX_IpoActuator, KX_NetworkMessageActuator, KX_ObjectActuator, KX_ParentActuator, SCA_PropertyActuator, SCA_RandomActuator, KX_SCA_ReplaceMeshActuator, KX_SceneActuator, BL_ShapeActionActuator, KX_SoundActuator, KX_StateActuator, KX_TrackToActuator, KX_VisibilityActuator + +@group Controllers: SCA_ANDController, SCA_NANDController, SCA_NORController, SCA_ORController, SCA_PythonController, SCA_XNORController, SCA_XORController +""" +import GameLogic + +class PyObjectPlus: + """ + PyObjectPlus base class of most other types in the Game Engine. + + @ivar invalid: Test if the object has been freed by the game engine and is no longer valid. + + Normally this is not a problem but when storing game engine data in the GameLogic module, + KX_Scenes or other KX_GameObjects its possible to hold a reference to invalid data. + Calling an attribute or method on an invalid object will raise a SystemError. + + The invalid attribute allows testing for this case without exception handling. + @type invalid: bool + """ + + def isA(game_type): + """ + Check if this is a type or a subtype game_type. + + @param game_type: the name of the type or the type its self from the L{GameTypes} module. + @type game_type: string or type + @return: True if this object is a type or a subtype of game_type. + @rtype: bool + """ + +class CValue(PyObjectPlus): + """ + This class is a basis for other classes. + @ivar name: The name of this CValue derived object (read-only). + @type name: string + @group Deprecated: getName + """ + def getName(): + """ + Returns the name of the CValue. + + @deprecated: Use the L{name} attribute instead. + @note: in most cases the CValue's subclasses will override this function. + @rtype: string + """ + +class CPropValue(CValue): + """ + This class has no python functions + """ + pass + +class SCA_ILogicBrick(CValue): + """ + Base class for all logic bricks. + + @ivar executePriority: This determines the order controllers are evaluated, and actuators are activated (lower priority is executed first). + @type executePriority: int + @ivar owner: The game object this logic brick is attached to (read-only). + @type owner: L{KX_GameObject} or None in exceptional cases. + @ivar name: The name of this logic brick (read-only). + @type name: string + """ + +#{ Deprecated + def getOwner(): + """ + Gets the game object associated with this logic brick. + + @deprecated: Use the L{owner} attribute instead. + @rtype: L{KX_GameObject} + """ + + def setExecutePriority(priority): + """ + Sets the priority of this logic brick. + + This determines the order controllers are evaluated, and actuators are activated. + Bricks with lower priority will be executed first. + + @deprecated: Use the L{executePriority} attribute instead. + @type priority: integer + @param priority: the priority of this logic brick. + """ + def getExecutePriority(): + """ + Gets the execution priority of this logic brick. + + @deprecated: Use the L{executePriority} attribute instead. + @rtype: integer + @return: this logic bricks current priority. + """ +#} + +class SCA_IObject(CValue): + """ + This class has no python functions + """ + pass + +class SCA_ISensor(SCA_ILogicBrick): + """ + Base class for all sensor logic bricks. + + @ivar usePosPulseMode: Flag to turn positive pulse mode on and off. + @type usePosPulseMode: boolean + @ivar useNegPulseMode: Flag to turn negative pulse mode on and off. + @type useNegPulseMode: boolean + @ivar frequency: The frequency for pulse mode sensors. + @type frequency: int + @ivar level: Option whether to detect level or edge transition when entering a state. + It makes a difference only in case of logic state transition (state actuator). + A level detector will immediately generate a pulse, negative or positive + depending on the sensor condition, as soon as the state is activated. + A edge detector will wait for a state change before generating a pulse. + note: mutually exclusive with L{tap}, enabling will disable L{tap}. + @type level: boolean + @ivar tap: When enabled only sensors that are just activated will send a positive event, + after this they will be detected as negative by the controllers. + This will make a key thats held act as if its only tapped for an instant. + note: mutually exclusive with L{level}, enabling will disable L{level}. + @type tap: boolean + @ivar invert: Flag to set if this sensor activates on positive or negative events. + @type invert: boolean + @ivar triggered: True if this sensor brick is in a positive state. (read-only) + @type triggered: boolean + @ivar positive: True if this sensor brick is in a positive state. (read-only) + @type positive: boolean + """ + + def reset(): + """ + Reset sensor internal state, effect depends on the type of sensor and settings. + + The sensor is put in its initial state as if it was just activated. + """ +#{ Deprecated + def isPositive(): + """ + True if this sensor brick is in a positive state. + + @deprecated: use L{positive} + """ + + def isTriggered(): + """ + True if this sensor brick has triggered the current controller. + + @deprecated: use L{triggered} + """ + + def getUsePosPulseMode(): + """ + True if the sensor is in positive pulse mode. + + @deprecated: use L{usePosPulseMode} + """ + def setUsePosPulseMode(pulse): + """ + Sets positive pulse mode. + + @type pulse: boolean + @param pulse: If True, will activate positive pulse mode for this sensor. + @deprecated: use L{usePosPulseMode} + """ + def getFrequency(): + """ + The frequency for pulse mode sensors. + + @rtype: integer + @return: the pulse frequency in 1/50 sec. + @deprecated: use L{frequency} + """ + def setFrequency(freq): + """ + Sets the frequency for pulse mode sensors. + + @type freq: integer + @return: the pulse frequency in 1/50 sec. + @deprecated: use L{frequency} + """ + def getUseNegPulseMode(): + """ + True if the sensor is in negative pulse mode. + + @deprecated: use L{useNegPulseMode} + """ + def setUseNegPulseMode(pulse): + """ + Sets negative pulse mode. + + @type pulse: boolean + @param pulse: If True, will activate negative pulse mode for this sensor. + @deprecated: use L{useNegPulseMode} + """ + def getInvert(): + """ + True if this sensor activates on negative events. + + @deprecated: use L{invert} + """ + def setInvert(invert): + """ + Sets if this sensor activates on positive or negative events. + + @type invert: boolean + @param invert: true if activates on negative events; false if activates on positive events. + @deprecated: use L{invert} + """ + def getLevel(): + """ + Returns whether this sensor is a level detector or a edge detector. + It makes a difference only in case of logic state transition (state actuator). + A level detector will immediately generate a pulse, negative or positive + depending on the sensor condition, as soon as the state is activated. + A edge detector will wait for a state change before generating a pulse. + + @rtype: boolean + @return: true if sensor is level sensitive, false if it is edge sensitive + @deprecated: use L{level} + """ + def setLevel(level): + """ + Set whether to detect level or edge transition when entering a state. + + @param level: Detect level instead of edge? (KX_TRUE, KX_FALSE) + @type level: boolean + @deprecated: use L{level} + """ +#} + +class SCA_IController(SCA_ILogicBrick): + """ + Base class for all controller logic bricks. + + @ivar state: the controllers state bitmask. + This can be used with the GameObject's state to test if the controller is active. + @type state: int bitmask + @ivar sensors: a list of sensors linked to this controller + - note: the sensors are not necessarily owned by the same object. + - note: when objects are instanced in dupligroups links may be lost from objects outside the dupligroup. + @type sensors: sequence supporting index/string lookups and iteration. + @ivar actuators: a list of actuators linked to this controller. + - note: the sensors are not necessarily owned by the same object. + - note: when objects are instanced in dupligroups links may be lost from objects outside the dupligroup. + @type actuators: sequence supporting index/string lookups and iteration. + @ivar useHighPriority: When set the controller executes always before all other controllers that dont have this set. + note: Order of execution between high priority controllers is not guaranteed. + @type useHighPriority: bool + """ +#{ Deprecated + def getState(): + """ + Get the controllers state bitmask, this can be used with the GameObject's state to test if the the controller is active. + This for instance will always be true however you could compare with a previous state to see when the state was activated. + GameLogic.getCurrentController().state & GameLogic.getCurrentController().owner.state + @deprecated: Use the L{state} property + @rtype: int + """ + def getSensors(): + """ + Gets a list of all sensors attached to this controller. + @deprecated: use the L{sensors} property + @rtype: list [L{SCA_ISensor}] + """ + def getSensor(name): + """ + Gets the named linked sensor. + @deprecated: use the L{sensors}[name] property + @type name: string + @rtype: L{SCA_ISensor} + """ + def getActuators(): + """ + Gets a list of all actuators linked to this controller. + @deprecated: Use the L{actuators} property + @rtype: list [L{SCA_IActuator}] + """ + def getActuator(name): + """ + Gets the named linked actuator. + @deprecated: use the L{actuators}[name] property + @type name: string + @rtype: L{SCA_IActuator} + """ +#} + +class SCA_IActuator(SCA_ILogicBrick): + """ + Base class for all actuator logic bricks. + """ + +class BL_ActionActuator(SCA_IActuator): + """ + Action Actuators apply an action to an actor. + + @ivar action: The name of the action to set as the current action. + @type action: string + @ivar channelNames: A list of channel names that may be used with L{setChannel} and L{getChannel} + @type channelNames: list of strings + @ivar frameStart: Specifies the starting frame of the animation. + @type frameStart: float + @ivar frameEnd: Specifies the ending frame of the animation. + @type frameEnd: float + @ivar blendIn: Specifies the number of frames of animation to generate when making transitions between actions. + @type blendIn: float + @ivar priority: Sets the priority of this actuator. Actuators will lower + priority numbers will override actuators with higher + numbers. + @type priority: integer + @ivar frame: Sets the current frame for the animation. + @type frame: float + @ivar propName: Sets the property to be used in FromProp playback mode. + @type propName: string + @ivar blendTime: Sets the internal frame timer. This property must be in + the range from 0.0 to blendIn. + @type blendTime: float + @ivar mode: The operation mode of the actuator. KX_ACTIONACT_PLAY, KX_ACTIONACT_PROPERTY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND + @type mode: integer + @ivar useContinue: The actions continue option, True or False. + When True, the action will always play from where last left off, + otherwise negative events to this actuator will reset it to its start frame. + @type useContinue: boolean + @ivar framePropName: The name of the property that is set to the current frame number. + @type framePropName: string + """ + def setChannel(channel, matrix): + """ + Alternative to the 2 arguments, 4 arguments (channel, matrix, loc, size, quat) are also supported. + + @note: These values are relative to the bones rest position, currently the api has no way to get this info (which is annoying), but can be worked around by using bones with a rest pose that has no translation. + @param channel: A string specifying the name of the bone channel, error raised if not in L{channelNames}. + @type channel: string + @param matrix: A 4x4 matrix specifying the overriding transformation + as an offset from the bone's rest position. + @type matrix: list [[float]] + """ + + def getChannel(channel): + """ + @param channel: A string specifying the name of the bone channel. error raised if not in L{channelNames}. + @type channel: string + @rtype: tuple + @return: (loc, size, quat) + """ + +#{ Deprecated + def setAction(action, reset = True): + """ + Sets the current action. + @deprecated: use the L{action} property + @param action: The name of the action to set as the current action. + @type action: string + @param reset: Optional parameter indicating whether to reset the + blend timer or not. A value of 1 indicates that the + timer should be reset. A value of 0 will leave it + unchanged. If reset is not specified, the timer will + be reset. + """ + + def setStart(start): + """ + Specifies the starting frame of the animation. + @deprecated: Use the L{frameStart} property + @param start: the starting frame of the animation + @type start: float + """ + + def setEnd(end): + """ + Specifies the ending frame of the animation. + @deprecated: use the L{frameEnd} property + @param end: the ending frame of the animation + @type end: float + """ + def setBlendin(blendin): + """ + Specifies the number of frames of animation to generate + when making transitions between actions. + @deprecated: use the L{blendIn} property + @param blendin: the number of frames in transition. + @type blendin: float + """ + + def setPriority(priority): + """ + Sets the priority of this actuator. + + @deprecated: Use use the L{priority} property + @param priority: Specifies the new priority. Actuators will lower + priority numbers will override actuators with higher + numbers. + @type priority: integer + """ + def setFrame(frame): + """ + Sets the current frame for the animation. + + @deprecated: use the L{frame} property + @param frame: Specifies the new current frame for the animation + @type frame: float + """ + + def setProperty(prop): + """ + Sets the property to be used in FromProp playback mode. + + @deprecated: use the L{property} property + @param prop: the name of the property to use. + @type prop: string. + """ + + def setBlendtime(blendtime): + """ + Sets the internal frame timer. + + Allows the script to directly modify the internal timer + used when generating transitions between actions. + + @deprecated: use the L{blendTime} property + @param blendtime: The new time. This parameter must be in the range from 0.0 to 1.0. + @type blendtime: float + """ + + def setType(mode): + """ + Sets the operation mode of the actuator + + @deprecated: use the L{type} property + @param mode: KX_ACTIONACT_PLAY, KX_ACTIONACT_PROPERTY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND + @type mode: integer + """ + + def setContinue(cont): + """ + Set the actions continue option True or False. see getContinue. + + @deprecated: use the L{useContinue} property + @param cont: The continue option. + @type cont: bool + """ + + def getType(): + """ + Returns the operation mode of the actuator + + @deprecated: use the L{type} property + @rtype: integer + @return: KX_ACTIONACT_PLAY, KX_ACTIONACT_PROPERTY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND + """ + + def getContinue(): + """ + When True, the action will always play from where last left off, otherwise negative events to this actuator will reset it to its start frame. + + @deprecated: use the L{useContinue} property + @rtype: bool + """ + + def getAction(): + """ + getAction() returns the name of the action associated with this actuator. + + @deprecated: use the L{action} property + @rtype: string + """ + + def getStart(): + """ + Returns the starting frame of the action. + + @deprecated: use the L{frameStart} property + @rtype: float + """ + def getEnd(): + """ + Returns the last frame of the action. + + @deprecated: use the L{frameEnd} property + @rtype: float + """ + def getBlendin(): + """ + Returns the number of interpolation animation frames to be generated when this actuator is triggered. + + @deprecated: use the L{blendIn} property + @rtype: float + """ + def getPriority(): + """ + Returns the priority for this actuator. Actuators with lower Priority numbers will + override actuators with higher numbers. + + @deprecated: use the L{priority} property + @rtype: integer + """ + def getFrame(): + """ + Returns the current frame number. + + @deprecated: use the L{frame} property + @rtype: float + """ + def getProperty(): + """ + Returns the name of the property to be used in FromProp mode. + + @deprecated: use the L{property} property + @rtype: string + """ + def setFrameProperty(prop): + """ + @deprecated: use the L{framePropName} property + @param prop: A string specifying the property of the object that will be updated with the action frame number. + @type prop: string + """ + def getFrameProperty(): + """ + Returns the name of the property that is set to the current frame number. + + @deprecated: use the L{framePropName} property + @rtype: string + """ +#} + +class BL_Shader(PyObjectPlus): + """ + BL_Shader GLSL shaders. + + TODO - Description + """ + + def setUniformfv(name, fList): + """ + Set a uniform with a list of float values + + @param name: the uniform name + @type name: string + + @param fList: a list (2, 3 or 4 elements) of float values + @type fList: list[float] + """ + + def delSource(): + """ + Clear the shader. Use this method before the source is changed with L{setSource}. + """ + def getFragmentProg(): + """ + Returns the fragment program. + + @rtype: string + @return: The fragment program. + """ + def getVertexProg(): + """ + Get the vertex program. + + @rtype: string + @return: The vertex program. + """ + def isValid(): + """ + Check if the shader is valid. + + @rtype: bool + @return: True if the shader is valid + """ + def setAttrib(enum): + """ + Set attribute location. (The parameter is ignored a.t.m. and the value of "tangent" is always used.) + + @param enum: attribute location value + @type enum: integer + """ + def setNumberOfPasses( max_pass ): + """ + Set the maximum number of passes. Not used a.t.m. + + @param max_pass: the maximum number of passes + @type max_pass: integer + """ + def setSampler(name, index): + """ + Set uniform texture sample index. + + @param name: Uniform name + @type name: string + + @param index: Texture sample index. + @type index: integer + """ + def setSource(vertexProgram, fragmentProgram): + """ + Set the vertex and fragment programs + + @param vertexProgram: Vertex program + @type vertexProgram: string + + @param fragmentProgram: Fragment program + @type fragmentProgram: string + """ + def setUniform1f(name, fx): + """ + Set a uniform with 1 float value. + + @param name: the uniform name + @type name: string + + @param fx: Uniform value + @type fx: float + """ + def setUniform1i(name, ix): + """ + Set a uniform with an integer value. + + @param name: the uniform name + @type name: string + + @param ix: the uniform value + @type ix: integer + """ + def setUniform2f(name, fx, fy): + """ + Set a uniform with 2 float values + + @param name: the uniform name + @type name: string + + @param fx: first float value + @type fx: float + + @param fy: second float value + @type fy: float + """ + def setUniform2i(name, ix, iy): + """ + Set a uniform with 2 integer values + + @param name: the uniform name + @type name: string + + @param ix: first integer value + @type ix: integer + + @param iy: second integer value + @type iy: integer + """ + def setUniform3f(name, fx,fy,fz): + """ + Set a uniform with 3 float values. + + @param name: the uniform name + @type name: string + + @param fx: first float value + @type fx: float + + @param fy: second float value + @type fy: float + + @param fz: third float value + @type fz: float + """ + def setUniform3i(name, ix,iy,iz): + """ + Set a uniform with 3 integer values + + @param name: the uniform name + @type name: string + + @param ix: first integer value + @type ix: integer + + @param iy: second integer value + @type iy: integer + + @param iz: third integer value + @type iz: integer + """ + def setUniform4f(name, fx,fy,fz,fw): + """ + Set a uniform with 4 float values. + + @param name: the uniform name + @type name: string + + @param fx: first float value + @type fx: float + + @param fy: second float value + @type fy: float + + @param fz: third float value + @type fz: float + + @param fw: fourth float value + @type fw: float + """ + def setUniform4i(name, ix,iy,iz, iw): + """ + Set a uniform with 4 integer values + + @param name: the uniform name + @type name: string + + @param ix: first integer value + @type ix: integer + + @param iy: second integer value + @type iy: integer + + @param iz: third integer value + @type iz: integer + + @param iw: fourth integer value + @type iw: integer + """ + def setUniformDef(name, type): + """ + Define a new uniform + + @param name: the uniform name + @type name: string + + @param type: uniform type + @type type: UNI_NONE, UNI_INT, UNI_FLOAT, UNI_INT2, UNI_FLOAT2, UNI_INT3, UNI_FLOAT3, UNI_INT4, UNI_FLOAT4, UNI_MAT3, UNI_MAT4, UNI_MAX + """ + def setUniformMatrix3(name, mat, transpose): + """ + Set a uniform with a 3x3 matrix value + + @param name: the uniform name + @type name: string + + @param mat: A 3x3 matrix [[f,f,f], [f,f,f], [f,f,f]] + @type mat: 3x3 matrix + + @param transpose: set to True to transpose the matrix + @type transpose: bool + """ + def setUniformMatrix4(name, mat, transpose): + """ + Set a uniform with a 4x4 matrix value + + @param name: the uniform name + @type name: string + + @param mat: A 4x4 matrix [[f,f,f,f], [f,f,f,f], [f,f,f,f], [f,f,f,f]] + @type mat: 4x4 matrix + + @param transpose: set to True to transpose the matrix + @type transpose: bool + """ + def setUniformiv(name, iList): + """ + Set a uniform with a list of integer values + + @param name: the uniform name + @type name: string + + @param iList: a list (2, 3 or 4 elements) of integer values + @type iList: list[integer] + """ + def validate(): + """ + Validate the shader object. + + """ + +class BL_ShapeActionActuator(SCA_IActuator): + """ + ShapeAction Actuators apply an shape action to an mesh object.\ + + @ivar action: The name of the action to set as the current shape action. + @type action: string + @ivar frameStart: Specifies the starting frame of the shape animation. + @type frameStart: float + @ivar frameEnd: Specifies the ending frame of the shape animation. + @type frameEnd: float + @ivar blendIn: Specifies the number of frames of animation to generate when making transitions between actions. + @type blendIn: float + @ivar priority: Sets the priority of this actuator. Actuators will lower + priority numbers will override actuators with higher + numbers. + @type priority: integer + @ivar frame: Sets the current frame for the animation. + @type frame: float + @ivar propName: Sets the property to be used in FromProp playback mode. + @type propName: string + @ivar blendTime: Sets the internal frame timer. This property must be in + the range from 0.0 to blendin. + @type blendTime: float + @ivar mode: The operation mode of the actuator. + KX_ACTIONACT_PLAY, KX_ACTIONACT_PROPERTY, KX_ACTIONACT_FLIPPER, + KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND + @type mode: integer + @ivar framePropName: The name of the property that is set to the current frame number. + @type framePropName: string + + """ +#{ Deprecated + def setAction(action, reset = True): + """ + Sets the current action. + + @deprecated: use the L{action} property + @param action: The name of the action to set as the current action. + @type action: string + @param reset: Optional parameter indicating whether to reset the + blend timer or not. A value of 1 indicates that the + timer should be reset. A value of 0 will leave it + unchanged. If reset is not specified, the timer will + be reset. + """ + + def setStart(start): + """ + Specifies the starting frame of the animation. + + @deprecated: use the L{frameStart} property + @param start: the starting frame of the animation + @type start: float + """ + + def setEnd(end): + """ + Specifies the ending frame of the animation. + + @deprecated: use the L{frameEnd} property + @param end: the ending frame of the animation + @type end: float + """ + def setBlendin(blendin): + """ + Specifies the number of frames of animation to generate + when making transitions between actions. + + @deprecated: use the L{blendIn} property + @param blendin: the number of frames in transition. + @type blendin: float + """ + + def setPriority(priority): + """ + Sets the priority of this actuator. + + @deprecated: use the L{priority} property + @param priority: Specifies the new priority. Actuators will lower + priority numbers will override actuators with higher + numbers. + @type priority: integer + """ + def setFrame(frame): + """ + Sets the current frame for the animation. + + @deprecated: use the L{frame} property + @param frame: Specifies the new current frame for the animation + @type frame: float + """ + + def setProperty(prop): + """ + Sets the property to be used in FromProp playback mode. + + @deprecated: use the L{property} property + @param prop: the name of the property to use. + @type prop: string. + """ + + def setBlendtime(blendtime): + """ + Sets the internal frame timer. + + Allows the script to directly modify the internal timer + used when generating transitions between actions. + + @deprecated: use the L{blendTime} property + @param blendtime: The new time. This parameter must be in the range from 0.0 to 1.0. + @type blendtime: float + """ + + def setType(mode): + """ + Sets the operation mode of the actuator + + @deprecated: use the L{type} property + @param mode: KX_ACTIONACT_PLAY, KX_ACTIONACT_PROPERTY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND + @type mode: integer + """ + + def getType(): + """ + Returns the operation mode of the actuator + + @deprecated: use the L{type} property + @rtype: integer + @return: KX_ACTIONACT_PLAY, KX_ACTIONACT_PROPERTY, KX_ACTIONACT_FLIPPER, KX_ACTIONACT_LOOPSTOP, KX_ACTIONACT_LOOPEND + """ + + def getAction(): + """ + getAction() returns the name of the action associated with this actuator. + + @deprecated: use the L{action} property + @rtype: string + """ + + def getStart(): + """ + Returns the starting frame of the action. + + @deprecated: use the L{frameStart} property + @rtype: float + """ + def getEnd(): + """ + Returns the last frame of the action. + + @deprecated: use the L{frameEnd} property + @rtype: float + """ + def getBlendin(): + """ + Returns the number of interpolation animation frames to be generated when this actuator is triggered. + + @deprecated: use the L{blendIn} property + @rtype: float + """ + def getPriority(): + """ + Returns the priority for this actuator. Actuators with lower Priority numbers will + override actuators with higher numbers. + + @deprecated: use the L{priority} property + @rtype: integer + """ + def getFrame(): + """ + Returns the current frame number. + + @deprecated: use the L{frame} property + @rtype: float + """ + def getProperty(): + """ + Returns the name of the property to be used in FromProp mode. + + @deprecated: use the L{property} property + @rtype: string + """ + def setFrameProperty(prop): + """ + @deprecated: use the L{framePropName} property + @param prop: A string specifying the property of the object that will be updated with the action frame number. + @type prop: string + """ + def getFrameProperty(): + """ + Returns the name of the property that is set to the current frame number. + + @deprecated: use the L{framePropName} property + @rtype: string + """ +#} + +class CListValue(CPropValue): + """ + CListValue + + This is a list like object used in the game engine internally that behaves similar to a python list in most ways. + + As well as the normal index lookup. + C{val= clist[i]} + + CListValue supports string lookups. + C{val= scene.objects["OBCube"]} + + Other operations such as C{len(clist), list(clist), clist[0:10]} are also supported. + """ + def append(val): + """ + Add an item to the list (like pythons append) + + Warning: Appending values to the list can cause crashes when the list is used internally by the game engine. + """ + + def count(val): + """ + Count the number of instances of a value in the list. + + @rtype: integer + @return: number of instances + """ + def index(val): + """ + Return the index of a value in the list. + + @rtype: integer + @return: The index of the value in the list. + """ + def reverse(): + """ + Reverse the order of the list. + """ + def get(key, default=None): + """ + Return the value matching key, or the default value if its not found. + @return: The key value or a default. + """ + def from_id(id): + """ + This is a funtion especially for the game engine to return a value with a spesific id. + + Since object names are not always unique, the id of an object can be used to get an object from the CValueList. + + Example. + + C{myObID = id(gameObject)} + + C{...} + + C{ob= scene.objects.from_id(myObID)} + + Where myObID is an int or long from the id function. + + This has the advantage that you can store the id in places you could not store a gameObject. + + Warning: the id is derived from a memory location and will be different each time the game engine starts. + """ + +class KX_BlenderMaterial(PyObjectPlus): # , RAS_IPolyMaterial) + """ + KX_BlenderMaterial + + """ + + def getShader(): + """ + Returns the material's shader. + + @rtype: L{BL_Shader} + @return: the material's shader + """ + + def setBlending(src, dest): + """ + Set the pixel color arithmetic functions. + + @param src: Specifies how the red, green, blue, + and alpha source blending factors are computed. + @type src: GL_ZERO, + GL_ONE, + GL_SRC_COLOR, + GL_ONE_MINUS_SRC_COLOR, + GL_DST_COLOR, + GL_ONE_MINUS_DST_COLOR, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_SRC_ALPHA_SATURATE + + + @param dest: Specifies how the red, green, blue, + and alpha destination blending factors are computed. + @type dest: GL_ZERO, + GL_ONE, + GL_SRC_COLOR, + GL_ONE_MINUS_SRC_COLOR, + GL_DST_COLOR, + GL_ONE_MINUS_DST_COLOR, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_SRC_ALPHA_SATURATE + + """ + def getMaterialIndex(): + """ + Returns the material's index. + + @rtype: integer + @return: the material's index + """ + +class KX_CameraActuator(SCA_IActuator): + """ + Applies changes to a camera. + + @ivar min: minimum distance to the target object maintained by the actuator + @type min: float + @ivar max: maximum distance to stay from the target object + @type max: float + @ivar height: height to stay above the target object + @type height: float + @ivar useXY: axis this actuator is tracking, true=X, false=Y + @type useXY: boolean + @ivar object: the object this actuator tracks. + @type object: KX_GameObject or None + @author: snail + """ +#{ Deprecated + def getObject(name_only = 1): + """ + Returns the name of the object this actuator tracks. + + @deprecated: Use the L{object} attribute instead. + @type name_only: bool + @param name_only: optional argument, when 0 return a KX_GameObject + @rtype: string, KX_GameObject or None if no object is set + """ + + def setObject(target): + """ + Sets the object this actuator tracks. + + @deprecated: Use the L{object} attribute instead. + @param target: the object to track. + @type target: L{KX_GameObject}, string or None + """ + + def getMin(): + """ + Returns the minimum distance to target maintained by the actuator. + + @deprecated: Use the L{min} attribute instead. + @rtype: float + """ + + def setMin(distance): + """ + Sets the minimum distance to the target object maintained by the + actuator. + + @deprecated: Use the L{min} attribute instead. + @param distance: The minimum distance to maintain. + @type distance: float + """ + + def getMax(): + """ + Gets the maximum distance to stay from the target object. + + @deprecated: Use the L{max} attribute instead. + @rtype: float + """ + + def setMax(distance): + """ + Sets the maximum distance to stay from the target object. + + @deprecated: Use the L{max} attribute instead. + @param distance: The maximum distance to maintain. + @type distance: float + """ + + def getHeight(): + """ + Returns the height to stay above the target object. + + @deprecated: Use the L{height} attribute instead. + @rtype: float + """ + + def setHeight(height): + """ + Sets the height to stay above the target object. + + @deprecated: Use the L{height} attribute instead. + @type height: float + @param height: The height to stay above the target object. + """ + + def setXY(xaxis): + """ + Sets the axis to get behind. + + @deprecated: Use the L{useXY} attribute instead. + @param xaxis: False to track Y axis, True to track X axis. + @type xaxis: boolean + """ + + def getXY(): + """ + Returns the axis this actuator is tracking. + + @deprecated: Use the L{useXY} attribute instead. + @return: True if tracking X axis, False if tracking Y axis. + @rtype: boolean + """ +#} + +class KX_ConstraintActuator(SCA_IActuator): + """ + A constraint actuator limits the position, rotation, distance or orientation of an object. + + Properties: + + @ivar damp: time constant of the constraint expressed in frame (not use by Force field constraint) + @type damp: integer + + @ivar rotDamp: time constant for the rotation expressed in frame (only for the distance constraint) + 0 = use damp for rotation as well + @type rotDamp: integer + + @ivar direction: the reference direction in world coordinate for the orientation constraint + @type direction: 3-tuple of float: [x,y,z] + + @ivar option: Binary combination of the following values: + Applicable to Distance constraint: + - KX_ACT_CONSTRAINT_NORMAL ( 64) : Activate alignment to surface + - KX_ACT_CONSTRAINT_DISTANCE ( 512) : Activate distance control + - KX_ACT_CONSTRAINT_LOCAL (1024) : direction of the ray is along the local axis + Applicable to Force field constraint: + - KX_ACT_CONSTRAINT_DOROTFH (2048) : Force field act on rotation as well + Applicable to both: + - KX_ACT_CONSTRAINT_MATERIAL ( 128) : Detect material rather than property + - KX_ACT_CONSTRAINT_PERMANENT ( 256) : No deactivation if ray does not hit target + @type option: integer + + @ivar time: activation time of the actuator. The actuator disables itself after this many frame. + If set to 0, the actuator is not limited in time. + @type time: integer + + @ivar propName: the name of the property or material for the ray detection of the distance constraint. + @type propName: string + + @ivar min: The lower bound of the constraint + For the rotation and orientation constraint, it represents radiant + @type min: float + + @ivar distance: the target distance of the distance constraint + @type distance: float + + @ivar max: the upper bound of the constraint. + For rotation and orientation constraints, it represents radiant. + @type max: float + + @ivar rayLength: the length of the ray of the distance constraint. + @type rayLength: float + + @ivar limit: type of constraint, use one of the following constant: + KX_ACT_CONSTRAINT_LOCX ( 1) : limit X coord + KX_ACT_CONSTRAINT_LOCY ( 2) : limit Y coord + KX_ACT_CONSTRAINT_LOCZ ( 3) : limit Z coord + KX_ACT_CONSTRAINT_ROTX ( 4) : limit X rotation + KX_ACT_CONSTRAINT_ROTY ( 5) : limit Y rotation + KX_ACT_CONSTRAINT_ROTZ ( 6) : limit Z rotation + KX_ACT_CONSTRAINT_DIRPX ( 7) : set distance along positive X axis + KX_ACT_CONSTRAINT_DIRPY ( 8) : set distance along positive Y axis + KX_ACT_CONSTRAINT_DIRPZ ( 9) : set distance along positive Z axis + KX_ACT_CONSTRAINT_DIRNX (10) : set distance along negative X axis + KX_ACT_CONSTRAINT_DIRNY (11) : set distance along negative Y axis + KX_ACT_CONSTRAINT_DIRNZ (12) : set distance along negative Z axis + KX_ACT_CONSTRAINT_ORIX (13) : set orientation of X axis + KX_ACT_CONSTRAINT_ORIY (14) : set orientation of Y axis + KX_ACT_CONSTRAINT_ORIZ (15) : set orientation of Z axis + KX_ACT_CONSTRAINT_FHPX (16) : set force field along positive X axis + KX_ACT_CONSTRAINT_FHPY (17) : set force field along positive Y axis + KX_ACT_CONSTRAINT_FHPZ (18) : set force field along positive Z axis + KX_ACT_CONSTRAINT_FHNX (19) : set force field along negative X axis + KX_ACT_CONSTRAINT_FHNY (20) : set force field along negative Y axis + KX_ACT_CONSTRAINT_FHNZ (21) : set force field along negative Z axis + @type limit: integer + """ +#{ Deprecated + def setDamp(time): + """ + Sets the time this constraint is delayed. + + @param time: The number of frames to delay. + Negative values are ignored. + @type time: integer + """ + def getDamp(): + """ + Returns the damping time of the constraint. + + @rtype: integer + """ + def setMin(lower): + """ + Sets the lower bound of the constraint. + + For rotational and orientation constraints, lower is specified in degrees. + + @type lower: float + """ + def getMin(): + """ + Gets the lower bound of the constraint. + + For rotational and orientation constraints, the lower bound is returned in radians. + + @rtype: float + """ + def setMax(upper): + """ + Sets the upper bound of the constraint. + + For rotational and orientation constraints, upper is specified in degrees. + + @type upper: float + """ + def getMax(): + """ + Gets the upper bound of the constraint. + + For rotational and orientation constraints, the upper bound is returned in radians. + + @rtype: float + """ + def setLimit(limit): + """ + Sets the type of constraint. + + See module L{GameLogic} for valid constraint types. + + @param limit: + Position constraints: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY, KX_CONSTRAINTACT_LOCZ + Rotation constraints: KX_CONSTRAINTACT_ROTX, KX_CONSTRAINTACT_ROTY or KX_CONSTRAINTACT_ROTZ + Distance contraints: KX_ACT_CONSTRAINT_DIRPX, KX_ACT_CONSTRAINT_DIRPY, KX_ACT_CONSTRAINT_DIRPZ, KX_ACT_CONSTRAINT_DIRNX, KX_ACT_CONSTRAINT_DIRNY, KX_ACT_CONSTRAINT_DIRNZ + Orientation constraints: KX_ACT_CONSTRAINT_ORIX, KX_ACT_CONSTRAINT_ORIY, KX_ACT_CONSTRAINT_ORIZ + """ + def getLimit(): + """ + Gets the type of constraint. + + See module L{GameLogic} for valid constraints. + + @return: + Position constraints: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY, KX_CONSTRAINTACT_LOCZ, + Rotation constraints: KX_CONSTRAINTACT_ROTX, KX_CONSTRAINTACT_ROTY, KX_CONSTRAINTACT_ROTZ, + Distance contraints: KX_ACT_CONSTRAINT_DIRPX, KX_ACT_CONSTRAINT_DIRPY, KX_ACT_CONSTRAINT_DIRPZ, KX_ACT_CONSTRAINT_DIRNX, KX_ACT_CONSTRAINT_DIRNY, KX_ACT_CONSTRAINT_DIRNZ, + Orientation constraints: KX_ACT_CONSTRAINT_ORIX, KX_ACT_CONSTRAINT_ORIY, KX_ACT_CONSTRAINT_ORIZ + """ + def setRotDamp(duration): + """ + Sets the time constant of the orientation constraint. + + @param duration: If the duration is negative, it is set to 0. + @type duration: integer + """ + def getRotDamp(): + """ + Returns the damping time for application of the constraint. + + @rtype: integer + """ + def setDirection(vector): + """ + Sets the reference direction in world coordinate for the orientation constraint + + @type vector: 3-tuple + """ + def getDirection(): + """ + Returns the reference direction of the orientation constraint in world coordinate. + + @rtype: 3-tuple + """ + def setOption(option): + """ + Sets several options of the distance constraint. + + @type option: integer + @param option: Binary combination of the following values: + 64 : Activate alignment to surface + 128 : Detect material rather than property + 256 : No deactivation if ray does not hit target + 512 : Activate distance control + """ + def getOption(): + """ + Returns the option parameter. + + @rtype: integer + """ + def setTime(duration): + """ + Sets the activation time of the actuator. + + @type duration: integer + @param duration: The actuator disables itself after this many frame. + If set to 0 or negative, the actuator is not limited in time. + """ + def getTime(): + """ + Returns the time parameter. + + @rtype: integer + """ + def setProperty(property): + """ + Sets the name of the property or material for the ray detection of the distance constraint. + + @type property: string + @param property: If empty, the ray will detect any collisioning object. + """ + def getProperty(): + """ + Returns the property parameter. + + @rtype: string + """ + def setDistance(distance): + """ + Sets the target distance in distance constraint. + + @type distance: float + """ + def getDistance(): + """ + Returns the distance parameter. + + @rtype: float + """ + def setRayLength(length): + """ + Sets the maximum ray length of the distance constraint. + + @type length: float + """ + def getRayLength(): + """ + Returns the length of the ray + + @rtype: float + """ +#} + +class KX_ConstraintWrapper(PyObjectPlus): + """ + KX_ConstraintWrapper + + """ + def getConstraintId(val): + """ + Returns the contraint's ID + + @rtype: integer + @return: the constraint's ID + """ + +class KX_GameActuator(SCA_IActuator): + """ + The game actuator loads a new .blend file, restarts the current .blend file or quits the game. + + Properties: + + @ivar fileName: the new .blend file to load + @type fileName: string. + @ivar mode: The mode of this actuator + @type mode: Constant in... + - L{GameLogic.KX_GAME_LOAD} + - L{GameLogic.KX_GAME_START} + - L{GameLogic.KX_GAME_RESTART} + - L{GameLogic.KX_GAME_QUIT} + - L{GameLogic.KX_GAME_SAVECFG} + - L{GameLogic.KX_GAME_LOADCFG} + """ +#{ Deprecated + def getFile(): + """ + Returns the filename of the new .blend file to load. + + @deprecated: use the L{fileName} property + @rtype: string + """ + def setFile(filename): + """ + Sets the new .blend file to load. + + @deprecated: use the L{fileName} property + @param filename: The file name this actuator will load. + @type filename: string + """ +#} + +class KX_GameObject(SCA_IObject): + """ + All game objects are derived from this class. + + Properties assigned to game objects are accessible as attributes of this class. + - note: Calling ANY method or attribute on an object that has been removed from a scene will raise a SystemError, if an object may have been removed since last accessing it use the L{invalid} attribute to check. + + @ivar name: The object's name. (read-only) + - note: Currently (Blender 2.49) the prefix "OB" is added to all objects name. This may change in blender 2.5. + @type name: string. + @ivar mass: The object's mass + - note: The object must have a physics controller for the mass to be applied, otherwise the mass value will be returned as 0.0 + @type mass: float + @ivar linVelocityMin: Enforces the object keeps moving at a minimum velocity. + - note: Applies to dynamic and rigid body objects only. + - note: A value of 0.0 disables this option. + - note: While objects are stationary the minimum velocity will not be applied. + @type linVelocityMin: float + @ivar linVelocityMax: Clamp the maximum linear velocity to prevent objects moving beyond a set speed. + - note: Applies to dynamic and rigid body objects only. + - note: A value of 0.0 disables this option (rather then setting it stationary). + @type linVelocityMax: float + @ivar localInertia: the object's inertia vector in local coordinates. Read only. + @type localInertia: list [ix, iy, iz] + @ivar parent: The object's parent object. (read-only) + @type parent: L{KX_GameObject} or None + @ivar visible: visibility flag. + - note: Game logic will still run for invisible objects. + @type visible: boolean + @ivar occlusion: occlusion capability flag. + @type occlusion: boolean + @ivar position: The object's position. + + deprecated: use L{localPosition} and L{worldPosition} + @type position: list [x, y, z] On write: local position, on read: world position + @ivar orientation: The object's orientation. 3x3 Matrix. You can also write a Quaternion or Euler vector. + + deprecated: use L{localOrientation} and L{worldOrientation} + @type orientation: 3x3 Matrix [[float]] On write: local orientation, on read: world orientation + @ivar scaling: The object's scaling factor. list [sx, sy, sz] + + deprecated: use L{localScale} and L{worldScale} + @type scaling: list [sx, sy, sz] On write: local scaling, on read: world scaling + @ivar localOrientation: The object's local orientation. 3x3 Matrix. You can also write a Quaternion or Euler vector. + @type localOrientation: 3x3 Matrix [[float]] + @ivar worldOrientation: The object's world orientation. + @type worldOrientation: 3x3 Matrix [[float]] + @ivar localScale: The object's local scaling factor. + @type localScale: list [sx, sy, sz] + @ivar worldScale: The object's world scaling factor. Read-only + @type worldScale: list [sx, sy, sz] + @ivar localPosition: The object's local position. + @type localPosition: list [x, y, z] + @ivar worldPosition: The object's world position. + @type worldPosition: list [x, y, z] + @ivar timeOffset: adjust the slowparent delay at runtime. + @type timeOffset: float + @ivar state: the game object's state bitmask, using the first 30 bits, one bit must always be set. + @type state: int + @ivar meshes: a list meshes for this object. + - note: Most objects use only 1 mesh. + - note: Changes to this list will not update the KX_GameObject. + @type meshes: list of L{KX_MeshProxy} + @ivar sensors: a sequence of L{SCA_ISensor} objects with string/index lookups and iterator support. + - note: This attribute is experemental and may be removed (but probably wont be). + - note: Changes to this list will not update the KX_GameObject. + @type sensors: list + @ivar controllers: a sequence of L{SCA_IController} objects with string/index lookups and iterator support. + - note: This attribute is experemental and may be removed (but probably wont be). + - note: Changes to this list will not update the KX_GameObject. + @type controllers: list of L{SCA_ISensor}. + @ivar actuators: a list of L{SCA_IActuator} with string/index lookups and iterator support. + - note: This attribute is experemental and may be removed (but probably wont be). + - note: Changes to this list will not update the KX_GameObject. + @type actuators: list + @ivar attrDict: get the objects internal python attribute dictionary for direct (faster) access. + @type attrDict: dict + @ivar children: direct children of this object, (read-only). + @type children: L{CListValue} of L{KX_GameObject}'s + @ivar childrenRecursive: all children of this object including childrens children, (read-only). + @type childrenRecursive: L{CListValue} of L{KX_GameObject}'s + @group Deprecated: getPosition, setPosition, setWorldPosition, getOrientation, setOrientation, getState, setState, getParent, getVisible, getMass, getMesh, getChildren, getChildrenRecursive + @group Property Access: get, attrDict, getPropertyNames + """ + def endObject(): + """ + Delete this object, can be used inpace of the EndObject Actuator. + The actual removal of the object from the scene is delayed. + """ + def replaceMesh(mesh, useDisplayMesh=True, usePhysicsMesh=False): + """ + Replace the mesh of this object with a new mesh. This works the same was as the actuator. + @type mesh: L{KX_MeshProxy} or mesh name + @type useDisplayMesh: bool + @param useDisplayMesh: when enabled the display mesh will be replaced (optional argument). + @type usePhysicsMesh: bool + @param usePhysicsMesh: when enabled the physics mesh will be replaced (optional argument). + """ + def getVisible(): + """ + Gets the game object's visible flag. + + @deprecated: use L{visible} + @rtype: boolean + """ + def setVisible(visible, recursive): + """ + Sets the game object's visible flag. + + @type visible: boolean + @type recursive: boolean + @param recursive: optional argument to set all childrens visibility flag too. + """ + def setOcclusion(occlusion, recursive): + """ + Sets the game object's occlusion capability. + + @type occlusion: boolean + @type recursive: boolean + @param recursive: optional argument to set all childrens occlusion flag too. + """ + def getState(): + """ + Gets the game object's state bitmask. + + @deprecated: use L{state} + @rtype: int + @return: the objects state. + """ + def setState(state): + """ + Sets the game object's state flag. + The bitmasks for states from 1 to 30 can be set with (1<<0, 1<<1, 1<<2 ... 1<<29) + @deprecated: use L{state} + @type state: integer + """ + def setPosition(pos): + """ + Sets the game object's position. + Global coordinates for root object, local for child objects. + + @deprecated: use L{localPosition} + @type pos: [x, y, z] + @param pos: the new position, in local coordinates. + """ + def setWorldPosition(pos): + """ + Sets the game object's position in world coordinates regardless if the object is root or child. + + @deprecated: use L{worldPosition} + @type pos: [x, y, z] + @param pos: the new position, in world coordinates. + """ + def getPosition(): + """ + Gets the game object's position. + + @deprecated: use L{worldPosition} + @rtype: list [x, y, z] + @return: the object's position in world coordinates. + """ + def setOrientation(orn): + """ + Sets the game object's orientation. + + @deprecated: use L{localOrientation} + @type orn: 3x3 rotation matrix, or Quaternion. + @param orn: a rotation matrix specifying the new rotation. + @note: When using this matrix with Blender.Mathutils.Matrix() types, it will need to be transposed. + """ + def alignAxisToVect(vect, axis, factor): + """ + Aligns any of the game object's axis along the given vector. + + @type vect: 3d vector. + @param vect: a vector to align the axis. + @type axis: integer. + @param axis:The axis you want to align + - 0: X axis + - 1: Y axis + - 2: Z axis (default) + @type factor: float + @param factor: Only rotate a feaction of the distance to the target vector (0.0 - 1.0) + """ + def getAxisVect(vect): + """ + Returns the axis vector rotates by the objects worldspace orientation. + This is the equivalent if multiplying the vector by the orientation matrix. + + @type vect: 3d vector. + @param vect: a vector to align the axis. + @rtype: 3d vector. + @return: The vector in relation to the objects rotation. + + """ + def getOrientation(): + """ + Gets the game object's orientation. + + @deprecated: use L{worldOrientation} + @rtype: 3x3 rotation matrix + @return: The game object's rotation matrix + @note: When using this matrix with Blender.Mathutils.Matrix() types, it will need to be transposed. + """ + def applyMovement(movement, local = 0): + """ + Sets the game object's movement. + + @type movement: 3d vector. + @param movement: movement vector. + @type local: boolean + @param local: - False: you get the "global" movement ie: relative to world orientation (default). + - True: you get the "local" movement ie: relative to object orientation. + """ + def applyRotation(rotation, local = 0): + """ + Sets the game object's rotation. + + @type rotation: 3d vector. + @param rotation: rotation vector. + @type local: boolean + @param local: - False: you get the "global" rotation ie: relative to world orientation (default). + - True: you get the "local" rotation ie: relative to object orientation. + """ + def applyForce(force, local = 0): + """ + Sets the game object's force. + + This requires a dynamic object. + + @type force: 3d vector. + @param force: force vector. + @type local: boolean + @param local: - False: you get the "global" force ie: relative to world orientation (default). + - True: you get the "local" force ie: relative to object orientation. + """ + def applyTorque(torque, local = 0): + """ + Sets the game object's torque. + + This requires a dynamic object. + + @type torque: 3d vector. + @param torque: torque vector. + @type local: boolean + @param local: - False: you get the "global" torque ie: relative to world orientation (default). + - True: you get the "local" torque ie: relative to object orientation. + """ + def getLinearVelocity(local = 0): + """ + Gets the game object's linear velocity. + + This method returns the game object's velocity through it's centre of mass, + ie no angular velocity component. + + @type local: boolean + @param local: - False: you get the "global" velocity ie: relative to world orientation (default). + - True: you get the "local" velocity ie: relative to object orientation. + @rtype: list [vx, vy, vz] + @return: the object's linear velocity. + """ + def setLinearVelocity(velocity, local = 0): + """ + Sets the game object's linear velocity. + + This method sets game object's velocity through it's centre of mass, + ie no angular velocity component. + + This requires a dynamic object. + + @type velocity: 3d vector. + @param velocity: linear velocity vector. + @type local: boolean + @param local: - False: you get the "global" velocity ie: relative to world orientation (default). + - True: you get the "local" velocity ie: relative to object orientation. + """ + def getAngularVelocity(local = 0): + """ + Gets the game object's angular velocity. + + @type local: boolean + @param local: - False: you get the "global" velocity ie: relative to world orientation (default). + - True: you get the "local" velocity ie: relative to object orientation. + @rtype: list [vx, vy, vz] + @return: the object's angular velocity. + """ + def setAngularVelocity(velocity, local = 0): + """ + Sets the game object's angular velocity. + + This requires a dynamic object. + + @type velocity: 3d vector. + @param velocity: angular velocity vector. + @type local: boolean + @param local: - False: you get the "global" velocity ie: relative to world orientation (default). + - True: you get the "local" velocity ie: relative to object orientation. + """ + def getVelocity(point): + """ + Gets the game object's velocity at the specified point. + + Gets the game object's velocity at the specified point, including angular + components. + + @type point: list [x, y, z] + @param point: the point to return the velocity for, in local coordinates. (optional: default = [0, 0, 0]) + @rtype: list [vx, vy, vz] + @return: the velocity at the specified point. + """ + def getMass(): + """ + Gets the game object's mass. + + @deprecated: use L{mass} + @rtype: float + @return: the object's mass. + """ + def getReactionForce(): + """ + Gets the game object's reaction force. + + The reaction force is the force applied to this object over the last simulation timestep. + This also includes impulses, eg from collisions. + + (B{This is not implimented for bullet physics at the moment}) + + @rtype: list [fx, fy, fz] + @return: the reaction force of this object. + """ + def applyImpulse(point, impulse): + """ + Applies an impulse to the game object. + + This will apply the specified impulse to the game object at the specified point. + If point != getPosition(), applyImpulse will also change the object's angular momentum. + Otherwise, only linear momentum will change. + + @type point: list [x, y, z] + @param point: the point to apply the impulse to (in world coordinates) + """ + def suspendDynamics(): + """ + Suspends physics for this object. + """ + def restoreDynamics(): + """ + Resumes physics for this object. + @Note: The objects linear velocity will be applied from when the dynamics were suspended. + """ + def enableRigidBody(): + """ + Enables rigid body physics for this object. + + Rigid body physics allows the object to roll on collisions. + @Note: This is not working with bullet physics yet. + """ + def disableRigidBody(): + """ + Disables rigid body physics for this object. + @Note: This is not working with bullet physics yet. The angular is removed but rigid body physics can still rotate it later. + """ + def getParent(): + """ + Gets this object's parent. + + @deprecated: use L{parent} + @rtype: L{KX_GameObject} + @return: this object's parent object, or None if this object has no parent. + """ + def setParent(parent,compound,ghost): + """ + Sets this object's parent. + Control the shape status with the optional compound and ghost parameters: + compound=1: the object shape should be added to the parent compound shape (default) + compound=0: the object should keep its individual shape. + In that case you can control if it should be ghost or not: + ghost=1 if the object should be made ghost while parented (default) + ghost=0 if the object should be solid while parented + Note: if the object type is sensor, it stays ghost regardless of ghost parameter + + @type parent: L{KX_GameObject} + @param parent: new parent object. + @type compound: int + @param compound: whether the shape should be added to the parent compound shape + @type ghost: int + @param ghost: whether the object should be ghost while parented + """ + def removeParent(): + """ + Removes this objects parent. + """ + def getChildren(): + """ + Return a list of immediate children of this object. + @rtype: L{CListValue} of L{KX_GameObject} + @return: a list of all this objects children. + """ + def getChildrenRecursive(): + """ + Return a list of children of this object, including all their childrens children. + @rtype: L{CListValue} of L{KX_GameObject} + @return: a list of all this objects children recursivly. + """ + def getMesh(mesh): + """ + Gets the mesh object for this object. + + @type mesh: integer + @param mesh: the mesh object to return (optional: default mesh = 0) + @rtype: L{KX_MeshProxy} + @return: the first mesh object associated with this game object, or None if this object has no meshs. + """ + def getPhysicsId(): + """ + Returns the user data object associated with this game object's physics controller. + """ + def getPropertyNames(): + """ + Gets a list of all property names. + @rtype: list + @return: All property names for this object. + """ + def getDistanceTo(other): + """ + Returns the distance to another object or point. + + @param other: a point or another L{KX_GameObject} to measure the distance to. + @type other: L{KX_GameObject} or list [x, y, z] + @rtype: float + """ + def getVectTo(other): + """ + Returns the vector and the distance to another object or point. + The vector is normalized unless the distance is 0, in which a NULL vector is returned. + + @param other: a point or another L{KX_GameObject} to get the vector and distance to. + @type other: L{KX_GameObject} or list [x, y, z] + @rtype: 3-tuple (float, 3-tuple (x,y,z), 3-tuple (x,y,z)) + @return: (distance, globalVector(3), localVector(3)) + """ + def rayCastTo(other,dist,prop): + """ + Look towards another point/object and find first object hit within dist that matches prop. + + The ray is always casted from the center of the object, ignoring the object itself. + The ray is casted towards the center of another object or an explicit [x,y,z] point. + Use rayCast() if you need to retrieve the hit point + + @param other: [x,y,z] or object towards which the ray is casted + @type other: L{KX_GameObject} or 3-tuple + @param dist: max distance to look (can be negative => look behind); 0 or omitted => detect up to other + @type dist: float + @param prop: property name that object must have; can be omitted => detect any object + @type prop: string + @rtype: L{KX_GameObject} + @return: the first object hit or None if no object or object does not match prop + """ + def rayCast(objto,objfrom,dist,prop,face,xray,poly): + """ + Look from a point/object to another point/object and find first object hit within dist that matches prop. + if poly is 0, returns a 3-tuple with object reference, hit point and hit normal or (None,None,None) if no hit. + if poly is 1, returns a 4-tuple with in addition a L{KX_PolyProxy} as 4th element. + + Ex:: + # shoot along the axis gun-gunAim (gunAim should be collision-free) + ob,point,normal = gun.rayCast(gunAim,None,50) + if ob: + # hit something + + Notes: + The ray ignores the object on which the method is called. + It is casted from/to object center or explicit [x,y,z] points. + + The face paremeter determines the orientation of the normal:: + 0 => hit normal is always oriented towards the ray origin (as if you casted the ray from outside) + 1 => hit normal is the real face normal (only for mesh object, otherwise face has no effect) + + The ray has X-Ray capability if xray parameter is 1, otherwise the first object hit (other than self object) stops the ray. + The prop and xray parameters interact as follow:: + prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray. + prop off, xray on : idem. + prop on, xray off: return closest hit if it matches prop, no hit otherwise. + prop on, xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray. + The L{KX_PolyProxy} 4th element of the return tuple when poly=1 allows to retrieve information on the polygon hit by the ray. + If there is no hit or the hit object is not a static mesh, None is returned as 4th element. + + The ray ignores collision-free objects and faces that dont have the collision flag enabled, you can however use ghost objects. + + @param objto: [x,y,z] or object to which the ray is casted + @type objto: L{KX_GameObject} or 3-tuple + @param objfrom: [x,y,z] or object from which the ray is casted; None or omitted => use self object center + @type objfrom: L{KX_GameObject} or 3-tuple or None + @param dist: max distance to look (can be negative => look behind); 0 or omitted => detect up to to + @type dist: float + @param prop: property name that object must have; can be omitted or "" => detect any object + @type prop: string + @param face: normal option: 1=>return face normal; 0 or omitted => normal is oriented towards origin + @type face: int + @param xray: X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object + @type xray: int + @param poly: polygon option: 1=>return value is a 4-tuple and the 4th element is a L{KX_PolyProxy} + @type poly: int + @rtype: 3-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz)) + or 4-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz), L{KX_PolyProxy}) + @return: (object,hitpoint,hitnormal) or (object,hitpoint,hitnormal,polygon) + If no hit, returns (None,None,None) or (None,None,None,None) + If the object hit is not a static mesh, polygon is None + """ + def setCollisionMargin(margin): + """ + Set the objects collision margin. + + note: If this object has no physics controller (a physics ID of zero), this function will raise RuntimeError. + + @type margin: float + @param margin: the collision margin distance in blender units. + """ + def sendMessage(subject, body="", to=""): + """ + Sends a message. + + @param subject: The subject of the message + @type subject: string + @param body: The body of the message (optional) + @type body: string + @param to: The name of the object to send the message to (optional) + @type to: string + """ + def reinstancePhysicsMesh(gameObject, meshObject): + """ + Updates the physics system with the changed mesh. + + If no arguments are given the physics mesh will be re-created from the first mesh assigned to the game object. + + @param gameObject: optional argument, set the physics shape from this gameObjets mesh. + @type gameObject: string, L{KX_GameObject} or None + @param meshObject: optional argument, set the physics shape from this mesh. + @type meshObject: string, L{KX_MeshProxy} or None + + @note: if this object has instances the other instances will be updated too. + @note: the gameObject argument has an advantage that it can convert from a mesh with modifiers applied (such as subsurf). + @warning: only triangle mesh type objects are supported currently (not convex hull) + @warning: if the object is a part of a combound object it will fail (parent or child) + @warning: rebuilding the physics mesh can be slow, running many times per second will give a performance hit. + @rtype: boolean + @return: True if reinstance succeeded, False if it failed. + """ + + def get(key, default=None): + """ + Return the value matching key, or the default value if its not found. + @return: The key value or a default. + """ + + +class KX_IpoActuator(SCA_IActuator): + """ + IPO actuator activates an animation. + + @ivar frameStart: Start frame. + @type frameStart: float + @ivar frameEnd: End frame. + @type frameEnd: float + @ivar propName: Use this property to define the Ipo position + @type propName: string + @ivar framePropName: Assign this property this action current frame number + @type framePropName: string + @ivar mode: Play mode for the ipo. (In GameLogic.KX_IPOACT_PLAY, KX_IPOACT_PINGPONG, KX_IPOACT_FLIPPER, KX_IPOACT_LOOPSTOP, KX_IPOACT_LOOPEND, KX_IPOACT_FROM_PROP) + @type mode: int + @ivar useIpoAsForce: Apply Ipo as a global or local force depending on the local option (dynamic objects only) + @type useIpoAsForce: bool + @ivar useIpoAdd: Ipo is added to the current loc/rot/scale in global or local coordinate according to Local flag + @type useIpoAdd: bool + @ivar useIpoLocal: Let the ipo acts in local coordinates, used in Force and Add mode. + @type useIpoLocal: bool + @ivar useChildren: Update IPO on all children Objects as well + @type useChildren: bool + """ +#{ Deprecated + def set(mode, startframe, endframe, force): + """ + Sets the properties of the actuator. + + @deprecated: use other attributes. + @param mode: "Play", "PingPong", "Flipper", "LoopStop", "LoopEnd" or "FromProp" + @type mode: string + @param startframe: first frame to use + @type startframe: integer + @param endframe: last frame to use + @type endframe: integer + @param force: special mode + @type force: integer (0=normal, 1=interpret location as force, 2=additive) + """ + def setProperty(property): + """ + Sets the name of the property to be used in FromProp mode. + + @deprecated: use L{propName} + @type property: string + """ + def setStart(startframe): + """ + Sets the frame from which the IPO starts playing. + + @deprecated: use L{frameStart} + @type startframe: integer + """ + def getStart(): + """ + Returns the frame from which the IPO starts playing. + + @deprecated: use L{frameStart} + @rtype: integer + """ + def setEnd(endframe): + """ + Sets the frame at which the IPO stops playing. + + @deprecated: use L{frameEnd} + @type endframe: integer + """ + def getEnd(): + """ + Returns the frame at which the IPO stops playing. + + @deprecated: use L{frameEnd} + @rtype: integer + """ + def setIpoAsForce(force): + """ + Set whether to interpret the ipo as a force rather than a displacement. + + @deprecated: use L{useIpoAsForce} + @type force: boolean + @param force: KX_TRUE or KX_FALSE + """ + def getIpoAsForce(): + """ + Returns whether to interpret the ipo as a force rather than a displacement. + + @deprecated: use L{useIpoAsForce} + @rtype: boolean + """ + def setIpoAdd(add): + """ + Set whether to interpret the ipo as additive rather than absolute. + + @deprecated: use L{useIpoAdd} + @type add: boolean + @param add: KX_TRUE or KX_FALSE + """ + def getIpoAdd(): + """ + Returns whether to interpret the ipo as additive rather than absolute. + + @deprecated: use L{useIpoAdd} + @rtype: boolean + """ + def setType(mode): + """ + Sets the operation mode of the actuator. + + @deprecated: use L{type} + @param mode: KX_IPOACT_PLAY, KX_IPOACT_PINGPONG, KX_IPOACT_FLIPPER, KX_IPOACT_LOOPSTOP, KX_IPOACT_LOOPEND + @type mode: string + """ + def getType(): + """ + Returns the operation mode of the actuator. + + @deprecated: use L{type} + @rtype: integer + @return: KX_IPOACT_PLAY, KX_IPOACT_PINGPONG, KX_IPOACT_FLIPPER, KX_IPOACT_LOOPSTOP, KX_IPOACT_LOOPEND + """ + def setForceIpoActsLocal(local): + """ + Set whether to apply the force in the object's local + coordinates rather than the world global coordinates. + + @deprecated: use L{useIpoLocal} + @param local: Apply the ipo-as-force in the object's local + coordinates? (KX_TRUE, KX_FALSE) + @type local: boolean + """ + def getForceIpoActsLocal(): + """ + Return whether to apply the force in the object's local + coordinates rather than the world global coordinates. + + @deprecated: use L{useIpoLocal} + """ +#} + +class KX_LightObject(KX_GameObject): + """ + A Light object. + + Example: + + # Turn on a red alert light. + import GameLogic + + co = GameLogic.getCurrentController() + light = co.owner + + light.energy = 1.0 + light.colour = [1.0, 0.0, 0.0] + + @group Constants: NORMAL, SPOT, SUN + @ivar SPOT: A spot light source. See attribute 'type' + @ivar SUN: A point light source with no attenuation. See attribute 'type' + @ivar NORMAL: A point light source. See attribute 'type' + + @ivar type: The type of light - must be SPOT, SUN or NORMAL + @ivar layer: The layer mask that this light affects object on. + @type layer: bitfield + @ivar energy: The brightness of this light. + @type energy: float + @ivar distance: The maximum distance this light can illuminate. (SPOT and NORMAL lights only) + @type distance: float + @ivar colour: The colour of this light. Black = [0.0, 0.0, 0.0], White = [1.0, 1.0, 1.0] + @type colour: list [r, g, b] + @ivar color: Synonym for colour. + @ivar lin_attenuation: The linear component of this light's attenuation. (SPOT and NORMAL lights only) + @type lin_attenuation: float + @ivar quad_attenuation: The quadratic component of this light's attenuation (SPOT and NORMAL lights only) + @type quad_attenuation: float + @ivar spotsize: The cone angle of the spot light, in degrees. (float) (SPOT lights only) + 0.0 <= spotsize <= 180.0. Spotsize = 360.0 is also accepted. + @ivar spotblend: Specifies the intensity distribution of the spot light. (float) (SPOT lights only) + Higher values result in a more focused light source. + 0.0 <= spotblend <= 1.0. + + """ + +class KX_MeshProxy(SCA_IObject): + """ + A mesh object. + + You can only change the vertex properties of a mesh object, not the mesh topology. + + To use mesh objects effectively, you should know a bit about how the game engine handles them. + 1. Mesh Objects are converted from Blender at scene load. + 2. The Converter groups polygons by Material. This means they can be sent to the + renderer efficiently. A material holds: + 1. The texture. + 2. The Blender material. + 3. The Tile properties + 4. The face properties - (From the "Texture Face" panel) + 5. Transparency & z sorting + 6. Light layer + 7. Polygon shape (triangle/quad) + 8. Game Object + 3. Verticies will be split by face if necessary. Verticies can only be shared between + faces if: + 1. They are at the same position + 2. UV coordinates are the same + 3. Their normals are the same (both polygons are "Set Smooth") + 4. They are the same colour + For example: a cube has 24 verticies: 6 faces with 4 verticies per face. + + The correct method of iterating over every L{KX_VertexProxy} in a game object:: + import GameLogic + + co = GameLogic.getCurrentController() + obj = co.owner + + m_i = 0 + mesh = obj.getMesh(m_i) # There can be more than one mesh... + while mesh != None: + for mat in range(mesh.getNumMaterials()): + for v_index in range(mesh.getVertexArrayLength(mat)): + vertex = mesh.getVertex(mat, v_index) + # Do something with vertex here... + # ... eg: colour the vertex red. + vertex.colour = [1.0, 0.0, 0.0, 1.0] + m_i += 1 + mesh = obj.getMesh(m_i) + + @ivar materials: + @type materials: list of L{KX_BlenderMaterial} or L{KX_PolygonMaterial} types + + @ivar numPolygons: + @type numPolygons: integer + + @ivar numMaterials: + @type numMaterials: integer + """ + + def getNumMaterials(): + """ + Gets the number of materials associated with this object. + + @rtype: integer + """ + + def getMaterialName(matid): + """ + Gets the name of the specified material. + + @type matid: integer + @param matid: the specified material. + @rtype: string + @return: the attached material name. + """ + def getTextureName(matid): + """ + Gets the name of the specified material's texture. + + @type matid: integer + @param matid: the specified material + @rtype: string + @return: the attached material's texture name. + """ + def getVertexArrayLength(matid): + """ + Gets the length of the vertex array associated with the specified material. + + There is one vertex array for each material. + + @type matid: integer + @param matid: the specified material + @rtype: integer + @return: the number of verticies in the vertex array. + """ + def getVertex(matid, index): + """ + Gets the specified vertex from the mesh object. + + @type matid: integer + @param matid: the specified material + @type index: integer + @param index: the index into the vertex array. + @rtype: L{KX_VertexProxy} + @return: a vertex object. + """ + def getNumPolygons(): + """ + Returns the number of polygon in the mesh. + + @rtype: integer + """ + def getPolygon(index): + """ + Gets the specified polygon from the mesh. + + @type index: integer + @param index: polygon number + @rtype: L{KX_PolyProxy} + @return: a polygon object. + """ + +class SCA_MouseSensor(SCA_ISensor): + """ + Mouse Sensor logic brick. + + Properties: + + @ivar position: current [x,y] coordinates of the mouse, in frame coordinates (pixels) + @type position: [integer,interger] + @ivar mode: sensor mode: 1=KX_MOUSESENSORMODE_LEFTBUTTON 2=KX_MOUSESENSORMODE_MIDDLEBUTTON + 3=KX_MOUSESENSORMODE_RIGHTBUTTON 4=KX_MOUSESENSORMODE_WHEELUP + 5=KX_MOUSESENSORMODE_WHEELDOWN 9=KX_MOUSESENSORMODE_MOVEMENT + @type mode: integer + """ + + def getXPosition(): + """ + Gets the x coordinate of the mouse. + + @deprecated: use the L{position} property + @rtype: integer + @return: the current x coordinate of the mouse, in frame coordinates (pixels) + """ + def getYPosition(): + """ + Gets the y coordinate of the mouse. + + @deprecated: use the L{position} property + @rtype: integer + @return: the current y coordinate of the mouse, in frame coordinates (pixels). + """ + def getButtonStatus(button): + """ + Get the mouse button status. + + @type button: int + @param button: value in GameLogic members KX_MOUSE_BUT_LEFT, KX_MOUSE_BUT_MIDDLE, KX_MOUSE_BUT_RIGHT + + @rtype: integer + @return: value in GameLogic members KX_INPUT_NONE, KX_INPUT_NONE, KX_INPUT_JUST_ACTIVATED, KX_INPUT_ACTIVE, KX_INPUT_JUST_RELEASED + """ + +class KX_MouseFocusSensor(SCA_MouseSensor): + """ + The mouse focus sensor detects when the mouse is over the current game object. + + The mouse focus sensor works by transforming the mouse coordinates from 2d device + space to 3d space then raycasting away from the camera. + + @ivar raySource: The worldspace source of the ray (the view position) + @type raySource: list (vector of 3 floats) + @ivar rayTarget: The worldspace target of the ray. + @type rayTarget: list (vector of 3 floats) + @ivar rayDirection: The L{rayTarget} - L{raySource} normalized. + @type rayDirection: list (normalized vector of 3 floats) + @ivar hitObject: the last object the mouse was over. + @type hitObject: L{KX_GameObject} or None + @ivar hitPosition: The worldspace position of the ray intersecton. + @type hitPosition: list (vector of 3 floats) + @ivar hitNormal: the worldspace normal from the face at point of intersection. + @type hitNormal: list (normalized vector of 3 floats) + @ivar usePulseFocus: When enabled, moving the mouse over a different object generates a pulse. (only used when the 'Mouse Over Any' sensor option is set) + @type usePulseFocus: bool + """ +#{ Deprecated + def getHitNormal(): + """ + Returns the normal (in worldcoordinates) at the point of collision where the object was hit by this ray. + + @deprecated: use the L{hitNormal} property + @rtype: list [x, y, z] + @return: the ray collision normal. + """ + def getHitObject(): + """ + Returns the object that was hit by this ray or None. + + @deprecated: use the L{hitObject} property + @rtype: L{KX_GameObject} or None + @return: the collision object. + """ + def getHitPosition(): + """ + Returns the position (in worldcoordinates) at the point of collision where the object was hit by this ray. + + @deprecated: use the L{hitPosition} property + @rtype: list [x, y, z] + @return: the ray collision position. + """ + def getRayDirection(): + """ + Returns the normalized direction (in worldcoordinates) of the ray cast by the mouse. + + @deprecated: use the L{rayDirection} property + @rtype: list [x, y, z] + @return: the ray direction. + """ + def getRaySource(): + """ + Returns the position (in worldcoordinates) the ray was cast from by the mouse. + + @deprecated: use the L{raySource} property + @rtype: list [x, y, z] + @return: the ray source. + """ + def getRayTarget(): + """ + Returns the target of the ray (in worldcoordinates) that seeks the focus object. + + @deprecated: use the L{rayTarget} property + @rtype: list [x, y, z] + @return: the ray target. + """ +#} + +class KX_TouchSensor(SCA_ISensor): + """ + Touch sensor detects collisions between objects. + + @ivar propName: The property or material to collide with. + @type propName: string + @ivar useMaterial: Determines if the sensor is looking for a property or material. + KX_True = Find material; KX_False = Find property + @type useMaterial: boolean + @ivar usePulseCollision: When enabled, changes to the set of colliding objects generate a pulse. + @type usePulseCollision: bool + @ivar hitObject: The last collided object. (read-only) + @type hitObject: L{KX_GameObject} or None + @ivar hitObjectList: A list of colliding objects. (read-only) + @type hitObjectList: L{CListValue} of L{KX_GameObject} + """ +#{ Deprecated + def setProperty(name): + """ + Set the property or material to collide with. Use + setTouchMaterial() to switch between properties and + materials. + + @deprecated: use the L{property} property + @type name: string + """ + + def getProperty(): + """ + Returns the property or material to collide with. Use + getTouchMaterial() to find out whether this sensor + looks for properties or materials. + + @deprecated: use the L{property} property + @rtype: string + """ + def getHitObject(): + """ + Returns the last object hit by this touch sensor. + + @deprecated: use the L{hitObject} property + @rtype: L{KX_GameObject} + """ + def getHitObjectList(): + """ + Returns a list of all objects hit in the last frame. (B{deprecated}) + + Only objects that have the requisite material/property are listed. + + @deprecated: use the L{hitObjectList} property + @rtype: L{CListValue} of L{hitObjectList} + """ + def getTouchMaterial(): + """ + Returns KX_TRUE if this sensor looks for a specific material, + KX_FALSE if it looks for a specific property. (B{deprecated}) + + @deprecated: use the L{useMaterial} property + """ +#} + +class KX_NearSensor(KX_TouchSensor): + """ + A near sensor is a specialised form of touch sensor. + + @ivar distance: The near sensor activates when an object is within this distance. + @type distance: float + @ivar resetDistance: The near sensor deactivates when the object exceeds this distance. + @type resetDistance: float + """ + +class KX_NetworkMessageActuator(SCA_IActuator): + """ + Message Actuator + + @ivar propName: Messages will only be sent to objects with the given property name. + @type propName: string + @ivar subject: The subject field of the message. + @type subject: string + @ivar body: The body of the message. + @type body: string + @ivar usePropBody: Send a property instead of a regular body message. + @type usePropBody: boolean + """ +#{Deprecated + def setToPropName(name): + """ + Messages will only be sent to objects with the given property name. + + @deprecated: Use the L{propName} attribute instead. + @type name: string + """ + def setSubject(subject): + """ + Sets the subject field of the message. + + @deprecated: Use the L{subject} attribute instead. + @type subject: string + """ + def setBodyType(bodytype): + """ + Sets the type of body to send. + + @deprecated: Use the L{usePropBody} attribute instead. + @type bodytype: boolean + @param bodytype: True to send the value of a property, False to send the body text. + """ + def setBody(body): + """ + Sets the message body. + + @deprecated: Use the L{body} attribute instead. + @type body: string + @param body: if the body type is True, this is the name of the property to send. + if the body type is False, this is the text to send. + """ +#} + +class KX_NetworkMessageSensor(SCA_ISensor): + """ + The Message Sensor logic brick. + + Currently only loopback (local) networks are supported. + + @ivar subject: The subject the sensor is looking for. + @type subject: string + @ivar frameMessageCount: The number of messages received since the last frame. + (Read-only) + @type frameMessageCount: int + @ivar subjects: The list of message subjects received. (Read-only) + @type subjects: list of strings + @ivar bodies: The list of message bodies received. (Read-only) + @type bodies: list of strings + """ +#{ Deprecated + def setSubjectFilterText(subject): + """ + Change the message subject text that this sensor is listening to. + + @deprecated: Use the L{subject} attribute instead. + @type subject: string + @param subject: the new message subject to listen for. + """ + + def getFrameMessageCount(): + """ + Get the number of messages received since the last frame. + + @deprecated: Use the L{frameMessageCount} attribute instead. + @rtype: integer + """ + def getBodies(): + """ + Gets the list of message bodies. + + @deprecated: Use the L{bodies} attribute instead. + @rtype: list + """ + def getSubject(): + """ + Gets the message subject this sensor is listening for from the Subject: field. + + @deprecated: Use the L{subject} attribute instead. + @rtype: string + """ + def getSubjects(): + """ + Gets the list of message subjects received. + + @deprecated: Use the L{subjects} attribute instead. + @rtype: list + """ +#} + +class KX_ObjectActuator(SCA_IActuator): + """ + The object actuator ("Motion Actuator") applies force, torque, displacement, angular displacement, + velocity, or angular velocity to an object. + Servo control allows to regulate force to achieve a certain speed target. + + @ivar force: The force applied by the actuator + @type force: list [x, y, z] + @ivar useLocalForce: A flag specifying if the force is local + @type useLocalForce: bool + @ivar torque: The torque applied by the actuator + @type torque: list [x, y, z] + @ivar useLocalTorque: A flag specifying if the torque is local + @type useLocalTorque: bool + @ivar dLoc: The displacement vector applied by the actuator + @type dLoc: list [x, y, z] + @ivar useLocalDLoc: A flag specifying if the dLoc is local + @type useLocalDLoc: bool + @ivar dRot: The angular displacement vector applied by the actuator + - note: Since the displacement is applied every frame, you must adjust the displacement + based on the frame rate, or you game experience will depend on the player's computer + speed. + @type dRot: list [x, y, z] + @ivar useLocalDRot: A flag specifying if the dRot is local + @type useLocalDRot: bool + @ivar linV: The linear velocity applied by the actuator + @type linV: list [x, y, z] + @ivar useLocalLinV: A flag specifying if the linear velocity is local + - note: This is the target speed for servo controllers + @type useLocalLinV: bool + @ivar angV: The angular velocity applied by the actuator + @type angV: list [x, y, z] + @ivar useLocalAngV: A flag specifying if the angular velocity is local + @type useLocalAngV: bool + + @ivar damping: The damping parameter of the servo controller + @type damping: short + + @ivar forceLimitX: The min/max force limit along the X axis and activates or deactivates the limits in the servo controller + @type forceLimitX: list [min(float), max(float), bool] + @ivar forceLimitY: The min/max force limit along the Y axis and activates or deactivates the limits in the servo controller + @type forceLimitY: list [min(float), max(float), bool] + @ivar forceLimitZ: The min/max force limit along the Z axis and activates or deactivates the limits in the servo controller + @type forceLimitZ: list [min(float), max(float), bool] + + @ivar pid: The PID coefficients of the servo controller + @type pid: list of floats [proportional, integral, derivate] + @ivar reference: The object that is used as reference to compute the velocity for the servo controller. + @type reference: KX_GameObject or None + + @group Deprecated: getForce, setForce, getTorque, setTorque, getDLoc, setDLoc, getDRot, setDRot, getLinearVelocity, setLinearVelocity, getAngularVelocity, + setAngularVelocity, getDamping, setDamping, getForceLimitX, setForceLimitX, getForceLimitY, setForceLimitY, getForceLimitZ, setForceLimitZ, + getPID, setPID + """ + def getForce(): + """ + Returns the force applied by the actuator. + + @deprecated: Use L{force} and L{useLocalForce} instead. + @rtype: list [fx, fy, fz, local] + @return: A four item list, containing the vector force, and a flag specifying whether the force is local. + """ + def setForce(fx, fy, fz, local): + """ + Sets the force applied by the actuator. + + @deprecated: Use L{force} and L{useLocalForce} instead. + @type fx: float + @param fx: the x component of the force. + @type fy: float + @param fy: the z component of the force. + @type fz: float + @param fz: the z component of the force. + @type local: boolean + @param local: - False: the force is applied in world coordinates. + - True: the force is applied in local coordinates. + """ + def getTorque(): + """ + Returns the torque applied by the actuator. + + @deprecated: Use L{torque} and L{useLocalTorque} instead. + @rtype: list [S{Tau}x, S{Tau}y, S{Tau}z, local] + @return: A four item list, containing the vector torque, and a flag specifying whether + the torque is applied in local coordinates (True) or world coordinates (False) + """ + def setTorque(tx, ty, tz, local): + """ + Sets the torque applied by the actuator. + + @deprecated: Use L{torque} and L{useLocalTorque} instead. + @type tx: float + @param tx: the x component of the torque. + @type ty: float + @param ty: the z component of the torque. + @type tz: float + @param tz: the z component of the torque. + @type local: boolean + @param local: - False: the torque is applied in world coordinates. + - True: the torque is applied in local coordinates. + """ + def getDLoc(): + """ + Returns the displacement vector applied by the actuator. + + @deprecated: Use L{dLoc} and L{useLocalDLoc} instead. + @rtype: list [dx, dy, dz, local] + @return: A four item list, containing the vector displacement, and whether + the displacement is applied in local coordinates (True) or world + coordinates (False) + """ + def setDLoc(dx, dy, dz, local): + """ + Sets the displacement vector applied by the actuator. + + Since the displacement is applied every frame, you must adjust the displacement + based on the frame rate, or you game experience will depend on the player's computer + speed. + + @deprecated: Use L{dLoc} and L{useLocalDLoc} instead. + @type dx: float + @param dx: the x component of the displacement vector. + @type dy: float + @param dy: the z component of the displacement vector. + @type dz: float + @param dz: the z component of the displacement vector. + @type local: boolean + @param local: - False: the displacement vector is applied in world coordinates. + - True: the displacement vector is applied in local coordinates. + """ + def getDRot(): + """ + Returns the angular displacement vector applied by the actuator. + + @deprecated: Use L{dRot} and L{useLocalDRot} instead. + @rtype: list [dx, dy, dz, local] + @return: A four item list, containing the angular displacement vector, and whether + the displacement is applied in local coordinates (True) or world coordinates (False) + """ + def setDRot(dx, dy, dz, local): + """ + Sets the angular displacement vector applied by the actuator. + + Since the displacement is applied every frame, you must adjust the displacement + based on the frame rate, or you game experience will depend on the player's computer + speed. + + @deprecated: Use L{dRot} and L{useLocalDRot} instead. + @type dx: float + @param dx: the x component of the angular displacement vector. + @type dy: float + @param dy: the z component of the angular displacement vector. + @type dz: float + @param dz: the z component of the angular displacement vector. + @type local: boolean + @param local: - False: the angular displacement vector is applied in world coordinates. + - True: the angular displacement vector is applied in local coordinates. + """ + def getLinearVelocity(): + """ + Returns the linear velocity applied by the actuator. + For the servo control actuator, this is the target speed. + + @deprecated: Use L{linV} and L{useLocalLinV} instead. + @rtype: list [vx, vy, vz, local] + @return: A four item list, containing the vector velocity, and whether the velocity is applied in local coordinates (True) or world coordinates (False) + """ + def setLinearVelocity(vx, vy, vz, local): + """ + Sets the linear velocity applied by the actuator. + For the servo control actuator, sets the target speed. + + @deprecated: Use L{linV} and L{useLocalLinV} instead. + @type vx: float + @param vx: the x component of the velocity vector. + @type vy: float + @param vy: the z component of the velocity vector. + @type vz: float + @param vz: the z component of the velocity vector. + @type local: boolean + @param local: - False: the velocity vector is in world coordinates. + - True: the velocity vector is in local coordinates. + """ + def getAngularVelocity(): + """ + Returns the angular velocity applied by the actuator. + + @deprecated: Use L{angV} and L{useLocalAngV} instead. + @rtype: list [S{omega}x, S{omega}y, S{omega}z, local] + @return: A four item list, containing the vector velocity, and whether + the velocity is applied in local coordinates (True) or world + coordinates (False) + """ + def setAngularVelocity(wx, wy, wz, local): + """ + Sets the angular velocity applied by the actuator. + + @deprecated: Use L{angV} and L{useLocalAngV} instead. + @type wx: float + @param wx: the x component of the velocity vector. + @type wy: float + @param wy: the z component of the velocity vector. + @type wz: float + @param wz: the z component of the velocity vector. + @type local: boolean + @param local: - False: the velocity vector is applied in world coordinates. + - True: the velocity vector is applied in local coordinates. + """ + def getDamping(): + """ + Returns the damping parameter of the servo controller. + + @deprecated: Use L{damping} instead. + @rtype: integer + @return: the time constant of the servo controller in frame unit. + """ + def setDamping(damp): + """ + Sets the damping parameter of the servo controller. + + @deprecated: Use L{damping} instead. + @type damp: integer + @param damp: the damping parameter in frame unit. + """ + def getForceLimitX(): + """ + Returns the min/max force limit along the X axis used by the servo controller. + + @deprecated: Use L{forceLimitX} instead. + @rtype: list [min, max, enabled] + @return: A three item list, containing the min and max limits of the force as float + and whether the limits are active(true) or inactive(true) + """ + def setForceLimitX(min, max, enable): + """ + Sets the min/max force limit along the X axis and activates or deactivates the limits in the servo controller. + + @deprecated: Use L{forceLimitX} instead. + @type min: float + @param min: the minimum value of the force along the X axis. + @type max: float + @param max: the maximum value of the force along the X axis. + @type enable: boolean + @param enable: - True: the force will be limited to the min/max + - False: the force will not be limited + """ + def getForceLimitY(): + """ + Returns the min/max force limit along the Y axis used by the servo controller. + + @deprecated: Use L{forceLimitY} instead. + @rtype: list [min, max, enabled] + @return: A three item list, containing the min and max limits of the force as float + and whether the limits are active(true) or inactive(true) + """ + def setForceLimitY(min, max, enable): + """ + Sets the min/max force limit along the Y axis and activates or deactivates the limits in the servo controller. + + @deprecated: Use L{forceLimitY} instead. + @type min: float + @param min: the minimum value of the force along the Y axis. + @type max: float + @param max: the maximum value of the force along the Y axis. + @type enable: boolean + @param enable: - True: the force will be limited to the min/max + - False: the force will not be limited + """ + def getForceLimitZ(): + """ + Returns the min/max force limit along the Z axis used by the servo controller. + + @deprecated: Use L{forceLimitZ} instead. + @rtype: list [min, max, enabled] + @return: A three item list, containing the min and max limits of the force as float + and whether the limits are active(true) or inactive(true) + """ + def setForceLimitZ(min, max, enable): + """ + Sets the min/max force limit along the Z axis and activates or deactivates the limits in the servo controller. + + @deprecated: Use L{forceLimitZ} instead. + @type min: float + @param min: the minimum value of the force along the Z axis. + @type max: float + @param max: the maximum value of the force along the Z axis. + @type enable: boolean + @param enable: - True: the force will be limited to the min/max + - False: the force will not be limited + """ + def getPID(): + """ + Returns the PID coefficient of the servo controller. + + @deprecated: Use L{pid} instead. + @rtype: list [P, I, D] + @return: A three item list, containing the PID coefficient as floats: + P : proportional coefficient + I : Integral coefficient + D : Derivate coefficient + """ + def setPID(P, I, D): + """ + Sets the PID coefficients of the servo controller. + + @deprecated: Use L{pid} instead. + @type P: flat + @param P: proportional coefficient + @type I: float + @param I: Integral coefficient + @type D: float + @param D: Derivate coefficient + """ + +class KX_ParentActuator(SCA_IActuator): + """ + The parent actuator can set or remove an objects parent object. + @ivar object: the object this actuator sets the parent too. + @type object: KX_GameObject or None + @ivar mode: The mode of this actuator + @type mode: int from 0 to 1 L{GameLogic.Parent Actuator} + @ivar compound: Whether the object shape should be added to the parent compound shape when parenting + Effective only if the parent is already a compound shape + @type compound: bool + @ivar ghost: whether the object should be made ghost when parenting + Effective only if the shape is not added to the parent compound shape + @type ghost: bool + + """ + def setObject(object): + """ + Sets the object to set as parent. + + Object can be either a L{KX_GameObject} or the name of the object. + + @deprecated: Use the L{object} property. + @type object: L{KX_GameObject}, string or None + """ + def getObject(name_only = 1): + """ + Returns the name of the object to change to. + + @deprecated: Use the L{object} property. + @type name_only: bool + @param name_only: optional argument, when 0 return a KX_GameObject + @rtype: string, KX_GameObject or None if no object is set + """ + +class KX_PhysicsObjectWrapper(PyObjectPlus): + """ + KX_PhysicsObjectWrapper + + """ + def setActive(active): + """ + Set the object to be active. + + @param active: set to True to be active + @type active: bool + """ + + def setAngularVelocity(x, y, z, local): + """ + Set the angular velocity of the object. + + @param x: angular velocity for the x-axis + @type x: float + + @param y: angular velocity for the y-axis + @type y: float + + @param z: angular velocity for the z-axis + @type z: float + + @param local: set to True for local axis + @type local: bool + """ + def setLinearVelocity(x, y, z, local): + """ + Set the linear velocity of the object. + + @param x: linear velocity for the x-axis + @type x: float + + @param y: linear velocity for the y-axis + @type y: float + + @param z: linear velocity for the z-axis + @type z: float + + @param local: set to True for local axis + @type local: bool + """ + def setPosition(x, y, z): + """ + Set the position of the object + + @param x: x coordinate + @type x: float + + @param y: y coordinate + @type y: float + + @param z: z coordinate + @type z: float + """ + +class KX_PolyProxy(SCA_IObject): + """ + A polygon holds the index of the vertex forming the poylgon. + + Note: + The polygon attributes are read-only, you need to retrieve the vertex proxy if you want + to change the vertex settings. + + @ivar matname: The name of polygon material, empty if no material. + @type matname: string + @ivar material: The material of the polygon + @type material: L{KX_PolygonMaterial} or L{KX_BlenderMaterial} + @ivar texture: The texture name of the polygon. + @type texture: string + @ivar matid: The material index of the polygon, use this to retrieve vertex proxy from mesh proxy + @type matid: integer + @ivar v1: vertex index of the first vertex of the polygon, use this to retrieve vertex proxy from mesh proxy + @type v1: integer + @ivar v2: vertex index of the second vertex of the polygon, use this to retrieve vertex proxy from mesh proxy + @type v2: integer + @ivar v3: vertex index of the third vertex of the polygon, use this to retrieve vertex proxy from mesh proxy + @type v3: integer + @ivar v4: vertex index of the fourth vertex of the polygon, 0 if polygon has only 3 vertex + use this to retrieve vertex proxy from mesh proxy + @type v4: integer + @ivar visible: visible state of the polygon: 1=visible, 0=invisible + @type visible: integer + @ivar collide: collide state of the polygon: 1=receives collision, 0=collision free. + @type collide: integer + """ + + def getMaterialName(): + """ + Returns the polygon material name with MA prefix + + @rtype: string + @return: material name + """ + def getMaterial(): + """ + Returns the polygon material + + @rtype: L{KX_PolygonMaterial} or L{KX_BlenderMaterial} + """ + def getTextureName(): + """ + Returns the polygon texture name + + @rtype: string + @return: texture name + """ + def getMaterialIndex(): + """ + Returns the material bucket index of the polygon. + This index and the ones returned by getVertexIndex() are needed to retrieve the vertex proxy from L{KX_MeshProxy}. + + @rtype: integer + @return: the material index in the mesh + """ + def getNumVertex(): + """ + Returns the number of vertex of the polygon. + + @rtype: integer + @return: number of vertex, 3 or 4. + """ + def isVisible(): + """ + Returns whether the polygon is visible or not + + @rtype: integer + @return: 0=invisible, 1=visible + """ + def isCollider(): + """ + Returns whether the polygon is receives collision or not + + @rtype: integer + @return: 0=collision free, 1=receives collision + """ + def getVertexIndex(vertex): + """ + Returns the mesh vertex index of a polygon vertex + This index and the one returned by getMaterialIndex() are needed to retrieve the vertex proxy from L{KX_MeshProxy}. + + @type vertex: integer + @param vertex: index of the vertex in the polygon: 0->3 + @rtype: integer + @return: mesh vertex index + """ + def getMesh(): + """ + Returns a mesh proxy + + @rtype: L{KX_MeshProxy} + @return: mesh proxy + """ + +class KX_PolygonMaterial: + """ + This is the interface to materials in the game engine. + + Materials define the render state to be applied to mesh objects. + + Warning: Some of the methods/variables are CObjects. If you mix these up, + you will crash blender. + + This example requires: + - PyOpenGL http://pyopengl.sourceforge.net/ + - GLEWPy http://glewpy.sourceforge.net/ + Example:: + + import GameLogic + import OpenGL + from OpenGL.GL import * + from OpenGL.GLU import * + import glew + from glew import * + + glewInit() + + vertex_shader = \"\"\" + + void main(void) + { + gl_Position = ftransform(); + } + \"\"\" + + fragment_shader =\"\"\" + + void main(void) + { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + } + \"\"\" + + class MyMaterial: + def __init__(self): + self.pass_no = 0 + # Create a shader + self.m_program = glCreateProgramObjectARB() + # Compile the vertex shader + self.shader(GL_VERTEX_SHADER_ARB, (vertex_shader)) + # Compile the fragment shader + self.shader(GL_FRAGMENT_SHADER_ARB, (fragment_shader)) + # Link the shaders together + self.link() + + def PrintInfoLog(self, tag, object): + \"\"\" + PrintInfoLog prints the GLSL compiler log + \"\"\" + print "Tag: def PrintGLError(self, tag = ""): + + def PrintGLError(self, tag = ""): + \"\"\" + Prints the current GL error status + \"\"\" + if len(tag): + print tag + err = glGetError() + if err != GL_NO_ERROR: + print "GL Error: %s\\n"%(gluErrorString(err)) + + def shader(self, type, shaders): + \"\"\" + shader compiles a GLSL shader and attaches it to the current + program. + + type should be either GL_VERTEX_SHADER_ARB or GL_FRAGMENT_SHADER_ARB + shaders should be a sequence of shader source to compile. + \"\"\" + # Create a shader object + shader_object = glCreateShaderObjectARB(type) + + # Add the source code + glShaderSourceARB(shader_object, len(shaders), shaders) + + # Compile the shader + glCompileShaderARB(shader_object) + + # Print the compiler log + self.PrintInfoLog("vertex shader", shader_object) + + # Check if compiled, and attach if it did + compiled = glGetObjectParameterivARB(shader_object, GL_OBJECT_COMPILE_STATUS_ARB) + if compiled: + glAttachObjectARB(self.m_program, shader_object) + + # Delete the object (glAttachObjectARB makes a copy) + glDeleteObjectARB(shader_object) + + # print the gl error log + self.PrintGLError() + + def link(self): + \"\"\" + Links the shaders together. + \"\"\" + # clear error indicator + glGetError() + + glLinkProgramARB(self.m_program) + + self.PrintInfoLog("link", self.m_program) + + linked = glGetObjectParameterivARB(self.m_program, GL_OBJECT_LINK_STATUS_ARB) + if not linked: + print "Shader failed to link" + return + + glValidateProgramARB(self.m_program) + valid = glGetObjectParameterivARB(self.m_program, GL_OBJECT_VALIDATE_STATUS_ARB) + if not valid: + print "Shader failed to validate" + return + + def activate(self, rasty, cachingInfo, mat): + self.pass_no+=1 + if (self.pass_no == 1): + glDisable(GL_COLOR_MATERIAL) + glUseProgramObjectARB(self.m_program) + return True + + glEnable(GL_COLOR_MATERIAL) + glUseProgramObjectARB(0) + self.pass_no = 0 + return False + + obj = GameLogic.getCurrentController().owner + + mesh = obj.meshes[0] + + for mat in mesh.materials: + mat.setCustomMaterial(MyMaterial()) + print mat.texture + + @ivar texture: Texture name + @type texture: string (read-only) + + @ivar gl_texture: OpenGL texture handle (eg for glBindTexture(GL_TEXTURE_2D, gl_texture) + @type gl_texture: integer (read-only) + + @ivar material: Material name + @type material: string (read-only) + + @ivar tface: Texture face properties + @type tface: CObject (read-only) + + @ivar tile: Texture is tiling + @type tile: boolean + @ivar tilexrep: Number of tile repetitions in x direction. + @type tilexrep: integer + @ivar tileyrep: Number of tile repetitions in y direction. + @type tileyrep: integer + + @ivar drawingmode: Drawing mode for the material. + - 2 (drawingmode & 4) Textured + - 4 (drawingmode & 16) Light + - 14 (drawingmode & 16384) 3d Polygon Text + @type drawingmode: bitfield + + @ivar transparent: This material is transparent. All meshes with this + material will be rendered after non transparent meshes from back + to front. + @type transparent: boolean + + @ivar zsort: Transparent polygons in meshes with this material will be sorted back to + front before rendering. + Non-Transparent polygons will be sorted front to back before rendering. + @type zsort: boolean + + @ivar lightlayer: Light layers this material affects. + @type lightlayer: bitfield. + + @ivar triangle: Mesh data with this material is triangles. It's probably not safe to change this. + @type triangle: boolean + + @ivar diffuse: The diffuse colour of the material. black = [0.0, 0.0, 0.0] white = [1.0, 1.0, 1.0] + @type diffuse: list [r, g, b] + @ivar specular: The specular colour of the material. black = [0.0, 0.0, 0.0] white = [1.0, 1.0, 1.0] + @type specular: list [r, g, b] + @ivar shininess: The shininess (specular exponent) of the material. 0.0 <= shininess <= 128.0 + @type shininess: float + @ivar specularity: The amount of specular of the material. 0.0 <= specularity <= 1.0 + @type specularity: float + """ + def updateTexture(tface, rasty): + """ + Updates a realtime animation. + + @param tface: Texture face (eg mat.tface) + @type tface: CObject + @param rasty: Rasterizer + @type rasty: CObject + """ + def setTexture(tface): + """ + Sets texture render state. + + Example:: + mat.setTexture(mat.tface) + + @param tface: Texture face + @type tface: CObject + """ + def activate(rasty, cachingInfo): + """ + Sets material parameters for this object for rendering. + + Material Parameters set: + 1. Texture + 2. Backface culling + 3. Line drawing + 4. Specular Colour + 5. Shininess + 6. Diffuse Colour + 7. Polygon Offset. + + @param rasty: Rasterizer instance. + @type rasty: CObject + @param cachingInfo: Material cache instance. + @type cachingInfo: CObject + """ + def setCustomMaterial(material): + """ + Sets the material state setup object. + + Using this method, you can extend or completely replace the gameengine material + to do your own advanced multipass effects. + + Use this method to register your material class. Instead of the normal material, + your class's activate method will be called just before rendering the mesh. + This should setup the texture, material, and any other state you would like. + It should return True to render the mesh, or False if you are finished. You should + clean up any state Blender does not set before returning False. + + Activate Method Definition:: + def activate(self, rasty, cachingInfo, material): + + Example:: + class PyMaterial: + def __init__(self): + self.pass_no = -1 + + def activate(self, rasty, cachingInfo, material): + # Activate the material here. + # + # The activate method will be called until it returns False. + # Every time the activate method returns True the mesh will + # be rendered. + # + # rasty is a CObject for passing to material.updateTexture() + # and material.activate() + # cachingInfo is a CObject for passing to material.activate() + # material is the KX_PolygonMaterial instance this material + # was added to + + # default material properties: + self.pass_no += 1 + if self.pass_no == 0: + material.activate(rasty, cachingInfo) + # Return True to do this pass + return True + + # clean up and return False to finish. + self.pass_no = -1 + return False + + # Create a new Python Material and pass it to the renderer. + mat.setCustomMaterial(PyMaterial()) + + @param material: The material object. + @type material: instance + """ + +class KX_RadarSensor(KX_NearSensor): + """ + Radar sensor is a near sensor with a conical sensor object. + + @ivar coneOrigin: The origin of the cone with which to test. The origin + is in the middle of the cone. + (read-only) + @type coneOrigin: list of floats [x, y, z] + @ivar coneTarget: The center of the bottom face of the cone with which to test. + (read-only) + @type coneTarget: list of floats [x, y, z] + @ivar distance: The height of the cone with which to test. + @type distance: float + @ivar angle: The angle of the cone (in degrees) with which to test. + @type angle: float from 0 to 360 + @ivar axis: The axis on which the radar cone is cast + @type axis: int from 0 to 5 + KX_RADAR_AXIS_POS_X, KX_RADAR_AXIS_POS_Y, KX_RADAR_AXIS_POS_Z, + KX_RADAR_AXIS_NEG_X, KX_RADAR_AXIS_NEG_Y, KX_RADAR_AXIS_NEG_Z + """ +#{Deprecated + #--The following methods are deprecated, please use properties instead. + def getConeOrigin(): + """ + Returns the origin of the cone with which to test. The origin + is in the middle of the cone. + + @deprecated: Use the L{coneOrigin} property. + @rtype: list [x, y, z] + """ + + def getConeTarget(): + """ + Returns the center of the bottom face of the cone with which to test. + + @deprecated: Use the L{coneTarget} property. + @rtype: list [x, y, z] + """ +#} + + def getConeHeight(): + """ + Returns the height of the cone with which to test. + + @rtype: float + """ + +class KX_RaySensor(SCA_ISensor): + """ + A ray sensor detects the first object in a given direction. + + @ivar propName: The property the ray is looking for. + @type propName: string + @ivar range: The distance of the ray. + @type range: float + @ivar useMaterial: Whether or not to look for a material (false = property) + @type useMaterial: boolean + @ivar useXRay: Whether or not to use XRay. + @type useXRay: boolean + @ivar hitObject: The game object that was hit by the ray. (Read-only) + @type hitObject: KX_GameObject + @ivar hitPosition: The position (in worldcoordinates) where the object was hit by the ray. (Read-only) + @type hitPosition: list [x, y, z] + @ivar hitNormal: The normal (in worldcoordinates) of the object at the location where the object was hit by the ray. (Read-only) + @type hitNormal: list [x, y, z] + @ivar rayDirection: The direction from the ray (in worldcoordinates). (Read-only) + @type rayDirection: list [x, y, z] + @ivar axis: The axis the ray is pointing on. + @type axis: int from 0 to 5 + KX_RAY_AXIS_POS_X, KX_RAY_AXIS_POS_Y, KX_RAY_AXIS_POS_Z, + KX_RAY_AXIS_NEG_X, KX_RAY_AXIS_NEG_Y, KX_RAY_AXIS_NEG_Z + """ +#{ Deprecated + def getHitObject(): + """ + Returns the game object that was hit by this ray. + + @deprecated: Use the L{hitObject} attribute instead. + @rtype: KX_GameObject + """ + def getHitPosition(): + """ + Returns the position (in worldcoordinates) where the object was hit by this ray. + + @deprecated: Use the L{hitPosition} attribute instead. + @rtype: list [x, y, z] + """ + def getHitNormal(): + """ + Returns the normal (in worldcoordinates) of the object at the location where the object was hit by this ray. + + @deprecated: Use the L{hitNormal} attribute instead. + @rtype: list [nx, ny, nz] + """ + def getRayDirection(): + """ + Returns the direction from the ray (in worldcoordinates) + + @deprecated: Use the L{rayDirection} attribute instead. + @rtype: list [dx, dy, dz] + """ +#} + +class KX_SCA_AddObjectActuator(SCA_IActuator): + """ + Edit Object Actuator (in Add Object Mode) + @ivar object: the object this actuator adds. + @type object: KX_GameObject or None + @ivar objectLastCreated: the last added object from this actuator (read-only). + @type objectLastCreated: KX_GameObject or None + @ivar time: the lifetime of added objects, in frames. Set to 0 to disable automatic deletion. + @type time: integer + @ivar linearVelocity: the initial linear velocity of added objects. + @type linearVelocity: list [vx, vy, vz] + @ivar angularVelocity: the initial angular velocity of added objects. + @type angularVelocity: list [vx, vy, vz] + + @warning: An Add Object actuator will be ignored if at game start, the linked object doesn't exist + (or is empty) or the linked object is in an active layer. + + This will genereate a warning in the console: + + C{ERROR: GameObject I{OBName} has a AddObjectActuator I{ActuatorName} without object (in 'nonactive' layer)} + """ +#{Deprecated + def setObject(object): + """ + Sets the game object to add. + + A copy of the object will be added to the scene when the actuator is activated. + + If the object does not exist, this function is ignored. + + object can either be a L{KX_GameObject} or the name of an object or None. + + @deprecated: use the L{object} property + @type object: L{KX_GameObject}, string or None + """ + def getObject(name_only = 0): + """ + Returns the name of the game object to be added. + + Returns None if no game object has been assigned to be added. + + @deprecated: use the L{object} property + @type name_only: bool + @param name_only: optional argument, when 0 return a KX_GameObject + @rtype: string, KX_GameObject or None if no object is set + """ + def setTime(time): + """ + Sets the lifetime of added objects, in frames. + + If time == 0, the object will last forever. + + @deprecated: use the L{time} property + @type time: integer + @param time: The minimum value for time is 0. + """ + def getTime(): + """ + Returns the lifetime of the added object, in frames. + + @deprecated: use the L{time} property + @rtype: integer + """ + def setLinearVelocity(vx, vy, vz): + """ + Sets the initial linear velocity of added objects. + + @deprecated: use the L{linearVelocity} property + @type vx: float + @param vx: the x component of the initial linear velocity. + @type vy: float + @param vy: the y component of the initial linear velocity. + @type vz: float + @param vz: the z component of the initial linear velocity. + """ + def getLinearVelocity(): + """ + Returns the initial linear velocity of added objects. + + @deprecated: use the L{linearVelocity} property + @rtype: list [vx, vy, vz] + """ + def setAngularVelocity(vx, vy, vz): + """ + Sets the initial angular velocity of added objects. + + @deprecated: use the L{angularVelocity} property + @type vx: float + @param vx: the x component of the initial angular velocity. + @type vy: float + @param vy: the y component of the initial angular velocity. + @type vz: float + @param vz: the z component of the initial angular velocity. + """ + def getAngularVelocity(): + """ + Returns the initial angular velocity of added objects. + + @deprecated: use the L{angularVelocity} property + @rtype: list [vx, vy, vz] + """ + def getLastCreatedObject(): + """ + Returns the last object created by this actuator. + + @deprecated: use the L{objectLastCreated} property + @rtype: L{KX_GameObject} + @return: A L{KX_GameObject} or None if no object has been created. + """ +#} + def instantAddObject(): + """ + Returns the last object created by this actuator. The object can then be accessed from L{objectLastCreated}. + + @rtype: None + """ + +class KX_SCA_DynamicActuator(SCA_IActuator): + """ + Dynamic Actuator. + @ivar mode: the type of operation of the actuator, 0-4 + KX_DYN_RESTORE_DYNAMICS, KX_DYN_DISABLE_DYNAMICS, + KX_DYN_ENABLE_RIGID_BODY, KX_DYN_DISABLE_RIGID_BODY, KX_DYN_SET_MASS + @type mode: integer + @ivar mass: the mass value for the KX_DYN_SET_MASS operation + @type mass: float + """ +#{ Deprecated + def setOperation(operation): + """ + Set the type of operation when the actuator is activated: + - 0 = restore dynamics + - 1 = disable dynamics + - 2 = enable rigid body + - 3 = disable rigid body + - 4 = set mass + + @deprecated: Use the L{mode} attribute instead. + """ + def getOperation(): + """ + return the type of operation + @deprecated: Use the L{mode} attribute instead. + """ +#} + +class KX_SCA_EndObjectActuator(SCA_IActuator): + """ + Edit Object Actuator (in End Object mode) + + This actuator has no python methods. + """ + +class KX_SCA_ReplaceMeshActuator(SCA_IActuator): + """ + Edit Object actuator, in Replace Mesh mode. + + Example:: + # Level-of-detail + # Switch a game object's mesh based on its depth in the camera view. + # +----------+ +-----------+ +-------------------------------------+ + # | Always +-----+ Python +-----+ Edit Object (Replace Mesh) LOD.Mesh | + # +----------+ +-----------+ +-------------------------------------+ + import GameLogic + + # List detail meshes here + # Mesh (name, near, far) + # Meshes overlap so that they don't 'pop' when on the edge of the distance. + meshes = ((".Hi", 0.0, -20.0), + (".Med", -15.0, -50.0), + (".Lo", -40.0, -100.0) + ) + + co = GameLogic.getCurrentController() + obj = co.owner + act = co.actuators["LOD." + obj.name] + cam = GameLogic.getCurrentScene().active_camera + + def Depth(pos, plane): + return pos[0]*plane[0] + pos[1]*plane[1] + pos[2]*plane[2] + plane[3] + + # Depth is negative and decreasing further from the camera + depth = Depth(obj.position, cam.world_to_camera[2]) + + newmesh = None + curmesh = None + # Find the lowest detail mesh for depth + for mesh in meshes: + if depth < mesh[1] and depth > mesh[2]: + newmesh = mesh + if "ME" + obj.name + mesh[0] == act.getMesh(): + curmesh = mesh + + if newmesh != None and "ME" + obj.name + newmesh[0] != act.getMesh(): + # The mesh is a different mesh - switch it. + # Check the current mesh is not a better fit. + if curmesh == None or curmesh[1] < depth or curmesh[2] > depth: + act.mesh = obj.getName() + newmesh[0] + GameLogic.addActiveActuator(act, True) + + @warning: Replace mesh actuators will be ignored if at game start, the + named mesh doesn't exist. + + This will generate a warning in the console: + + C{ERROR: GameObject I{OBName} ReplaceMeshActuator I{ActuatorName} without object} + + @ivar mesh: L{KX_MeshProxy} or the name of the mesh that will replace the current one + Set to None to disable actuator + @type mesh: L{KX_MeshProxy} or None if no mesh is set + + @ivar useDisplayMesh: when true the displayed mesh is replaced. + @type useDisplayMesh: boolean + @ivar usePhysicsMesh: when true the physics mesh is replaced. + @type usePhysicsMesh: boolean + """ + def setMesh(name): + """ + Sets the name of the mesh that will replace the current one. + When the name is None it will unset the mesh value so no action is taken. + + @deprecated: Use the L{mesh} attribute instead. + @type name: string or None + """ + def getMesh(): + """ + Returns the name of the mesh that will replace the current one. + + Returns None if no mesh has been scheduled to be added. + + @deprecated: Use the L{mesh} attribute instead. + @rtype: string or None + """ + def instantReplaceMesh(): + """ + Immediately replace mesh without delay. + @rtype: None + """ + +class KX_Scene(PyObjectPlus): + """ + An active scene that gives access to objects, cameras, lights and scene attributes. + + The activity culling stuff is supposed to disable logic bricks when their owner gets too far + from the active camera. It was taken from some code lurking at the back of KX_Scene - who knows + what it does! + + Example:: + import GameLogic + + # get the scene + scene = GameLogic.getCurrentScene() + + # print all the objects in the scene + for obj in scene.objects: + print obj.name + + # get an object named 'Cube' + obj = scene.objects["OBCube"] + + # get the first object in the scene. + obj = scene.objects[0] + + Example:: + # Get the depth of an object in the camera view. + import GameLogic + + obj = GameLogic.getCurrentController().owner + cam = GameLogic.getCurrentScene().active_camera + + # Depth is negative and decreasing further from the camera + depth = obj.position[0]*cam.world_to_camera[2][0] + obj.position[1]*cam.world_to_camera[2][1] + obj.position[2]*cam.world_to_camera[2][2] + cam.world_to_camera[2][3] + + @bug: All attributes are read only at the moment. + + @ivar name: The scene's name, (read-only). + @type name: string + @ivar objects: A list of objects in the scene, (read-only). + @type objects: L{CListValue} of L{KX_GameObject} + @ivar objectsInactive: A list of objects on background layers (used for the addObject actuator), (read-only). + @type objectsInactive: L{CListValue} of L{KX_GameObject} + @ivar lights: A list of lights in the scene, (read-only). + @type lights: L{CListValue} of L{KX_LightObject} + @ivar cameras: A list of cameras in the scene, (read-only). + @type cameras: L{CListValue} of L{KX_Camera} + @ivar active_camera: The current active camera. + note: this can be set directly from python to avoid using the L{KX_SceneActuator}. + @type active_camera: L{KX_Camera} + @ivar suspended: True if the scene is suspended, (read-only). + @type suspended: boolean + @ivar activity_culling: True if the scene is activity culling + @type activity_culling: boolean + @ivar activity_culling_radius: The distance outside which to do activity culling. Measured in manhattan distance. + @type activity_culling_radius: float + @ivar dbvt_culling: True when Dynamic Bounding box Volume Tree is set (read-only). + @type dbvt_culling: bool + @group Deprecated: getLightList, getObjectList, getName + """ + + def getLightList(): + """ + Returns the list of lights in the scene. + + @deprecated: Use the L{lights} attribute instead. + @rtype: list [L{KX_LightObject}] + """ + def getObjectList(): + """ + Returns the list of objects in the scene. + + @deprecated: Use the L{objects} attribute instead. + @rtype: list [L{KX_GameObject}] + """ + def getName(): + """ + Returns the name of the scene. + + @deprecated: Use the L{name} attribute instead. + @rtype: string + """ + + def addObject(object, other, time=0): + """ + Adds an object to the scene like the Add Object Actuator would, and returns the created object. + + @param object: The object to add + @type object: L{KX_GameObject} or string + @param other: The object's center to use when adding the object + @type other: L{KX_GameObject} or string + @param time: The lifetime of the added object, in frames. A time of 0 means the object will last forever. + @type time: int + + @rtype: L{KX_GameObject} + """ + + def get(key, default=None): + """ + Return the value matching key, or the default value if its not found. + @return: The key value or a default. + """ + +class KX_SceneActuator(SCA_IActuator): + """ + Scene Actuator logic brick. + + @warning: Scene actuators that use a scene name will be ignored if at game start, the + named scene doesn't exist or is empty + + This will generate a warning in the console: + + C{ERROR: GameObject I{OBName} has a SceneActuator I{ActuatorName} (SetScene) without scene} + + @ivar scene: the name of the scene to change to/overlay/underlay/remove/suspend/resume + @type scene: string. + @ivar camera: the camera to change to. + When setting the attribute, you can use either a L{KX_Camera} or the name of the camera. + @type camera: L{KX_Camera} on read, string or L{KX_Camera} on write + @ivar useRestart: Set flag to True to restart the sene + @type useRestart: bool + @ivar mode: The mode of the actuator + @type mode: int from 0 to 5 L{GameLogic.Scene Actuator} + """ +#{ Deprecated + def setUseRestart(flag): + """ + Set flag to True to restart the scene. + + @deprecated: Use the L{useRestart} attribute instead. + @type flag: boolean + """ + def setScene(scene): + """ + Sets the name of the scene to change to/overlay/underlay/remove/suspend/resume. + + @deprecated: use the L{scene} attribute instead. + @type scene: string + """ + def setCamera(camera): + """ + Sets the camera to change to. + + Camera can be either a L{KX_Camera} or the name of the camera. + + @deprecated: use the L{camera} attribute instead. + @type camera: L{KX_Camera} or string + """ + def getUseRestart(): + """ + Returns True if the scene will be restarted. + + @deprecated: use the L{useRestart} attribute instead. + @rtype: boolean + """ + def getScene(): + """ + Returns the name of the scene to change to/overlay/underlay/remove/suspend/resume. + + Returns an empty string ("") if no scene has been set. + + @deprecated: use the L{scene} attribute instead. + @rtype: string + """ + def getCamera(): + """ + Returns the name of the camera to change to. + + @deprecated: use the L{camera} attribute instead. + @rtype: string + """ +#} + +class KX_SoundActuator(SCA_IActuator): + """ + Sound Actuator. + + The L{startSound()}, L{pauseSound()} and L{stopSound()} do not require + the actuator to be activated - they act instantly provided that the actuator has + been activated once at least. + + @ivar fileName: The filename of the sound this actuator plays. + @type fileName: string + + @ivar volume: The volume (gain) of the sound. + @type volume: float + + @ivar pitch: The pitch of the sound. + @type pitch: float + + @ivar rollOffFactor: The roll off factor. Rolloff defines the rate of attenuation as the sound gets further away. + @type rollOffFactor: float + + @ivar looping: The loop mode of the actuator. + @type looping: integer + + @ivar position: The position of the sound as a list: [x, y, z]. + @type position: float array + + @ivar velocity: The velocity of the emitter as a list: [x, y, z]. The relative velocity to the observer determines the pitch. List of 3 floats: [x, y, z]. + @type velocity: float array + + @ivar orientation: The orientation of the sound. When setting the orientation you can also use quaternion [float,float,float,float] or euler angles [float,float,float] + @type orientation: 3x3 matrix [[float]] + + @ivar mode: The operation mode of the actuator. You can use one of the following constants: + - KX_SOUNDACT_PLAYSTOP (1) + - KX_SOUNDACT_PLAYEND (2) + - KX_SOUNDACT_LOOPSTOP (3) + - KX_SOUNDACT_LOOPEND (4) + - KX_SOUNDACT_LOOPBIDIRECTIONAL (5) + - KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP (6) + @type mode: integer + """ + +#{ Play Methods + def startSound(): + """ + Starts the sound. + """ + def pauseSound(): + """ + Pauses the sound. + """ + def stopSound(): + """ + Stops the sound. + """ +#} + +#{ Deprecated + def setFilename(filename): + """ + Sets the filename of the sound this actuator plays. + + @deprecated: Use the L{fileName} attribute instead. + @type filename: string + """ + def getFilename(): + """ + Returns the filename of the sound this actuator plays. + + @deprecated: Use the L{fileName} attribute instead. + @rtype: string + """ + def setGain(gain): + """ + Sets the gain (volume) of the sound + + @deprecated: Use the L{volume} attribute instead. + @type gain: float + @param gain: 0.0 (quiet) <= gain <= 1.0 (loud) + """ + def getGain(): + """ + Gets the gain (volume) of the sound. + + @deprecated: Use the L{volume} attribute instead. + @rtype: float + """ + def setPitch(pitch): + """ + Sets the pitch of the sound. + + @deprecated: Use the L{pitch} attribute instead. + @type pitch: float + """ + def getPitch(): + """ + Returns the pitch of the sound. + + @deprecated: Use the L{pitch} attribute instead. + @rtype: float + """ + def setRollOffFactor(rolloff): + """ + Sets the rolloff factor for the sounds. + + Rolloff defines the rate of attenuation as the sound gets further away. + Higher rolloff factors shorten the distance at which the sound can be heard. + + @deprecated: Use the L{rollOffFactor} attribute instead. + @type rolloff: float + """ + def getRollOffFactor(): + """ + Returns the rolloff factor for the sound. + + @deprecated: Use the L{rollOffFactor} attribute instead. + @rtype: float + """ + def setLooping(loop): + """ + Sets the loop mode of the actuator. + + @bug: There are no constants defined for this method! + @param loop: - Play Stop 1 + - Play End 2 + - Loop Stop 3 + - Loop End 4 + - Bidirection Stop 5 + - Bidirection End 6 + + @deprecated: Use the L{looping} attribute instead. + @type loop: integer + """ + def getLooping(): + """ + Returns the current loop mode of the actuator. + + @deprecated: Use the L{looping} attribute instead. + @rtype: integer + """ + def setPosition(x, y, z): + """ + Sets the position this sound will come from. + + @deprecated: Use the L{position} attribute instead. + @type x: float + @param x: The x coordinate of the sound. + @type y: float + @param y: The y coordinate of the sound. + @type z: float + @param z: The z coordinate of the sound. + """ + def setVelocity(vx, vy, vz): + """ + Sets the velocity this sound is moving at. + + The sound's pitch is determined from the velocity. + + @deprecated: Use the L{velocity} attribute instead. + @type vx: float + @param vx: The vx coordinate of the sound. + @type vy: float + @param vy: The vy coordinate of the sound. + @type vz: float + @param vz: The vz coordinate of the sound. + """ + def setOrientation(o11, o12, o13, o21, o22, o23, o31, o32, o33): + """ + Sets the orientation of the sound. + + The nine parameters specify a rotation matrix:: + | o11, o12, o13 | + | o21, o22, o23 | + | o31, o32, o33 | + @deprecated: Use the L{orientation} attribute instead. + """ + + def setType(mode): + """ + Sets the operation mode of the actuator. + + @deprecated: Use the L{type} attribute instead. + @param mode: KX_SOUNDACT_PLAYSTOP, KX_SOUNDACT_PLAYEND, KX_SOUNDACT_LOOPSTOP, KX_SOUNDACT_LOOPEND, KX_SOUNDACT_LOOPBIDIRECTIONAL, KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP + @type mode: integer + """ + + def getType(): + """ + Returns the operation mode of the actuator. + + @deprecated: Use the L{type} attribute instead. + @rtype: integer + @return: KX_SOUNDACT_PLAYSTOP, KX_SOUNDACT_PLAYEND, KX_SOUNDACT_LOOPSTOP, KX_SOUNDACT_LOOPEND, KX_SOUNDACT_LOOPBIDIRECTIONAL, KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP + """ +#} + +class KX_StateActuator(SCA_IActuator): + """ + State actuator changes the state mask of parent object. + + Property: + + @ivar operation: type of bit operation to be applied on object state mask. + You can use one of the following constant: + - KX_STATE_OP_CPY (0) : Copy state mask + - KX_STATE_OP_SET (1) : Add bits to state mask + - KX_STATE_OP_CLR (2) : Substract bits to state mask + - KX_STATE_OP_NEG (3) : Invert bits to state mask + @type operation: integer + + @ivar mask: value that defines the bits that will be modified by the operation. + The bits that are 1 in the mask will be updated in the object state, + the bits that are 0 are will be left unmodified expect for the Copy operation + which copies the mask to the object state + @type mask: integer + """ + def setOperation(op): + """ + Set the type of bit operation to be applied on object state mask. + Use setMask() to specify the bits that will be modified. + + @deprecated: Use the L{operation} attribute instead. + @param op: bit operation (0=Copy, 1=Add, 2=Substract, 3=Invert) + @type op: integer + """ + def setMask(mask): + """ + Set the value that defines the bits that will be modified by the operation. + The bits that are 1 in the value will be updated in the object state, + the bits that are 0 are will be left unmodified expect for the Copy operation + which copies the value to the object state. + + @deprecated: Use the L{mask} attribute instead. + @param mask: bits that will be modified + @type mask: integer + """ + +class KX_TrackToActuator(SCA_IActuator): + """ + Edit Object actuator in Track To mode. + + @warning: Track To Actuators will be ignored if at game start, the + object to track to is invalid. + + This will generate a warning in the console: + + C{ERROR: GameObject I{OBName} no object in EditObjectActuator I{ActuatorName}} + + @ivar object: the object this actuator tracks. + @type object: KX_GameObject or None + @ivar time: the time in frames with which to delay the tracking motion + @type time: integer + @ivar use3D: the tracking motion to use 3D + @type use3D: boolean + + """ +#{ Deprecated + def setObject(object): + """ + Sets the object to track. + + @deprecated: Use the L{object} attribute instead. + @type object: L{KX_GameObject}, string or None + @param object: Either a reference to a game object or the name of the object to track. + """ + def getObject(name_only): + """ + Returns the name of the object to track. + + @deprecated: Use the L{object} attribute instead. + @type name_only: bool + @param name_only: optional argument, when 0 return a KX_GameObject + @rtype: string, KX_GameObject or None if no object is set + """ + def setTime(time): + """ + Sets the time in frames with which to delay the tracking motion. + + @deprecated: Use the L{time} attribute instead. + @type time: integer + """ + def getTime(): + """ + Returns the time in frames with which the tracking motion is delayed. + + @deprecated: Use the L{time} attribute instead. + @rtype: integer + """ + def setUse3D(use3d): + """ + DEPRECATED: Use the property. + Sets the tracking motion to use 3D. + + @deprecated: Use the L{use3D} attribute instead. + @type use3d: boolean + @param use3d: - True: allow the tracking motion to extend in the z-direction. + - False: lock the tracking motion to the x-y plane. + """ + def getUse3D(): + """ + Returns True if the tracking motion will track in the z direction. + + @deprecated: Use the L{use3D} attribute instead. + @rtype: boolean + """ +#} + +class KX_VehicleWrapper(PyObjectPlus): + """ + KX_VehicleWrapper + + TODO - description + """ + + def addWheel(wheel, attachPos, attachDir, axleDir, suspensionRestLength, wheelRadius, hasSteering): + + """ + Add a wheel to the vehicle + + @param wheel: The object to use as a wheel. + @type wheel: L{KX_GameObject} or a KX_GameObject name + @param attachPos: The position that this wheel will attach to. + @type attachPos: vector of 3 floats + @param attachDir: The direction this wheel points. + @type attachDir: vector of 3 floats + @param axleDir: The direction of this wheels axle. + @type axleDir: vector of 3 floats + @param suspensionRestLength: TODO - Description + @type suspensionRestLength: float + @param wheelRadius: The size of the wheel. + @type wheelRadius: float + """ + + def applyBraking(force, wheelIndex): + """ + Apply a braking force to the specified wheel + + @param force: the brake force + @type force: float + + @param wheelIndex: index of the wheel where the force needs to be applied + @type wheelIndex: integer + """ + def applyEngineForce(force, wheelIndex): + """ + Apply an engine force to the specified wheel + + @param force: the engine force + @type force: float + + @param wheelIndex: index of the wheel where the force needs to be applied + @type wheelIndex: integer + """ + def getConstraintId(): + """ + Get the constraint ID + + @rtype: integer + @return: the constraint id + """ + def getConstraintType(): + """ + Returns the constraint type. + + @rtype: integer + @return: constraint type + """ + def getNumWheels(): + """ + Returns the number of wheels. + + @rtype: integer + @return: the number of wheels for this vehicle + """ + def getWheelOrientationQuaternion(wheelIndex): + """ + Returns the wheel orientation as a quaternion. + + @param wheelIndex: the wheel index + @type wheelIndex: integer + + @rtype: TODO - type should be quat as per method name but from the code it looks like a matrix + @return: TODO Description + """ + def getWheelPosition(wheelIndex): + """ + Returns the position of the specified wheel + + @param wheelIndex: the wheel index + @type wheelIndex: integer + + @rtype: list[x, y, z] + @return: position vector + """ + def getWheelRotation(wheelIndex): + """ + Returns the rotation of the specified wheel + + @param wheelIndex: the wheel index + @type wheelIndex: integer + + @rtype: float + @return: the wheel rotation + """ + def setRollInfluence(rollInfluece, wheelIndex): + """ + Set the specified wheel's roll influence. + The higher the roll influence the more the vehicle will tend to roll over in corners. + + @param rollInfluece: the wheel roll influence + @type rollInfluece: float + + @param wheelIndex: the wheel index + @type wheelIndex: integer + """ + def setSteeringValue(steering, wheelIndex): + """ + Set the specified wheel's steering + + @param steering: the wheel steering + @type steering: float + + @param wheelIndex: the wheel index + @type wheelIndex: integer + """ + def setSuspensionCompression(compression, wheelIndex): + """ + Set the specified wheel's compression + + @param compression: the wheel compression + @type compression: float + + @param wheelIndex: the wheel index + @type wheelIndex: integer + """ + def setSuspensionDamping(damping, wheelIndex): + """ + Set the specified wheel's damping + + @param damping: the wheel damping + @type damping: float + + @param wheelIndex: the wheel index + @type wheelIndex: integer + """ + def setSuspensionStiffness(stiffness, wheelIndex): + """ + Set the specified wheel's stiffness + + @param stiffness: the wheel stiffness + @type stiffness: float + + @param wheelIndex: the wheel index + @type wheelIndex: integer + """ + def setTyreFriction(friction, wheelIndex): + """ + Set the specified wheel's tyre friction + + @param friction: the tyre friction + @type friction: float + + @param wheelIndex: the wheel index + @type wheelIndex: integer + """ + +class KX_VertexProxy(SCA_IObject): + """ + A vertex holds position, UV, colour and normal information. + + Note: + The physics simulation is NOT currently updated - physics will not respond + to changes in the vertex position. + + @ivar XYZ: The position of the vertex. + @type XYZ: list [x, y, z] + @ivar UV: The texture coordinates of the vertex. + @type UV: list [u, v] + @ivar normal: The normal of the vertex + @type normal: list [nx, ny, nz] + @ivar colour: The colour of the vertex. + Black = [0.0, 0.0, 0.0, 1.0], White = [1.0, 1.0, 1.0, 1.0] + @type colour: list [r, g, b, a] + @ivar color: Synonym for colour. + + @group Position: x, y, z + @ivar x: The x coordinate of the vertex. + @type x: float + @ivar y: The y coordinate of the vertex. + @type y: float + @ivar z: The z coordinate of the vertex. + @type z: float + + @group Texture Coordinates: u, v + @ivar u: The u texture coordinate of the vertex. + @type u: float + @ivar v: The v texture coordinate of the vertex. + @type v: float + + @ivar u2: The second u texture coordinate of the vertex. + @type u2: float + @ivar v2: The second v texture coordinate of the vertex. + @type v2: float + + @group Colour: r, g, b, a + @ivar r: The red component of the vertex colour. 0.0 <= r <= 1.0 + @type r: float + @ivar g: The green component of the vertex colour. 0.0 <= g <= 1.0 + @type g: float + @ivar b: The blue component of the vertex colour. 0.0 <= b <= 1.0 + @type b: float + @ivar a: The alpha component of the vertex colour. 0.0 <= a <= 1.0 + @type a: float + """ + + def getXYZ(): + """ + Gets the position of this vertex. + + @rtype: list [x, y, z] + @return: this vertexes position in local coordinates. + """ + def setXYZ(pos): + """ + Sets the position of this vertex. + + @type pos: list [x, y, z] + @param pos: the new position for this vertex in local coordinates. + """ + def getUV(): + """ + Gets the UV (texture) coordinates of this vertex. + + @rtype: list [u, v] + @return: this vertexes UV (texture) coordinates. + """ + def setUV(uv): + """ + Sets the UV (texture) coordinates of this vertex. + + @type uv: list [u, v] + """ + def getUV2(): + """ + Gets the 2nd UV (texture) coordinates of this vertex. + + @rtype: list [u, v] + @return: this vertexes UV (texture) coordinates. + """ + def setUV2(uv, unit): + """ + Sets the 2nd UV (texture) coordinates of this vertex. + + @type uv: list [u, v] + @param unit: optional argument, FLAT==1, SECOND_UV==2, defaults to SECOND_UV + @param unit: int + """ + def getRGBA(): + """ + Gets the colour of this vertex. + + The colour is represented as four bytes packed into an integer value. The colour is + packed as RGBA. + + Since Python offers no way to get each byte without shifting, you must use the struct module to + access colour in an machine independent way. + + Because of this, it is suggested you use the r, g, b and a attributes or the colour attribute instead. + + Example:: + import struct; + col = struct.unpack('4B', struct.pack('I', v.getRGBA())) + # col = (r, g, b, a) + # black = ( 0, 0, 0, 255) + # white = (255, 255, 255, 255) + + @rtype: integer + @return: packed colour. 4 byte integer with one byte per colour channel in RGBA format. + """ + def setRGBA(col): + """ + Sets the colour of this vertex. + + See getRGBA() for the format of col, and its relevant problems. Use the r, g, b and a attributes + or the colour attribute instead. + + setRGBA() also accepts a four component list as argument col. The list represents the colour as [r, g, b, a] + with black = [0.0, 0.0, 0.0, 1.0] and white = [1.0, 1.0, 1.0, 1.0] + + Example:: + v.setRGBA(0xff0000ff) # Red + v.setRGBA(0xff00ff00) # Green on little endian, transparent purple on big endian + v.setRGBA([1.0, 0.0, 0.0, 1.0]) # Red + v.setRGBA([0.0, 1.0, 0.0, 1.0]) # Green on all platforms. + + @type col: integer or list [r, g, b, a] + @param col: the new colour of this vertex in packed RGBA format. + """ + def getNormal(): + """ + Gets the normal vector of this vertex. + + @rtype: list [nx, ny, nz] + @return: normalised normal vector. + """ + def setNormal(normal): + """ + Sets the normal vector of this vertex. + + @type normal: sequence of floats [r, g, b] + @param normal: the new normal of this vertex. + """ + +class KX_VisibilityActuator(SCA_IActuator): + """ + Visibility Actuator. + @ivar visibility: whether the actuator makes its parent object visible or invisible + @type visibility: boolean + @ivar useOcclusion: whether the actuator makes its parent object an occluder or not + @type useOcclusion: boolean + @ivar useRecursion: whether the visibility/occlusion should be propagated to all children of the object + @type useRecursion: boolean + """ +#{ Deprecated + def set(visible): + """ + Sets whether the actuator makes its parent object visible or invisible. + + @deprecated: Use the L{visibility} attribute instead. + @param visible: - True: Makes its parent visible. + - False: Makes its parent invisible. + """ +#} + +class SCA_2DFilterActuator(SCA_IActuator): + """ + Create, enable and disable 2D filters + + Properties: + + The following properties don't have an immediate effect. + You must active the actuator to get the result. + The actuator is not persistent: it automatically stops itself after setting up the filter + but the filter remains active. To stop a filter you must activate the actuator with 'type' + set to RAS_2DFILTER_DISABLED or RAS_2DFILTER_NOFILTER. + + @ivar shaderText: shader source code for custom shader + @type shaderText: string + @ivar disableMotionBlur: action on motion blur: 0=enable, 1=disable + @type disableMotionBlur: integer + @ivar mode: type of 2D filter, use one of the following constants: + RAS_2DFILTER_ENABLED (-2) : enable the filter that was previously disabled + RAS_2DFILTER_DISABLED (-1) : disable the filter that is currently active + RAS_2DFILTER_NOFILTER (0) : disable and destroy the filter that is currently active + RAS_2DFILTER_MOTIONBLUR (1) : create and enable preset filters + RAS_2DFILTER_BLUR (2) + RAS_2DFILTER_SHARPEN (3) + RAS_2DFILTER_DILATION (4) + RAS_2DFILTER_EROSION (5) + RAS_2DFILTER_LAPLACIAN (6) + RAS_2DFILTER_SOBEL (7) + RAS_2DFILTER_PREWITT (8) + RAS_2DFILTER_GRAYSCALE (9) + RAS_2DFILTER_SEPIA (10) + RAS_2DFILTER_INVERT (11) + RAS_2DFILTER_CUSTOMFILTER (12) : customer filter, the code code is set via shaderText property + @type mode: integer + @ivar passNumber: order number of filter in the stack of 2D filters. Filters are executed in increasing order of passNb. + Only be one filter can be defined per passNb. + @type passNumber: integer (0-100) + @ivar value: argument for motion blur filter + @type value: float (0.0-100.0) + """ + +class SCA_ANDController(SCA_IController): + """ + An AND controller activates only when all linked sensors are activated. + + There are no special python methods for this controller. + """ + +class SCA_ActuatorSensor(SCA_ISensor): + """ + Actuator sensor detect change in actuator state of the parent object. + It generates a positive pulse if the corresponding actuator is activated + and a negative pulse if the actuator is deactivated. + + Properties: + + @ivar actuator: the name of the actuator that the sensor is monitoring. + @type actuator: string + """ +#{Deprecated + def getActuator(): + """ + Return the Actuator with which the sensor operates. + + @deprecated: Use the L{actuator} attribute instead. + @rtype: string + """ + def setActuator(name): + """ + Sets the Actuator with which to operate. If there is no Actuator + of this name, the function has no effect. + + @deprecated: Use the L{actuator} attribute instead. + @param name: actuator name + @type name: string + """ +#} + +class SCA_AlwaysSensor(SCA_ISensor): + """ + This sensor is always activated. + """ + +class SCA_DelaySensor(SCA_ISensor): + """ + The Delay sensor generates positive and negative triggers at precise time, + expressed in number of frames. The delay parameter defines the length + of the initial OFF period. A positive trigger is generated at the end of this period. + The duration parameter defines the length of the ON period following the OFF period. + There is a negative trigger at the end of the ON period. If duration is 0, the sensor + stays ON and there is no negative trigger. + The sensor runs the OFF-ON cycle once unless the repeat option is set: the + OFF-ON cycle repeats indefinately (or the OFF cycle if duration is 0). + Use SCA_ISensor::reset() at any time to restart sensor. + + Properties: + + @ivar delay: length of the initial OFF period as number of frame, 0 for immediate trigger. + @type delay: integer. + @ivar duration: length of the ON period in number of frame after the initial OFF period. + If duration is greater than 0, a negative trigger is sent at the end of the ON pulse. + @type duration: integer + @ivar repeat: 1 if the OFF-ON cycle should be repeated indefinately, 0 if it should run once. + @type repeat: integer + """ +#{Deprecated + def setDelay(delay): + """ + Set the initial delay before the positive trigger. + + @deprecated: Use the L{delay} attribute instead. + @param delay: length of the initial OFF period as number of frame, 0 for immediate trigger + @type delay: integer + """ + def setDuration(duration): + """ + Set the duration of the ON pulse after initial delay and the generation of the positive trigger. + If duration is greater than 0, a negative trigger is sent at the end of the ON pulse. + + @deprecated: Use the L{duration} attribute instead. + @param duration: length of the ON period in number of frame after the initial OFF period + @type duration: integer + """ + def setRepeat(repeat): + """ + Set if the sensor repeat mode. + + @deprecated: Use the L{repeat} attribute instead. + @param repeat: 1 if the OFF-ON cycle should be repeated indefinately, 0 if it should run once. + @type repeat: integer + """ + def getDelay(): + """ + Return the delay parameter value. + + @deprecated: Use the L{delay} attribute instead. + @rtype: integer + """ + def getDuration(): + """ + Return the duration parameter value + + @deprecated: Use the L{duration} attribute instead. + @rtype: integer + """ + def getRepeat(): + """ + Return the repeat parameter value + + @deprecated: Use the L{repeat} attribute instead. + @rtype: KX_TRUE or KX_FALSE + """ +#} + +class SCA_JoystickSensor(SCA_ISensor): + """ + This sensor detects player joystick events. + + Properties: + + @ivar axisValues: (read-only) The state of the joysticks axis as a list of values L{numAxis} long. + each spesifying the value of an axis between -32767 and 32767 depending on how far the axis is pushed, 0 for nothing. + The first 2 values are used by most joysticks and gamepads for directional control. 3rd and 4th values are only on some joysticks and can be used for arbitary controls. + left:[-32767, 0, ...], right:[32767, 0, ...], up:[0, -32767, ...], down:[0, 32767, ...] + @type axisValues: list of ints + + @ivar axisSingle: (read-only) like L{axisValues} but returns a single axis value that is set by the sensor. + Only use this for "Single Axis" type sensors otherwise it will raise an error. + @type axisSingle: int + + @ivar hatValues: (read-only) The state of the joysticks hats as a list of values L{numHats} long. + each spesifying the direction of the hat from 1 to 12, 0 when inactive. + Hat directions are as follows... + - 0:None + - 1:Up + - 2:Right + - 4:Down + - 8:Left + - 3:Up - Right + - 6:Down - Right + - 12:Down - Left + - 9:Up - Left + + @type hatValues: list of ints + + @ivar hatSingle: (read-only) like L{hatValues} but returns a single hat direction value that is set by the sensor. + @type hatSingle: int + + @ivar numAxis: (read-only) The number of axes for the joystick at this index. + @type numAxis: integer + @ivar numButtons: (read-only) The number of buttons for the joystick at this index. + @type numButtons: integer + @ivar numHats: (read-only) The number of hats for the joystick at this index. + @type numHats: integer + @ivar connected: (read-only) True if a joystick is connected at this joysticks index. + @type connected: boolean + @ivar index: The joystick index to use (from 0 to 7). The first joystick is always 0. + @type index: integer + @ivar threshold: Axis threshold. Joystick axis motion below this threshold wont trigger an event. Use values between (0 and 32767), lower values are more sensitive. + @type threshold: integer + @ivar button: The button index the sensor reacts to (first button = 0). When the "All Events" toggle is set, this option has no effect. + @type button: integer + @ivar axis: The axis this sensor reacts to, as a list of two values [axisIndex, axisDirection] + axisIndex: the axis index to use when detecting axis movement, 1=primary directional control, 2=secondary directional control. + axisDirection: 0=right, 1=up, 2=left, 3=down + @type axis: [integer, integer] + @ivar hat: The hat the sensor reacts to, as a list of two values: [hatIndex, hatDirection] + hatIndex: the hat index to use when detecting hat movement, 1=primary hat, 2=secondary hat (4 max). + hatDirection: 1-12 + @type hat: [integer, integer] + """ + + def getButtonActiveList(): + """ + Returns a list containing the indicies of the currently pressed buttons. + @rtype: list + """ + def getButtonStatus(buttonIndex): + """ + Returns a bool of the current pressed state of the specified button. + @param buttonIndex: the button index, 0=first button + @type buttonIndex: integer + @rtype: bool + """ +#{Deprecated + def getIndex(): + """ + Returns the joystick index to use (from 1 to 8). + + @deprecated: Use the L{index} attribute instead. + @rtype: integer + """ + def setIndex(index): + """ + Sets the joystick index to use. + + @deprecated: Use the L{index} attribute instead. + @param index: The index of this joystick sensor, Clamped between 1 and 8. + @type index: integer + @note: This is only useful when you have more then 1 joystick connected to your computer - multiplayer games. + """ + def getAxis(): + """ + Returns the current axis this sensor reacts to. See L{getAxisValue()<SCA_JoystickSensor.getAxisValue>} for the current axis state. + + @deprecated: Use the L{axis} attribute instead. + @rtype: list + @return: 2 values returned are [axisIndex, axisDirection] - see L{setAxis()<SCA_JoystickSensor.setAxis>} for their purpose. + @note: When the "All Events" toggle is set, this option has no effect. + """ + def setAxis(axisIndex, axisDirection): + """ + @deprecated: Use the L{axis} attribute instead. + @param axisIndex: Set the axis index to use when detecting axis movement. + @type axisIndex: integer from 1 to 2 + @param axisDirection: Set the axis direction used for detecting motion. 0:right, 1:up, 2:left, 3:down. + @type axisDirection: integer from 0 to 3 + @note: When the "All Events" toggle is set, this option has no effect. + """ + def getAxisValue(): + """ + Returns the state of the joysticks axis. See differs to L{getAxis()<SCA_JoystickSensor.getAxis>} returning the current state of the joystick. + + @deprecated: Use the L{axisValues} attribute instead. + @rtype: list + @return: 4 values, each spesifying the value of an axis between -32767 and 32767 depending on how far the axis is pushed, 0 for nothing. + + The first 2 values are used by most joysticks and gamepads for directional control. 3rd and 4th values are only on some joysticks and can be used for arbitary controls. + + left:[-32767, 0, ...], right:[32767, 0, ...], up:[0, -32767, ...], down:[0, 32767, ...] + @note: Some gamepads only set the axis on and off like a button. + """ + def getThreshold(): + """ + Get the axis threshold. See L{setThreshold()<SCA_JoystickSensor.setThreshold>} for details. + + @deprecated: Use the L{threshold} attribute instead. + @rtype: integer + """ + def setThreshold(threshold): + """ + Set the axis threshold. + + @deprecated: Use the L{threshold} attribute instead. + @param threshold: Joystick axis motion below this threshold wont trigger an event. Use values between (0 and 32767), lower values are more sensitive. + @type threshold: integer + """ + def getButton(): + """ + Returns the button index the sensor reacts to. See L{getButtonValue()<SCA_JoystickSensor.getButtonValue>} for a list of pressed buttons. + + @deprecated: Use the L{button} attribute instead. + @rtype: integer + @note: When the "All Events" toggle is set, this option has no effect. + """ + def setButton(index): + """ + Sets the button index the sensor reacts to when the "All Events" option is not set. + + @deprecated: Use the L{button} attribute instead. + @note: When the "All Events" toggle is set, this option has no effect. + """ + def getButtonValue(): + """ + Returns a list containing the indicies of the currently pressed buttons. + + @deprecated: Use the L{getButtonActiveList} method instead. + @rtype: list + """ + def getHat(): + """ + Returns the current hat direction this sensor is set to. + [hatNumber, hatDirection]. + + @deprecated: Use the L{hat} attribute instead. + @rtype: list + @note: When the "All Events" toggle is set, this option has no effect. + """ + def setHat(index,direction): + """ + Sets the hat index the sensor reacts to when the "All Events" option is not set. + + @deprecated: Use the L{hat} attribute instead. + @type index: integer + """ + def getNumAxes(): + """ + Returns the number of axes for the joystick at this index. + + @deprecated: Use the L{numAxis} attribute instead. + @rtype: integer + """ + def getNumButtons(): + """ + Returns the number of buttons for the joystick at this index. + + @deprecated: Use the L{numButtons} attribute instead. + @rtype: integer + """ + def getNumHats(): + """ + Returns the number of hats for the joystick at this index. + + @deprecated: Use the L{numHats} attribute instead. + @rtype: integer + """ + def isConnected(): + """ + Returns True if a joystick is detected at this joysticks index. + + @deprecated: Use the L{connected} attribute instead. + @rtype: bool + """ +#} + +class SCA_KeyboardSensor(SCA_ISensor): + """ + A keyboard sensor detects player key presses. + + See module L{GameKeys} for keycode values. + + @ivar key: The key code this sensor is looking for. + @type key: keycode from L{GameKeys} module + @ivar hold1: The key code for the first modifier this sensor is looking for. + @type hold1: keycode from L{GameKeys} module + @ivar hold2: The key code for the second modifier this sensor is looking for. + @type hold2: keycode from L{GameKeys} module + @ivar toggleProperty: The name of the property that indicates whether or not to log keystrokes as a string. + @type toggleProperty: string + @ivar targetProperty: The name of the property that receives keystrokes in case in case a string is logged. + @type targetProperty: string + @ivar useAllKeys: Flag to determine whether or not to accept all keys. + @type useAllKeys: boolean + @ivar events: a list of pressed keys that have either been pressed, or just released, or are active this frame. (read-only). + + - 'keycode' matches the values in L{GameKeys}. + - 'status' uses... + - L{GameLogic.KX_INPUT_NONE} + - L{GameLogic.KX_INPUT_JUST_ACTIVATED} + - L{GameLogic.KX_INPUT_ACTIVE} + - L{GameLogic.KX_INPUT_JUST_RELEASED} + + @type events: list [[keycode, status], ...] + """ + + def getKeyStatus(keycode): + """ + Get the status of a key. + + @rtype: key state L{GameLogic} members (KX_INPUT_NONE, KX_INPUT_JUST_ACTIVATED, KX_INPUT_ACTIVE, KX_INPUT_JUST_RELEASED) + @return: The state of the given key + @type keycode: integer + @param keycode: The code that represents the key you want to get the state of + """ + +#{Deprecated + def getKey(): + """ + Returns the key code this sensor is looking for. + + @deprecated: Use the L{key} attribute instead. + @rtype: keycode from L{GameKeys} module + """ + + def setKey(keycode): + """ + Set the key this sensor should listen for. + + @deprecated: Use the L{key} attribute instead. + @type keycode: keycode from L{GameKeys} module + """ + + def getHold1(): + """ + Returns the key code for the first modifier this sensor is looking for. + + @deprecated: Use the L{hold1} attribute instead. + @rtype: keycode from L{GameKeys} module + """ + + def setHold1(keycode): + """ + Sets the key code for the first modifier this sensor should look for. + + @deprecated: Use the L{hold1} attribute instead. + @type keycode: keycode from L{GameKeys} module + """ + + def getHold2(): + """ + Returns the key code for the second modifier this sensor is looking for. + + @deprecated: Use the L{hold2} attribute instead. + @rtype: keycode from L{GameKeys} module + """ + + def setHold2(keycode): + """ + Sets the key code for the second modifier this sensor should look for. + + @deprecated: Use the L{hold2} attribute instead. + @type keycode: keycode from L{GameKeys} module + """ + + def getPressedKeys(): + """ + Get a list of keys that have either been pressed, or just released this frame. + + @deprecated: Use the L{events} attribute instead. + @rtype: list of key status. [[keycode, status]] + """ + + def getCurrentlyPressedKeys(): + """ + Get a list of currently pressed keys that have either been pressed, or just released + + @deprecated: Use the L{events} attribute instead. + @rtype: list of key status. [[keycode, status]] + """ +#} + +class SCA_NANDController(SCA_IController): + """ + An NAND controller activates when all linked sensors are not active. + + There are no special python methods for this controller. + """ + +class SCA_NORController(SCA_IController): + """ + An NOR controller activates only when all linked sensors are de-activated. + + There are no special python methods for this controller. + """ + +class SCA_ORController(SCA_IController): + """ + An OR controller activates when any connected sensor activates. + + There are no special python methods for this controller. + """ + +class SCA_PropertyActuator(SCA_IActuator): + """ + Property Actuator + + Properties: + + @ivar propName: the property on which to operate. + @type propName: string + @ivar value: the value with which the actuator operates. + @type value: string + @ivar mode: TODO - add constants to game logic dict!. + @type mode: int + """ +#{ Deprecated + def setProperty(prop): + """ + Set the property on which to operate. + + If there is no property of this name, the call is ignored. + + @deprecated: Use the L{propName} attribute instead. + @type prop: string + @param prop: The name of the property to set. + """ + def getProperty(): + """ + Returns the name of the property on which to operate. + + @deprecated: Use the L{propName} attribute instead. + @rtype: string + """ + def setValue(value): + """ + Set the value with which the actuator operates. + + If the value is not compatible with the type of the + property, the subsequent action is ignored. + + @deprecated: Use the L{value} attribute instead. + @type value: string + """ + def getValue(): + """ + Gets the value with which this actuator operates. + + @deprecated: Use the L{value} attribute instead. + @rtype: string + """ +#} + +class SCA_PropertySensor(SCA_ISensor): + """ + Activates when the game object property matches. + + Properties: + + @ivar mode: type of check on the property: + KX_PROPSENSOR_EQUAL(1), KX_PROPSENSOR_NOTEQUAL(2), KX_PROPSENSOR_INTERVAL(3), + KX_PROPSENSOR_CHANGED(4), KX_PROPSENSOR_EXPRESSION(5) + @type mode: integer + @ivar propName: the property the sensor operates. + @type propName: string + @ivar value: the value with which the sensor compares to the value of the property. + @type value: string + """ +#{ Deprecated + def getType(): + """ + Gets when to activate this sensor. + + @deprecated: Use the L{mode} attribute instead. + @return: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL, + KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED, + or KX_PROPSENSOR_EXPRESSION. + """ + + def setType(checktype): + """ + Set the type of check to perform. + + @deprecated: Use the L{mode} attribute instead. + @type checktype: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL, + KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED, + or KX_PROPSENSOR_EXPRESSION. + """ + + def getProperty(): + """ + Return the property with which the sensor operates. + + @deprecated: Use the L{propName} attribute instead. + @rtype: string + @return: the name of the property this sensor is watching. + """ + def setProperty(name): + """ + Sets the property with which to operate. If there is no property + of that name, this call is ignored. + + @deprecated: Use the L{propName} attribute instead. + @type name: string. + """ + def getValue(): + """ + Return the value with which the sensor compares to the value of the property. + + @deprecated: Use the L{value} attribute instead. + @rtype: string + @return: the value of the property this sensor is watching. + """ + def setValue(value): + """ + Set the value with which the sensor operates. If the value + is not compatible with the type of the property, the subsequent + action is ignored. + + @deprecated: Use the L{value} attribute instead. + @type value: string + """ +#} + +class SCA_PythonController(SCA_IController): + """ + A Python controller uses a Python script to activate it's actuators, + based on it's sensors. + + Properties: + + @ivar script: The value of this variable depends on the execution methid. + - When 'Script' execution mode is set this value contains the entire python script as a single string (not the script name as you might expect) which can be modified to run different scripts. + - When 'Module' execution mode is set this value will contain a single line string - module name and function "module.func" or "package.modile.func" where the module names are python textblocks or external scripts. + note: once this is set the script name given for warnings will remain unchanged. + @type script: string + @ivar mode: the execution mode for this controller (read-only). + - Script: 0, Execite the L{script} as a python code. + - Module: 1, Execite the L{script} as a module and function. + @type mode: int + + @group Deprecated: getScript, setScript + """ + def activate(actuator): + """ + Activates an actuator attached to this controller. + @type actuator: actuator or the actuator name as a string + """ + def deactivate(actuator): + """ + Deactivates an actuator attached to this controller. + @type actuator: actuator or the actuator name as a string + """ + def getScript(): + """ + Gets the Python script body this controller executes. + + @deprecated: Use the L{script} attribute instead. + @rtype: string + """ + def setScript(script_body): + """ + Sets the Python script string this controller executes. + + @deprecated: Use the L{script} attribute instead. + @type script_body: string. + """ + +class SCA_RandomActuator(SCA_IActuator): + """ + Random Actuator + + Properties: + + @ivar seed: Seed of the random number generator. + Equal seeds produce equal series. If the seed is 0, + the generator will produce the same value on every call. + @type seed: integer + @ivar para1: the first parameter of the active distribution. + Refer to the documentation of the generator types for the meaning + of this value. + @type para1: float, read-only + @ivar para2: the second parameter of the active distribution. + Refer to the documentation of the generator types for the meaning + of this value. + @type para2: float, read-only + @ivar distribution: distribution type: + KX_RANDOMACT_BOOL_CONST, KX_RANDOMACT_BOOL_UNIFORM, KX_RANDOMACT_BOOL_BERNOUILLI, + KX_RANDOMACT_INT_CONST, KX_RANDOMACT_INT_UNIFORM, KX_RANDOMACT_INT_POISSON, + KX_RANDOMACT_FLOAT_CONST, KX_RANDOMACT_FLOAT_UNIFORM, KX_RANDOMACT_FLOAT_NORMAL, + KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL + @type distribution: integer, read-only + @ivar propName: the name of the property to set with the random value. + If the generator and property types do not match, the assignment is ignored. + @type propName: string + + """ + def setBoolConst(value): + """ + Sets this generator to produce a constant boolean value. + + @param value: The value to return. + @type value: boolean + """ + def setBoolUniform(): + """ + Sets this generator to produce a uniform boolean distribution. + + The generator will generate True or False with 50% chance. + """ + def setBoolBernouilli(value): + """ + Sets this generator to produce a Bernouilli distribution. + + @param value: Specifies the proportion of False values to produce. + - 0.0: Always generate True + - 1.0: Always generate False + @type value: float + """ + def setIntConst(value): + """ + Sets this generator to always produce the given value. + + @param value: the value this generator produces. + @type value: integer + """ + def setIntUniform(lower_bound, upper_bound): + """ + Sets this generator to produce a random value between the given lower and + upper bounds (inclusive). + + @type lower_bound: integer + @type upper_bound: integer + """ + def setIntPoisson(value): + """ + Generate a Poisson-distributed number. + + This performs a series of Bernouilli tests with parameter value. + It returns the number of tries needed to achieve succes. + + @type value: float + """ + def setFloatConst(value): + """ + Always generate the given value. + + @type value: float + """ + def setFloatUniform(lower_bound, upper_bound): + """ + Generates a random float between lower_bound and upper_bound with a + uniform distribution. + + @type lower_bound: float + @type upper_bound: float + """ + def setFloatNormal(mean, standard_deviation): + """ + Generates a random float from the given normal distribution. + + @type mean: float + @param mean: The mean (average) value of the generated numbers + @type standard_deviation: float + @param standard_deviation: The standard deviation of the generated numbers. + """ + def setFloatNegativeExponential(half_life): + """ + Generate negative-exponentially distributed numbers. + + The half-life 'time' is characterized by half_life. + + @type half_life: float + """ +#{ Deprecated + def setSeed(seed): + """ + Sets the seed of the random number generator. + + Equal seeds produce equal series. If the seed is 0, + the generator will produce the same value on every call. + + @deprecated: Use the L{seed} attribute instead. + @type seed: integer + """ + def getSeed(): + """ + Returns the initial seed of the generator. + + @deprecated: Use the L{seed} attribute instead. + @rtype: integer + """ + def getPara1(): + """ + Returns the first parameter of the active distribution. + + Refer to the documentation of the generator types for the meaning + of this value. + + @deprecated: Use the L{para1} attribute instead. + @rtype: float + """ + def getPara2(): + """ + Returns the second parameter of the active distribution. + + Refer to the documentation of the generator types for the meaning + of this value. + + @deprecated: Use the L{para2} attribute instead. + @rtype: float + """ + def getDistribution(): + """ + Returns the type of random distribution. + + @deprecated: Use the L{distribution} attribute instead. + @rtype: distribution type + @return: KX_RANDOMACT_BOOL_CONST, KX_RANDOMACT_BOOL_UNIFORM, KX_RANDOMACT_BOOL_BERNOUILLI, + KX_RANDOMACT_INT_CONST, KX_RANDOMACT_INT_UNIFORM, KX_RANDOMACT_INT_POISSON, + KX_RANDOMACT_FLOAT_CONST, KX_RANDOMACT_FLOAT_UNIFORM, KX_RANDOMACT_FLOAT_NORMAL, + KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL + """ + def setProperty(property): + """ + Set the property to which the random value is assigned. + + If the generator and property types do not match, the assignment is ignored. + + @deprecated: Use the L{propName} attribute instead. + @type property: string + @param property: The name of the property to set. + """ + def getProperty(): + """ + Returns the name of the property to set. + + @deprecated: Use the L{propName} attribute instead. + @rtype: string + """ +#} + + +class SCA_RandomSensor(SCA_ISensor): + """ + This sensor activates randomly. + + @ivar lastDraw: The seed of the random number generator. + @type lastDraw: int + @ivar seed: The seed of the random number generator. + @type seed: int + """ + + def setSeed(seed): + """ + Sets the seed of the random number generator. + + If the seed is 0, the generator will produce the same value on every call. + + @type seed: integer. + """ + def getSeed(): + """ + Returns the initial seed of the generator. Equal seeds produce equal random + series. + + @rtype: integer + """ + def getLastDraw(): + """ + Returns the last random number generated. + + @rtype: integer + """ + +class SCA_XNORController(SCA_IController): + """ + An XNOR controller activates when all linked sensors are the same (activated or inative). + + There are no special python methods for this controller. + """ + +class SCA_XORController(SCA_IController): + """ + An XOR controller activates when there is the input is mixed, but not when all are on or off. + + There are no special python methods for this controller. + """ + +class KX_Camera(KX_GameObject): + """ + A Camera object. + + @group Constants: INSIDE, INTERSECT, OUTSIDE + @ivar INSIDE: see sphereInsideFrustum() and boxInsideFrustum() + @ivar INTERSECT: see sphereInsideFrustum() and boxInsideFrustum() + @ivar OUTSIDE: see sphereInsideFrustum() and boxInsideFrustum() + + @ivar lens: The camera's lens value. + @type lens: float + @ivar near: The camera's near clip distance. + @type near: float + @ivar far: The camera's far clip distance. + @type far: float + @ivar perspective: True if this camera has a perspective transform, False for an orthographic projection. + @type perspective: boolean + @ivar frustum_culling: True if this camera is frustum culling. + @type frustum_culling: boolean + @ivar projection_matrix: This camera's 4x4 projection matrix. + @type projection_matrix: 4x4 Matrix [[float]] + @ivar modelview_matrix: This camera's 4x4 model view matrix. (read-only) + Regenerated every frame from the camera's position and orientation. + @type modelview_matrix: 4x4 Matrix [[float]] + @ivar camera_to_world: This camera's camera to world transform. (read-only) + Regenerated every frame from the camera's position and orientation. + @type camera_to_world: 4x4 Matrix [[float]] + @ivar world_to_camera: This camera's world to camera transform. (read-only) + Regenerated every frame from the camera's position and orientation. + This is camera_to_world inverted. + @type world_to_camera: 4x4 Matrix [[float]] + @ivar useViewport: True when the camera is used as a viewport, set True to enable a viewport for this camera. + @type useViewport: bool + + @group Deprecated: enableViewport, getProjectionMatrix, setProjectionMatrix + """ + + def sphereInsideFrustum(centre, radius): + """ + Tests the given sphere against the view frustum. + + @note: when the camera is first initialized the result will be invalid because the projection matrix has not been set. + @param centre: The centre of the sphere (in world coordinates.) + @type centre: list [x, y, z] + @param radius: the radius of the sphere + @type radius: float + @return: INSIDE, OUTSIDE or INTERSECT + + Example:: + import GameLogic + co = GameLogic.getCurrentController() + cam = co.owner + + # A sphere of radius 4.0 located at [x, y, z] = [1.0, 1.0, 1.0] + if (cam.sphereInsideFrustum([1.0, 1.0, 1.0], 4) != cam.OUTSIDE): + # Sphere is inside frustum ! + # Do something useful ! + else: + # Sphere is outside frustum + """ + def boxInsideFrustum(box): + """ + Tests the given box against the view frustum. + + Example:: + import GameLogic + co = GameLogic.getCurrentController() + cam = co.owner + + # Box to test... + box = [] + box.append([-1.0, -1.0, -1.0]) + box.append([-1.0, -1.0, 1.0]) + box.append([-1.0, 1.0, -1.0]) + box.append([-1.0, 1.0, 1.0]) + box.append([ 1.0, -1.0, -1.0]) + box.append([ 1.0, -1.0, 1.0]) + box.append([ 1.0, 1.0, -1.0]) + box.append([ 1.0, 1.0, 1.0]) + + if (cam.boxInsideFrustum(box) != cam.OUTSIDE): + # Box is inside/intersects frustum ! + # Do something useful ! + else: + # Box is outside the frustum ! + + @note: when the camera is first initialized the result will be invalid because the projection matrix has not been set. + @return: INSIDE, OUTSIDE or INTERSECT + @type box: list + @param box: Eight (8) corner points of the box (in world coordinates.) + """ + def pointInsideFrustum(point): + """ + Tests the given point against the view frustum. + + Example:: + import GameLogic + co = GameLogic.getCurrentController() + cam = co.owner + + # Test point [0.0, 0.0, 0.0] + if (cam.pointInsideFrustum([0.0, 0.0, 0.0])): + # Point is inside frustum ! + # Do something useful ! + else: + # Box is outside the frustum ! + + @note: when the camera is first initialized the result will be invalid because the projection matrix has not been set. + @rtype: boolean + @return: True if the given point is inside this camera's viewing frustum. + @type point: [x, y, z] + @param point: The point to test (in world coordinates.) + """ + def getCameraToWorld(): + """ + Returns the camera-to-world transform. + + @rtype: matrix (4x4 list) + @return: the camera-to-world transform matrix. + """ + def getWorldToCamera(): + """ + Returns the world-to-camera transform. + + This returns the inverse matrix of getCameraToWorld(). + + @rtype: matrix (4x4 list) + @return: the world-to-camera transform matrix. + """ + def getProjectionMatrix(): + """ + Returns the camera's projection matrix. + + @deprecated: Use the L{projection_matrix} attribute instead. + @rtype: matrix (4x4 list) + @return: the camera's projection matrix. + """ + def setProjectionMatrix(matrix): + """ + Sets the camera's projection matrix. + + You should use normalised device coordinates for the clipping planes: + left = -1.0, right = 1.0, top = 1.0, bottom = -1.0, near = cam.near, far = cam.far + + Example:: + import GameLogic + + def Scale(matrix, size): + for y in range(4): + for x in range(4): + matrix[y][x] = matrix[y][x] * size[y] + return matrix + + # Generate a perspective projection matrix + def Perspective(cam): + return [[cam.near, 0.0 , 0.0 , 0.0 ], + [0.0 , cam.near, 0.0 , 0.0 ], + [0.0 , 0.0 , -(cam.far+cam.near)/(cam.far-cam.near), -2.0*cam.far*cam.near/(cam.far - cam.near)], + [0.0 , 0.0 , -1.0 , 0.0 ]] + + # Generate an orthographic projection matrix + # You will need to scale the camera + def Orthographic(cam): + return [[1.0/cam.scaling[0], 0.0 , 0.0 , 0.0 ], + [0.0 , 1.0/cam.scaling[1], 0.0 , 0.0 ], + [0.0 , 0.0 , -2.0/(cam.far-cam.near), -(cam.far+cam.near)/(cam.far-cam.near)], + [0.0 , 0.0 , 0.0 , 1.0 ]] + + # Generate an isometric projection matrix + def Isometric(cam): + return Scale([[0.707, 0.0 , 0.707, 0.0], + [0.408, 0.816,-0.408, 0.0], + [0.0 , 0.0 , 0.0 , 0.0], + [0.0 , 0.0 , 0.0 , 1.0]], + [1.0/cam.scaling[0], 1.0/cam.scaling[1], 1.0/cam.scaling[2], 1.0]) + + co = GameLogic.getCurrentController() + cam = co.owner + cam.setProjectionMatrix(Perspective(cam))) + + @deprecated: Use the L{projection_matrix} attribute instead. + @type matrix: 4x4 matrix. + @param matrix: The new projection matrix for this camera. + """ + + def enableViewport(viewport): + """ + Use this camera to draw a viewport on the screen (for split screen games or overlay scenes). The viewport region is defined with L{setViewport}. + + @deprecated: Use the L{useViewport} attribute instead. + @type viewport: bool + @param viewport: the new viewport status + """ + def setOnTop(): + """ + Set this cameras viewport ontop of all other viewport. + """ + def setViewport(left, bottom, right, top): + """ + Sets the region of this viewport on the screen in pixels. + + Use L{Rasterizer.getWindowHeight} L{Rasterizer.getWindowWidth} to calculate values relative to the entire display. + + @type left: int + @type bottom: int + @type right: int + @type top: int + """ + def getScreenPosition(arg): + """ + Gets the position of an object projected on screen space. + + Example: + # For an object in the middle of the screen, coord = [0.5,0.5] + coord = camera.getScreenPosition(object) + + @param arg: L{KX_GameObject}, object name or list [x, y, z] + @rtype: list [x, y] + @return: the object's position in screen coordinates. + """ + def getScreenVect(x, y): + """ + Gets the vector from the camera position in the screen coordinate direction. + + Example: + # Gets the vector of the camera front direction: + m_vect = camera.getScreenVect(0.5,0.5) + + @type x: float + @type y: float + @rtype: 3d vector + @return: the vector from a screen coordinate. + """ + def getScreenRay(x, y, dist, property): + """ + Look towards a screen coordinate (x,y) and find first object hit within dist that matches prop. + The ray is similar to KX_GameObject->rayCastTo. + + Example: + # Gets an object with a property "wall" in front of the camera within a distance of 100: + target = camera.getScreenRay(0.5,0.5,100,"wall") + + @type x: float + @type y: float + @param dist: max distance to look (can be negative => look behind); 0 or omitted => detect up to other + @type dist: float + @param property: property name that object must have; can be omitted => detect any object + @type property: string + @rtype: L{KX_GameObject} + @return: the first object hit or None if no object or object does not match prop + """ + +# Util func to extract all attrs +""" +import types +attrs = [] +for name, val in locals().items(): + if name.startswith('__'): + continue + if type(val) == types.ClassType: + for line in val.__doc__.split('\n'): + if '@ivar' in line: + attrs.append(name + '::' + line.split()[1].replace(':', '')) + +for a in attrs: + print a +""" + + +# Util func to construct a mapping from deprecated attrs to new ones. +""" +import types +import re +import pprint +depAttrs = {} +for name, val in locals().items(): + if name.startswith('__'): + continue + if type(val) == types.ClassType: + print "\t# %s" % name + + # Inspect each attribute. + for attrName in dir(val): + if attrName.startswith('__'): + continue + attr = getattr(val, attrName) + + # Check whether this attribute is deprecated by searching each line. + newAttrName = None + for line in attr.__doc__.split('\n'): + match = re.search(r'@deprecated.*L{(\w+)}', line) + if match: + newAttrName = match.group(1) + break + if not newAttrName: + continue + + # Store the mappings to new attributes in a list (because there + # could be collisions). + if attrName not in depAttrs: + depAttrs[attrName] = {} + mapping = depAttrs[attrName] + + for line in val.__doc__.split('\n'): + if ("@type %s:" % newAttrName) in line: + # The attribute is being replaced in this class (i.e. the + # deprecated attribute wasn't inherited from a parent). We + # have a winner! + funcType = None + if 'sequence' in line: + funcType = 'Keyed' + else: + funcType = 'Simple' + + if attrName.startswith('get') or attrName.startswith('is'): + func = "replace%sGetter" % funcType + elif attrName.startswith('set') or attrName.startswith('enable'): + func = "replace%sSetter" % funcType + else: + func = 'UNKNOWN' + + # Another mapping, from a conversion tuple to lists of class + # names. + conversion = (func, newAttrName) + if conversion not in mapping: + mapping[conversion] = [] + mapping[conversion].append(name) + break + +pprint.pprint(depAttrs, width = 100) +""" diff --git a/source/gameengine/PyDoc/KX_ActuatorSensor.py b/source/gameengine/PyDoc/KX_ActuatorSensor.py deleted file mode 100644 index cdfbf27576e..00000000000 --- a/source/gameengine/PyDoc/KX_ActuatorSensor.py +++ /dev/null @@ -1,25 +0,0 @@ -# $Id$ -# Documentation for KX_ActuatorSensor -from SCA_IActuator import * -from SCA_ISensor import * - -class KX_ActuatorSensor(SCA_ISensor): - """ - Actuator sensor detect change in actuator state of the parent object. - It generates a positive pulse if the corresponding actuator is activated - and a negative pulse if the actuator is deactivated. - """ - def getActuator(): - """ - Return the Actuator with which the sensor operates. - - @rtype: string - """ - def setActuator(name): - """ - Sets the Actuator with which to operate. If there is no Actuator - of this name, the function has no effect. - - @param name: actuator name - @type name: string - """ diff --git a/source/gameengine/PyDoc/KX_CDActuator.py b/source/gameengine/PyDoc/KX_CDActuator.py deleted file mode 100644 index 2c202476584..00000000000 --- a/source/gameengine/PyDoc/KX_CDActuator.py +++ /dev/null @@ -1,32 +0,0 @@ -# $Id$ -# Documentation for CD Actuator -from SCA_IActuator import * - -class KX_CDActuator(SCA_IActuator): - def startCD(): - """ - Starts the CD playing. - """ - def stopCD(): - """ - Stops the CD playing. - """ - def pauseCD(): - """ - Pauses the CD. - """ - def setGain(gain): - """ - Sets the gain (volume) of the CD. - - @type gain: float - @param gain: the gain to set the CD to. 0.0 = silent, 1.0 = max volume. - """ - def getGain(): - """ - Gets the current gain (volume) of the CD. - - @rtype: float - @return: Between 0.0 (silent) and 1.0 (max volume) - """ - diff --git a/source/gameengine/PyDoc/KX_Camera.py b/source/gameengine/PyDoc/KX_Camera.py deleted file mode 100644 index 4cadf1c0ed0..00000000000 --- a/source/gameengine/PyDoc/KX_Camera.py +++ /dev/null @@ -1,187 +0,0 @@ -# $Id$ -# Documentation for Camera game objects. -from KX_GameObject import * - -class KX_Camera(KX_GameObject): - """ - A Camera object. - - @group Constants: INSIDE, INTERSECT, OUTSIDE - @ivar INSIDE: see sphereInsideFrustum() and boxInsideFrustum() - @ivar INTERSECT: see sphereInsideFrustum() and boxInsideFrustum() - @ivar OUTSIDE: see sphereInsideFrustum() and boxInsideFrustum() - - @ivar lens: The camera's lens value. - @type lens: float - @ivar near: The camera's near clip distance. - @type near: float - @ivar far: The camera's far clip distance. - @type far: float - @ivar perspective: True if this camera has a perspective transform. - - If perspective is False, this camera has an orthographic transform. - - Note that the orthographic transform is faked by multiplying the lens attribute - by 100.0 and translating the camera 100.0 along the z axis. - - This is the same as Blender. If you want a true orthographic transform, see L{setProjectionMatrix}. - @type perspective: boolean - @ivar frustum_culling: True if this camera is frustum culling. - @type frustum_culling: boolean - @ivar projection_matrix: This camera's 4x4 projection matrix. - @type projection_matrix: 4x4 Matrix [[float]] - @ivar modelview_matrix: This camera's 4x4 model view matrix. (read only) - Regenerated every frame from the camera's position and orientation. - @type modelview_matrix: 4x4 Matrix [[float]] - @ivar camera_to_world: This camera's camera to world transform. (read only) - Regenerated every frame from the camera's position and orientation. - @type camera_to_world: 4x4 Matrix [[float]] - @ivar world_to_camera: This camera's world to camera transform. (read only) - Regenerated every frame from the camera's position and orientation. - This is camera_to_world inverted. - @type world_to_camera: 4x4 Matrix [[float]] - """ - - def sphereInsideFrustum(centre, radius): - """ - Tests the given sphere against the view frustum. - - @param centre: The centre of the sphere (in world coordinates.) - @type centre: list [x, y, z] - @param radius: the radius of the sphere - @type radius: float - @return: INSIDE, OUTSIDE or INTERSECT - - Example:: - import GameLogic - co = GameLogic.getCurrentController() - cam = co.GetOwner() - - # A sphere of radius 4.0 located at [x, y, z] = [1.0, 1.0, 1.0] - if (cam.sphereInsideFrustum([1.0, 1.0, 1.0], 4) != cam.OUTSIDE): - # Sphere is inside frustum ! - # Do something useful ! - else: - # Sphere is outside frustum - """ - def boxInsideFrustum(box): - """ - Tests the given box against the view frustum. - - Example:: - import GameLogic - co = GameLogic.getCurrentController() - cam = co.GetOwner() - - # Box to test... - box = [] - box.append([-1.0, -1.0, -1.0]) - box.append([-1.0, -1.0, 1.0]) - box.append([-1.0, 1.0, -1.0]) - box.append([-1.0, 1.0, 1.0]) - box.append([ 1.0, -1.0, -1.0]) - box.append([ 1.0, -1.0, 1.0]) - box.append([ 1.0, 1.0, -1.0]) - box.append([ 1.0, 1.0, 1.0]) - - if (cam.boxInsideFrustum(box) != cam.OUTSIDE): - # Box is inside/intersects frustum ! - # Do something useful ! - else: - # Box is outside the frustum ! - - @return: INSIDE, OUTSIDE or INTERSECT - @type box: list - @param box: Eight (8) corner points of the box (in world coordinates.) - """ - def pointInsideFrustum(point): - """ - Tests the given point against the view frustum. - - Example:: - import GameLogic - co = GameLogic.getCurrentController() - cam = co.GetOwner() - - # Test point [0.0, 0.0, 0.0] - if (cam.pointInsideFrustum([0.0, 0.0, 0.0])): - # Point is inside frustum ! - # Do something useful ! - else: - # Box is outside the frustum ! - - @rtype: boolean - @return: True if the given point is inside this camera's viewing frustum. - @type point: [x, y, z] - @param point: The point to test (in world coordinates.) - """ - def getCameraToWorld(): - """ - Returns the camera-to-world transform. - - @rtype: matrix (4x4 list) - @return: the camera-to-world transform matrix. - """ - def getWorldToCamera(): - """ - Returns the world-to-camera transform. - - This returns the inverse matrix of getCameraToWorld(). - - @rtype: matrix (4x4 list) - @return: the world-to-camera transform matrix. - """ - def getProjectionMatrix(): - """ - Returns the camera's projection matrix. - - @rtype: matrix (4x4 list) - @return: the camera's projection matrix. - """ - def setProjectionMatrix(matrix): - """ - Sets the camera's projection matrix. - - You should use normalised device coordinates for the clipping planes: - left = -1.0, right = 1.0, top = 1.0, bottom = -1.0, near = cam.near, far = cam.far - - Example:: - import GameLogic - - def Scale(matrix, size): - for y in range(4): - for x in range(4): - matrix[y][x] = matrix[y][x] * size[y] - return matrix - - # Generate a perspective projection matrix - def Perspective(cam): - return [[cam.near, 0.0 , 0.0 , 0.0 ], - [0.0 , cam.near, 0.0 , 0.0 ], - [0.0 , 0.0 , -(cam.far+cam.near)/(cam.far-cam.near), -2.0*cam.far*cam.near/(cam.far - cam.near)], - [0.0 , 0.0 , -1.0 , 0.0 ]] - - # Generate an orthographic projection matrix - # You will need to scale the camera - def Orthographic(cam): - return [[1.0/cam.scaling[0], 0.0 , 0.0 , 0.0 ], - [0.0 , 1.0/cam.scaling[1], 0.0 , 0.0 ], - [0.0 , 0.0 , -2.0/(cam.far-cam.near), -(cam.far+cam.near)/(cam.far-cam.near)], - [0.0 , 0.0 , 0.0 , 1.0 ]] - - # Generate an isometric projection matrix - def Isometric(cam): - return Scale([[0.707, 0.0 , 0.707, 0.0], - [0.408, 0.816,-0.408, 0.0], - [0.0 , 0.0 , 0.0 , 0.0], - [0.0 , 0.0 , 0.0 , 1.0]], - [1.0/cam.scaling[0], 1.0/cam.scaling[1], 1.0/cam.scaling[2], 1.0]) - - co = GameLogic.getCurrentController() - cam = co.getOwner() - cam.setProjectionMatrix(Perspective(cam))) - - @type matrix: 4x4 matrix. - @param matrix: The new projection matrix for this camera. - """ - diff --git a/source/gameengine/PyDoc/KX_CameraActuator.py b/source/gameengine/PyDoc/KX_CameraActuator.py deleted file mode 100644 index 9a9abaf3d57..00000000000 --- a/source/gameengine/PyDoc/KX_CameraActuator.py +++ /dev/null @@ -1,88 +0,0 @@ -# $Id$ -# Documentation for KX_CameraActuator -from SCA_IActuator import * - -class KX_CameraActuator(SCA_IActuator): - """ - Applies changes to a camera. - - @author: snail - """ - def getObject(name_only = 1): - """ - Returns the name of the object this actuator tracks. - - @type name_only: bool - @param name_only: optional argument, when 0 return a KX_GameObject - @rtype: string, KX_GameObject or None if no object is set - """ - - def setObject(target): - """ - Sets the object this actuator tracks. - - @param target: the object to track. - @type target: L{KX_GameObject}, string or None - """ - - def getMin(): - """ - Returns the minimum distance to target maintained by the actuator. - - @rtype: float - """ - - def setMin(distance): - """ - Sets the minimum distance to the target object maintained by the - actuator. - - @param distance: The minimum distance to maintain. - @type distance: float - """ - - def getMax(): - """ - Gets the maximum distance to stay from the target object. - - @rtype: float - """ - - def setMax(distance): - """ - Sets the maximum distance to stay from the target object. - - @param distance: The maximum distance to maintain. - @type distance: float - """ - - def getHeight(): - """ - Returns the height to stay above the target object. - - @rtype: float - """ - - def setHeight(height): - """ - Sets the height to stay above the target object. - - @type height: float - @param height: The height to stay above the target object. - """ - - def setXY(xaxis): - """ - Sets the axis to get behind. - - @param xaxis: False to track Y axis, True to track X axis. - @type xaxis: boolean - """ - - def getXY(): - """ - Returns the axis this actuator is tracking. - - @return: True if tracking X axis, False if tracking Y axis. - @rtype: boolean - """ diff --git a/source/gameengine/PyDoc/KX_ConstraintActuator.py b/source/gameengine/PyDoc/KX_ConstraintActuator.py deleted file mode 100644 index 7c7ad5aa0fa..00000000000 --- a/source/gameengine/PyDoc/KX_ConstraintActuator.py +++ /dev/null @@ -1,180 +0,0 @@ -# $Id$ -# Documentation for KX_ConstraintActuator -from SCA_IActuator import * - -class KX_ConstraintActuator(SCA_IActuator): - """ - A constraint actuator limits the position, rotation, distance or orientation of an object. - """ - def setDamp(time): - """ - Sets the time this constraint is delayed. - - @param time: The number of frames to delay. - Negative values are ignored. - @type time: integer - """ - def getDamp(): - """ - Returns the damping time of the constraint. - - @rtype: integer - """ - def setMin(lower): - """ - Sets the lower bound of the constraint. - - For rotational and orientation constraints, lower is specified in degrees. - - @type lower: float - """ - def getMin(): - """ - Gets the lower bound of the constraint. - - For rotational and orientation constraints, the lower bound is returned in radians. - - @rtype: float - """ - def setMax(upper): - """ - Sets the upper bound of the constraint. - - For rotational and orientation constraints, upper is specified in degrees. - - @type upper: float - """ - def getMax(): - """ - Gets the upper bound of the constraint. - - For rotational and orientation constraints, the upper bound is returned in radians. - - @rtype: float - """ - def setLimit(limit): - """ - Sets the type of constraint. - - See module L{GameLogic} for valid constraint types. - - @param limit: - Position constraints: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY, KX_CONSTRAINTACT_LOCZ - Rotation constraints: KX_CONSTRAINTACT_ROTX, KX_CONSTRAINTACT_ROTY or KX_CONSTRAINTACT_ROTZ - Distance contraints: KX_ACT_CONSTRAINT_DIRPX, KX_ACT_CONSTRAINT_DIRPY, KX_ACT_CONSTRAINT_DIRPZ, KX_ACT_CONSTRAINT_DIRNX, KX_ACT_CONSTRAINT_DIRNY, KX_ACT_CONSTRAINT_DIRNZ - Orientation constraints: KX_ACT_CONSTRAINT_ORIX, KX_ACT_CONSTRAINT_ORIY, KX_ACT_CONSTRAINT_ORIZ - """ - def getLimit(): - """ - Gets the type of constraint. - - See module L{GameLogic} for valid constraints. - - @return: - Position constraints: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY, KX_CONSTRAINTACT_LOCZ, - Rotation constraints: KX_CONSTRAINTACT_ROTX, KX_CONSTRAINTACT_ROTY, KX_CONSTRAINTACT_ROTZ, - Distance contraints: KX_ACT_CONSTRAINT_DIRPX, KX_ACT_CONSTRAINT_DIRPY, KX_ACT_CONSTRAINT_DIRPZ, KX_ACT_CONSTRAINT_DIRNX, KX_ACT_CONSTRAINT_DIRNY, KX_ACT_CONSTRAINT_DIRNZ, - Orientation constraints: KX_ACT_CONSTRAINT_ORIX, KX_ACT_CONSTRAINT_ORIY, KX_ACT_CONSTRAINT_ORIZ - """ - def setRotDamp(duration): - """ - Sets the time constant of the orientation constraint. - - @param duration: If the duration is negative, it is set to 0. - @type duration: integer - """ - def getRotDamp(): - """ - Returns the damping time for application of the constraint. - - @rtype: integer - """ - def setDirection(vector): - """ - Sets the reference direction in world coordinate for the orientation constraint - - @type vector: 3-tuple - """ - def getDirection(): - """ - Returns the reference direction of the orientation constraint in world coordinate. - - @rtype: 3-tuple - """ - def setOption(option): - """ - Sets several options of the distance constraint. - - @type option: integer - @param option: Binary combination of the following values: - 64 : Activate alignment to surface - 128 : Detect material rather than property - 256 : No deactivation if ray does not hit target - 512 : Activate distance control - """ - def getOption(): - """ - Returns the option parameter. - - @rtype: integer - """ - def setTime(duration): - """ - Sets the activation time of the actuator. - - @type duration: integer - @param duration: The actuator disables itself after this many frame. - If set to 0 or negative, the actuator is not limited in time. - """ - def getTime(): - """ - Returns the time parameter. - - @rtype: integer - """ - def setProperty(property): - """ - Sets the name of the property or material for the ray detection of the distance constraint. - - @type property: string - @param property: If empty, the ray will detect any collisioning object. - """ - def getProperty(): - """ - Returns the property parameter. - - @rtype: string - """ - def setDistance(distance): - """ - Sets the target distance in distance constraint. - - @type distance: float - """ - def getDistance(): - """ - Returns the distance parameter. - - @rtype: float - """ - def setRayLength(length): - """ - Sets the maximum ray length of the distance constraint. - - @type length: float - """ - def getRayLength(): - """ - Returns the length of the ray - - @rtype: float - """ - - - - - - - - - diff --git a/source/gameengine/PyDoc/KX_GameActuator.py b/source/gameengine/PyDoc/KX_GameActuator.py deleted file mode 100644 index b916b3b5617..00000000000 --- a/source/gameengine/PyDoc/KX_GameActuator.py +++ /dev/null @@ -1,22 +0,0 @@ -# $Id$ -# Documentation for KX_GameActuator -from SCA_IActuator import * - -class KX_GameActuator(SCA_IActuator): - """ - The game actuator loads a new .blend file, restarts the current .blend file or quits the game. - """ - def getFile(): - """ - Returns the filename of the new .blend file to load. - - @rtype: string - """ - def setFile(filename): - """ - Sets the new .blend file to load. - - @param filename: The file name this actuator will load. - @type filename: string - """ - diff --git a/source/gameengine/PyDoc/KX_GameObject.py b/source/gameengine/PyDoc/KX_GameObject.py deleted file mode 100644 index 505ce253dd1..00000000000 --- a/source/gameengine/PyDoc/KX_GameObject.py +++ /dev/null @@ -1,369 +0,0 @@ -# $Id$ -# Documentation for game objects - -class KX_GameObject: - """ - All game objects are derived from this class. - - Properties assigned to game objects are accessible as attributes of this class. - - @ivar name: The object's name. - @type name: string. - @ivar mass: The object's mass (provided the object has a physics controller). Read only. - @type mass: float - @ivar parent: The object's parent object. (Read only) - @type parent: L{KX_GameObject} - @ivar visible: visibility flag. - @type visible: boolean - @ivar position: The object's position. - @type position: list [x, y, z] - @ivar orientation: The object's orientation. 3x3 Matrix. - You can also write a Quaternion or Euler vector. - @type orientation: 3x3 Matrix [[float]] - @ivar scaling: The object's scaling factor. list [sx, sy, sz] - @type scaling: list [sx, sy, sz] - @ivar timeOffset: adjust the slowparent delay at runtime. - @type timeOffset: float - """ - def endObject(visible): - """ - Delete this object, can be used inpace of the EndObject Actuator. - The actual removal of the object from the scene is delayed. - """ - def replaceMesh(mesh_name): - """ - Replace the mesh of this object with a new mesh. This works the same was as the actuator. - @type mesh_name: string - """ - def getVisible(): - """ - Gets the game object's visible flag. - - @rtype: boolean - """ - def setVisible(visible): - """ - Sets the game object's visible flag. - - @type visible: boolean - """ - def getState(): - """ - Gets the game object's state bitmask. - - @rtype: int - @return: the objects state. - """ - def setState(state): - """ - Sets the game object's state flag. - The bitmasks for states from 1 to 30 can be set with (1<<0, 1<<1, 1<<2 ... 1<<29) - - @type state: integer - """ - def setPosition(pos): - """ - Sets the game object's position. - Global coordinates for root object, local for child objects. - - - @type pos: [x, y, z] - @param pos: the new position, in local coordinates. - """ - def setWorldPosition(pos): - """ - Sets the game object's position in world coordinates regardless if the object is root or child. - - @type pos: [x, y, z] - @param pos: the new position, in world coordinates. - """ - def getPosition(): - """ - Gets the game object's position. - - @rtype: list [x, y, z] - @return: the object's position in world coordinates. - """ - def setOrientation(orn): - """ - Sets the game object's orientation. - - @type orn: 3x3 rotation matrix, or Quaternion. - @param orn: a rotation matrix specifying the new rotation. - @note: When using this matrix with Blender.Mathutils.Matrix() types, it will need to be transposed. - """ - def alignAxisToVect(vect, axis): - """ - Aligns any of the game object's axis along the given vector. - - @type vect: 3d vector. - @param vect: a vector to align the axis. - @type axis: integer. - @param axis:The axis you want to align - - 0: X axis - - 1: Y axis - - 2: Z axis (default) - """ - def getAxisVect(vect): - """ - Returns the axis vector rotates by the objects worldspace orientation. - This is the equivalent if multiplying the vector by the orientation matrix. - - @type vect: 3d vector. - @param vect: a vector to align the axis. - @rtype: 3d vector. - @return: The vector in relation to the objects rotation. - - """ - def getOrientation(): - """ - Gets the game object's orientation. - - @rtype: 3x3 rotation matrix - @return: The game object's rotation matrix - @note: When using this matrix with Blender.Mathutils.Matrix() types, it will need to be transposed. - """ - def getLinearVelocity(local = 0): - """ - Gets the game object's linear velocity. - - This method returns the game object's velocity through it's centre of mass, - ie no angular velocity component. - - @type local: boolean - @param local: - False: you get the "global" velocity ie: relative to world orientation (default). - - True: you get the "local" velocity ie: relative to object orientation. - @rtype: list [vx, vy, vz] - @return: the object's linear velocity. - """ - def setLinearVelocity(velocity, local = 0): - """ - Sets the game object's linear velocity. - - This method sets game object's velocity through it's centre of mass, - ie no angular velocity component. - - @type velocity: 3d vector. - @param velocity: linear velocity vector. - @type local: boolean - @param local: - False: you get the "global" velocity ie: relative to world orientation (default). - - True: you get the "local" velocity ie: relative to object orientation. - """ - def getAngularVelocity(local = 0): - """ - Gets the game object's angular velocity. - - @type local: boolean - @param local: - False: you get the "global" velocity ie: relative to world orientation (default). - - True: you get the "local" velocity ie: relative to object orientation. - @rtype: list [vx, vy, vz] - @return: the object's angular velocity. - """ - def setAngularVelocity(velocity, local = 0): - """ - Sets the game object's angular velocity. - - @type velocity: 3d vector. - @param velocity: angular velocity vector. - @type local: boolean - @param local: - False: you get the "global" velocity ie: relative to world orientation (default). - - True: you get the "local" velocity ie: relative to object orientation. - """ - def getVelocity(point): - """ - Gets the game object's velocity at the specified point. - - Gets the game object's velocity at the specified point, including angular - components. - - @type point: list [x, y, z] - @param point: the point to return the velocity for, in local coordinates. (optional: default = [0, 0, 0]) - @rtype: list [vx, vy, vz] - @return: the velocity at the specified point. - """ - def getMass(): - """ - Gets the game object's mass. - - @rtype: float - @return: the object's mass. - """ - def getReactionForce(): - """ - Gets the game object's reaction force. - - The reaction force is the force applied to this object over the last simulation timestep. - This also includes impulses, eg from collisions. - - @rtype: list [fx, fy, fz] - @return: the reaction force of this object. - """ - def applyImpulse(point, impulse): - """ - Applies an impulse to the game object. - - This will apply the specified impulse to the game object at the specified point. - If point != getPosition(), applyImpulse will also change the object's angular momentum. - Otherwise, only linear momentum will change. - - @type point: list [x, y, z] - @param point: the point to apply the impulse to (in world coordinates) - """ - def suspendDynamics(): - """ - Suspends physics for this object. - """ - def restoreDynamics(): - """ - Resumes physics for this object. - @Note: The objects linear velocity will be applied from when the dynamics were suspended. - """ - def enableRigidBody(): - """ - Enables rigid body physics for this object. - - Rigid body physics allows the object to roll on collisions. - @Note: This is not working with bullet physics yet. - """ - def disableRigidBody(): - """ - Disables rigid body physics for this object. - @Note: This is not working with bullet physics yet. The angular is removed but rigid body physics can still rotate it later. - """ - def getParent(): - """ - Gets this object's parent. - - @rtype: L{KX_GameObject} - @return: this object's parent object, or None if this object has no parent. - """ - def setParent(parent): - """ - Sets this object's parent. - - @type parent: L{KX_GameObject} - @param parent: new parent object. - """ - def removeParent(): - """ - Removes this objects parent. - """ - def getChildren(): - """ - Return a list of immediate children of this object. - @rtype: list - @return: a list of all this objects children. - """ - def getChildrenRecursive(): - """ - Return a list of children of this object, including all their childrens children. - @rtype: list - @return: a list of all this objects children recursivly. - """ - def getMesh(mesh): - """ - Gets the mesh object for this object. - - @type mesh: integer - @param mesh: the mesh object to return (optional: default mesh = 0) - @rtype: L{KX_MeshProxy} - @return: the first mesh object associated with this game object, or None if this object has no meshs. - """ - def getPhysicsId(): - """ - Returns the user data object associated with this game object's physics controller. - """ - def getPropertyNames(): - """ - Gets a list of all property names. - @rtype: list - @return: All property names for this object. - """ - def getDistanceTo(other): - """ - Returns the distance to another object or point. - - @param other: a point or another L{KX_GameObject} to measure the distance to. - @type other: L{KX_GameObject} or list [x, y, z] - @rtype: float - """ - def getVectTo(other): - """ - Returns the vector and the distance to another object or point. - The vector is normalized unless the distance is 0, in which a NULL vector is returned. - - @param other: a point or another L{KX_GameObject} to get the vector and distance to. - @type other: L{KX_GameObject} or list [x, y, z] - @rtype: 3-tuple (float, 3-tuple (x,y,z), 3-tuple (x,y,z)) - @return: (distance, globalVector(3), localVector(3)) - """ - def rayCastTo(other,dist,prop): - """ - Look towards another point/object and find first object hit within dist that matches prop. - - The ray is always casted from the center of the object, ignoring the object itself. - The ray is casted towards the center of another object or an explicit [x,y,z] point. - Use rayCast() if you need to retrieve the hit point - - @param other: [x,y,z] or object towards which the ray is casted - @type other: L{KX_GameObject} or 3-tuple - @param dist: max distance to look (can be negative => look behind); 0 or omitted => detect up to other - @type dist: float - @param prop: property name that object must have; can be omitted => detect any object - @type prop: string - @rtype: L{KX_GameObject} - @return: the first object hit or None if no object or object does not match prop - """ - def rayCast(objto,objfrom,dist,prop,face,xray,poly): - """ - Look from a point/object to another point/object and find first object hit within dist that matches prop. - if poly is 0, returns a 3-tuple with object reference, hit point and hit normal or (None,None,None) if no hit. - if poly is 1, returns a 4-tuple with in addition a L{KX_PolyProxy} as 4th element. - - Ex:: - # shoot along the axis gun-gunAim (gunAim should be collision-free) - ob,point,normal = gun.rayCast(gunAim,None,50) - if ob: - # hit something - - Notes: - The ray ignores the object on which the method is called. - It is casted from/to object center or explicit [x,y,z] points. - - The face paremeter determines the orientation of the normal:: - 0 => hit normal is always oriented towards the ray origin (as if you casted the ray from outside) - 1 => hit normal is the real face normal (only for mesh object, otherwise face has no effect) - - The ray has X-Ray capability if xray parameter is 1, otherwise the first object hit (other than self object) stops the ray. - The prop and xray parameters interact as follow:: - prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray. - prop off, xray on : idem. - prop on, xray off: return closest hit if it matches prop, no hit otherwise. - prop on, xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray. - The L{KX_PolyProxy} 4th element of the return tuple when poly=1 allows to retrieve information on the polygon hit by the ray. - If there is no hit or the hit object is not a static mesh, None is returned as 4th element. - - The ray ignores collision-free objects and faces that dont have the collision flag enabled, you can however use ghost objects. - - @param objto: [x,y,z] or object to which the ray is casted - @type objto: L{KX_GameObject} or 3-tuple - @param objfrom: [x,y,z] or object from which the ray is casted; None or omitted => use self object center - @type objfrom: L{KX_GameObject} or 3-tuple or None - @param dist: max distance to look (can be negative => look behind); 0 or omitted => detect up to to - @type dist: float - @param prop: property name that object must have; can be omitted => detect any object - @type prop: string - @param face: normal option: 1=>return face normal; 0 or omitted => normal is oriented towards origin - @type face: int - @param xray: X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object - @type xray: int - @param poly: polygon option: 1=>return value is a 4-tuple and the 4th element is a L{KX_PolyProxy} - @type poly: int - @rtype: 3-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz)) - or 4-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz), L{KX_PolyProxy}) - @return: (object,hitpoint,hitnormal) or (object,hitpoint,hitnormal,polygon) - If no hit, returns (None,None,None) or (None,None,None,None) - If the object hit is not a static mesh, polygon is None - """ - - diff --git a/source/gameengine/PyDoc/KX_IpoActuator.py b/source/gameengine/PyDoc/KX_IpoActuator.py deleted file mode 100644 index e2fe3b289e3..00000000000 --- a/source/gameengine/PyDoc/KX_IpoActuator.py +++ /dev/null @@ -1,105 +0,0 @@ -# $Id$ -# Documentation for KX_IpoActuator -from SCA_IActuator import * - -class KX_IpoActuator(SCA_IActuator): - """ - IPO actuator activates an animation. - """ - def set(mode, startframe, endframe, force): - """ - Sets the properties of the actuator. - - @param mode: "Play", "PingPong", "Flipper", "LoopStop", "LoopEnd" or "FromProp" - @type mode: string - @param startframe: first frame to use - @type startframe: integer - @param endframe: last frame to use - @type endframe: integer - @param force: special mode - @type force: integer (0=normal, 1=interpret location as force, 2=additive) - """ - def setProperty(property): - """ - Sets the name of the property to be used in FromProp mode. - - @type property: string - """ - def setStart(startframe): - """ - Sets the frame from which the IPO starts playing. - - @type startframe: integer - """ - def getStart(): - """ - Returns the frame from which the IPO starts playing. - - @rtype: integer - """ - def setEnd(endframe): - """ - Sets the frame at which the IPO stops playing. - - @type endframe: integer - """ - def getEnd(): - """ - Returns the frame at which the IPO stops playing. - - @rtype: integer - """ - def setIpoAsForce(force): - """ - Set whether to interpret the ipo as a force rather than a displacement. - - @type force: boolean - @param force: KX_TRUE or KX_FALSE - """ - def getIpoAsForce(): - """ - Returns whether to interpret the ipo as a force rather than a displacement. - - @rtype: boolean - """ - def setIpoAdd(add): - """ - Set whether to interpret the ipo as additive rather than absolute. - - @type add: boolean - @param add: KX_TRUE or KX_FALSE - """ - def getIpoAdd(): - """ - Returns whether to interpret the ipo as additive rather than absolute. - - @rtype: boolean - """ - def setType(mode): - """ - Sets the operation mode of the actuator. - - @param mode: KX_IPOACT_PLAY, KX_IPOACT_PINGPONG, KX_IPOACT_FLIPPER, KX_IPOACT_LOOPSTOP, KX_IPOACT_LOOPEND - @type mode: string - """ - def getType(): - """ - Returns the operation mode of the actuator. - - @rtype: integer - @return: KX_IPOACT_PLAY, KX_IPOACT_PINGPONG, KX_IPOACT_FLIPPER, KX_IPOACT_LOOPSTOP, KX_IPOACT_LOOPEND - """ - def setForceIpoActsLocal(local): - """ - Set whether to apply the force in the object's local - coordinates rather than the world global coordinates. - - @param local: Apply the ipo-as-force in the object's local - coordinates? (KX_TRUE, KX_FALSE) - @type local: boolean - """ - def getForceIpoActsLocal(): - """ - Return whether to apply the force in the object's local - coordinates rather than the world global coordinates. - """ diff --git a/source/gameengine/PyDoc/KX_Light.py b/source/gameengine/PyDoc/KX_Light.py deleted file mode 100644 index ff0cf071d2d..00000000000 --- a/source/gameengine/PyDoc/KX_Light.py +++ /dev/null @@ -1,45 +0,0 @@ -# $Id$ -# Documentation for Light game objects. -from KX_GameObject import * - -class KX_Light(KX_GameObject): - """ - A Light object. - - Example: - - # Turn on a red alert light. - import GameLogic - - co = GameLogic.getCurrentController() - light = co.getOwner() - - light.energy = 1.0 - light.colour = [1.0, 0.0, 0.0] - - @group Constants: NORMAL, SPOT, SUN - @ivar SPOT: A spot light source. See attribute 'type' - @ivar SUN: A point light source with no attenuation. See attribute 'type' - @ivar NORMAL: A point light source. See attribute 'type' - - @ivar type: The type of light - must be SPOT, SUN or NORMAL - @ivar layer: The layer mask that this light affects object on. - @type layer: bitfield - @ivar energy: The brightness of this light. - @type energy: float - @ivar distance: The maximum distance this light can illuminate. (SPOT and NORMAL lights only) - @type distance: float - @ivar colour: The colour of this light. Black = [0.0, 0.0, 0.0], White = [1.0, 1.0, 1.0] - @type colour: list [r, g, b] - @ivar color: Synonym for colour. - @ivar lin_attenuation: The linear component of this light's attenuation. (SPOT and NORMAL lights only) - @type lin_attenuation: float - @ivar quad_attenuation: The quadratic component of this light's attenuation (SPOT and NORMAL lights only) - @type quad_attenuation: float - @ivar spotsize: The cone angle of the spot light, in degrees. (float) (SPOT lights only) - 0.0 <= spotsize <= 180.0. Spotsize = 360.0 is also accepted. - @ivar spotblend: Specifies the intensity distribution of the spot light. (float) (SPOT lights only) - Higher values result in a more focused light source. - 0.0 <= spotblend <= 1.0. - - """ diff --git a/source/gameengine/PyDoc/KX_MeshProxy.py b/source/gameengine/PyDoc/KX_MeshProxy.py deleted file mode 100644 index 03bc36b6ac1..00000000000 --- a/source/gameengine/PyDoc/KX_MeshProxy.py +++ /dev/null @@ -1,125 +0,0 @@ -# $Id$ -# Documentation for KX_MeshProxy - -class KX_MeshProxy: - """ - A mesh object. - - You can only change the vertex properties of a mesh object, not the mesh topology. - - To use mesh objects effectively, you should know a bit about how the game engine handles them. - 1. Mesh Objects are converted from Blender at scene load. - 2. The Converter groups polygons by Material. This means they can be sent to the - renderer efficiently. A material holds: - 1. The texture. - 2. The Blender material. - 3. The Tile properties - 4. The face properties - (From the "Texture Face" panel) - 5. Transparency & z sorting - 6. Light layer - 7. Polygon shape (triangle/quad) - 8. Game Object - 3. Verticies will be split by face if necessary. Verticies can only be shared between - faces if: - 1. They are at the same position - 2. UV coordinates are the same - 3. Their normals are the same (both polygons are "Set Smooth") - 4. They are the same colour - For example: a cube has 24 verticies: 6 faces with 4 verticies per face. - - The correct method of iterating over every L{KX_VertexProxy} in a game object:: - import GameLogic - - co = GameLogic.getcurrentController() - obj = co.getOwner() - - m_i = 0 - mesh = obj.getMesh(m_i) # There can be more than one mesh... - while mesh != None: - for mat in range(mesh.getNumMaterials()): - for v_index in range(mesh.getVertexArrayLength(mat)): - vertex = mesh.getVertex(mat, v_index) - # Do something with vertex here... - # ... eg: colour the vertex red. - vertex.colour = [1.0, 0.0, 0.0, 1.0] - m_i += 1 - mesh = obj.getMesh(m_i) - - - """ - - def getNumMaterials(): - """ - Gets the number of materials associated with this object. - - @rtype: integer - """ - - def getMaterialName(matid): - """ - Gets the name of the specified material. - - @type matid: integer - @param matid: the specified material. - @rtype: string - @return: the attached material name. - """ - def getTextureName(matid): - """ - Gets the name of the specified material's texture. - - @type matid: integer - @param matid: the specified material - @rtype: string - @return: the attached material's texture name. - """ - def getVertexArrayLength(matid): - """ - Gets the length of the vertex array associated with the specified material. - - There is one vertex array for each material. - - @type matid: integer - @param matid: the specified material - @rtype: integer - @return: the number of verticies in the vertex array. - """ - def getVertex(matid, index): - """ - Gets the specified vertex from the mesh object. - - @type matid: integer - @param matid: the specified material - @type index: integer - @param index: the index into the vertex array. - @rtype: L{KX_VertexProxy} - @return: a vertex object. - """ - def getNumPolygons(): - """ - Returns the number of polygon in the mesh. - - @rtype: integer - """ - def getPolygon(index): - """ - Gets the specified polygon from the mesh. - - @type index: integer - @param index: polygon number - @rtype: L{KX_PolyProxy} - @return: a polygon object. - """ - def reinstancePhysicsMesh(): - """ - Updates the physics system with the changed mesh. - - A mesh must have only one material with collision flags, - and have all collision primitives in one vertex array (ie. < 65535 verts) and - be either a polytope or polyheder mesh. If you don't get a warning in the - console when the collision type is polytope, the mesh is suitable for reinstance. - - @rtype: boolean - @return: True if reinstance succeeded, False if it failed. - """ - diff --git a/source/gameengine/PyDoc/KX_MouseFocusSensor.py b/source/gameengine/PyDoc/KX_MouseFocusSensor.py deleted file mode 100644 index 28d584037f8..00000000000 --- a/source/gameengine/PyDoc/KX_MouseFocusSensor.py +++ /dev/null @@ -1,26 +0,0 @@ -# $Id$ -# Documentation for KX_MouseFocusSensor -from SCA_MouseSensor import * - -class KX_MouseFocusSensor(SCA_MouseSensor): - """ - The mouse focus sensor detects when the mouse is over the current game object. - - The mouse focus sensor works by transforming the mouse coordinates from 2d device - space to 3d space then raycasting away from the camera. - """ - - def GetRayTarget(): - """ - Returns the end point of the sensor ray. - - @rtype: list [x, y, z] - @return: the end point of the sensor ray, in world coordinates. - """ - def GetRaySource(): - """ - Returns the start point of the sensor ray. - - @rtype: list [x, y, z] - @return: the start point of the sensor ray, in world coordinates. - """ diff --git a/source/gameengine/PyDoc/KX_NearSensor.py b/source/gameengine/PyDoc/KX_NearSensor.py deleted file mode 100644 index fef2e4b2acc..00000000000 --- a/source/gameengine/PyDoc/KX_NearSensor.py +++ /dev/null @@ -1,9 +0,0 @@ -# $Id$ -# Documentation for KX_NearSensor -from KX_TouchSensor import * - -class KX_NearSensor(KX_TouchSensor): - """ - A near sensor is a specialised form of touch sensor. - """ - diff --git a/source/gameengine/PyDoc/KX_NetworkMessageActuator.py b/source/gameengine/PyDoc/KX_NetworkMessageActuator.py deleted file mode 100644 index aecd2897743..00000000000 --- a/source/gameengine/PyDoc/KX_NetworkMessageActuator.py +++ /dev/null @@ -1,36 +0,0 @@ -# $Id$ -# Documentation for KX_NetworkMessageActuator -from SCA_IActuator import * - -class KX_NetworkMessageActuator(SCA_IActuator): - """ - Message Actuator - """ - def setToPropName(name): - """ - Messages will only be sent to objects with the given property name. - - @type name: string - """ - def setSubject(subject): - """ - Sets the subject field of the message. - - @type subject: string - """ - def setBodyType(bodytype): - """ - Sets the type of body to send. - - @type bodytype: boolean - @param bodytype: True to send the value of a property, False to send the body text. - """ - def setBody(body): - """ - Sets the message body. - - @type body: string - @param body: if the body type is True, this is the name of the property to send. - if the body type is False, this is the text to send. - """ - diff --git a/source/gameengine/PyDoc/KX_NetworkMessageSensor.py b/source/gameengine/PyDoc/KX_NetworkMessageSensor.py deleted file mode 100644 index 8f5f3609df7..00000000000 --- a/source/gameengine/PyDoc/KX_NetworkMessageSensor.py +++ /dev/null @@ -1,43 +0,0 @@ -# $Id$ -# Documentation for KX_NetworkMessageSensor -from SCA_ISensor import * - -class KX_NetworkMessageSensor(SCA_ISensor): - """ - The Message Sensor logic brick. - - Currently only loopback (local) networks are supported. - """ - def setSubjectFilterText(subject): - """ - Change the message subject text that this sensor is listening to. - - @type subject: string - @param subject: the new message subject to listen for. - """ - - def getFrameMessageCount(): - """ - Get the number of messages received since the last frame. - - @rtype: integer - """ - def getBodies(): - """ - Gets the list of message bodies. - - @rtype: list - """ - def getSubject(): - """ - Gets the message subject this sensor is listening for from the Subject: field. - - @rtype: string - """ - def getSubjects(): - """ - Gets the list of message subjects received. - - @rtype: list - """ -
\ No newline at end of file diff --git a/source/gameengine/PyDoc/KX_ObjectActuator.py b/source/gameengine/PyDoc/KX_ObjectActuator.py deleted file mode 100644 index b7b76473292..00000000000 --- a/source/gameengine/PyDoc/KX_ObjectActuator.py +++ /dev/null @@ -1,250 +0,0 @@ -# $Id$ -# Documentation for KX_ObjectActuator -from SCA_IActuator import * - -class KX_ObjectActuator(SCA_IActuator): - """ - The object actuator ("Motion Actuator") applies force, torque, displacement, angular displacement, - velocity, or angular velocity to an object. - Servo control allows to regulate force to achieve a certain speed target. - """ - def getForce(): - """ - Returns the force applied by the actuator. - - @rtype: list [fx, fy, fz, local] - @return: A four item list, containing the vector force, and a flag specifying whether the force is local. - """ - def setForce(fx, fy, fz, local): - """ - Sets the force applied by the actuator. - - @type fx: float - @param fx: the x component of the force. - @type fy: float - @param fy: the z component of the force. - @type fz: float - @param fz: the z component of the force. - @type local: boolean - @param local: - False: the force is applied in world coordinates. - - True: the force is applied in local coordinates. - """ - def getTorque(): - """ - Returns the torque applied by the actuator. - - @rtype: list [S{Tau}x, S{Tau}y, S{Tau}z, local] - @return: A four item list, containing the vector torque, and a flag specifying whether - the torque is applied in local coordinates (True) or world coordinates (False) - """ - def setTorque(tx, ty, tz, local): - """ - Sets the torque applied by the actuator. - - @type tx: float - @param tx: the x component of the torque. - @type ty: float - @param ty: the z component of the torque. - @type tz: float - @param tz: the z component of the torque. - @type local: boolean - @param local: - False: the torque is applied in world coordinates. - - True: the torque is applied in local coordinates. - """ - def getDLoc(): - """ - Returns the displacement vector applied by the actuator. - - @rtype: list [dx, dy, dz, local] - @return: A four item list, containing the vector displacement, and whether - the displacement is applied in local coordinates (True) or world - coordinates (False) - """ - def setDLoc(dx, dy, dz, local): - """ - Sets the displacement vector applied by the actuator. - - Since the displacement is applied every frame, you must adjust the displacement - based on the frame rate, or you game experience will depend on the player's computer - speed. - - @type dx: float - @param dx: the x component of the displacement vector. - @type dy: float - @param dy: the z component of the displacement vector. - @type dz: float - @param dz: the z component of the displacement vector. - @type local: boolean - @param local: - False: the displacement vector is applied in world coordinates. - - True: the displacement vector is applied in local coordinates. - """ - def getDRot(): - """ - Returns the angular displacement vector applied by the actuator. - - @rtype: list [dx, dy, dz, local] - @return: A four item list, containing the angular displacement vector, and whether - the displacement is applied in local coordinates (True) or world - coordinates (False) - """ - def setDRot(dx, dy, dz, local): - """ - Sets the angular displacement vector applied by the actuator. - - Since the displacement is applied every frame, you must adjust the displacement - based on the frame rate, or you game experience will depend on the player's computer - speed. - - @type dx: float - @param dx: the x component of the angular displacement vector. - @type dy: float - @param dy: the z component of the angular displacement vector. - @type dz: float - @param dz: the z component of the angular displacement vector. - @type local: boolean - @param local: - False: the angular displacement vector is applied in world coordinates. - - True: the angular displacement vector is applied in local coordinates. - """ - def getLinearVelocity(): - """ - Returns the linear velocity applied by the actuator. - For the servo control actuator, this is the target speed. - - @rtype: list [vx, vy, vz, local] - @return: A four item list, containing the vector velocity, and whether the velocity is applied in local coordinates (True) or world coordinates (False) - """ - def setLinearVelocity(vx, vy, vz, local): - """ - Sets the linear velocity applied by the actuator. - For the servo control actuator, sets the target speed. - - @type vx: float - @param vx: the x component of the velocity vector. - @type vy: float - @param vy: the z component of the velocity vector. - @type vz: float - @param vz: the z component of the velocity vector. - @type local: boolean - @param local: - False: the velocity vector is in world coordinates. - - True: the velocity vector is in local coordinates. - """ - def getAngularVelocity(): - """ - Returns the angular velocity applied by the actuator. - - @rtype: list [S{omega}x, S{omega}y, S{omega}z, local] - @return: A four item list, containing the vector velocity, and whether - the velocity is applied in local coordinates (True) or world - coordinates (False) - """ - def setAngularVelocity(wx, wy, wz, local): - """ - Sets the angular velocity applied by the actuator. - - @type wx: float - @param wx: the x component of the velocity vector. - @type wy: float - @param wy: the z component of the velocity vector. - @type wz: float - @param wz: the z component of the velocity vector. - @type local: boolean - @param local: - False: the velocity vector is applied in world coordinates. - - True: the velocity vector is applied in local coordinates. - """ - def getDamping(): - """ - Returns the damping parameter of the servo controller. - - @rtype: integer - @return: the time constant of the servo controller in frame unit. - """ - def setDamping(damp): - """ - Sets the damping parameter of the servo controller. - - @type damp: integer - @param damp: the damping parameter in frame unit. - """ - def getForceLimitX(): - """ - Returns the min/max force limit along the X axis used by the servo controller. - - @rtype: list [min, max, enabled] - @return: A three item list, containing the min and max limits of the force as float - and whether the limits are active(true) or inactive(true) - """ - def setForceLimitX(min, max, enable): - """ - Sets the min/max force limit along the X axis and activates or deactivates the limits in the servo controller. - - @type min: float - @param min: the minimum value of the force along the X axis. - @type max: float - @param max: the maximum value of the force along the X axis. - @type enable: boolean - @param enable: - True: the force will be limited to the min/max - - False: the force will not be limited - """ - def getForceLimitY(): - """ - Returns the min/max force limit along the Y axis used by the servo controller. - - @rtype: list [min, max, enabled] - @return: A three item list, containing the min and max limits of the force as float - and whether the limits are active(true) or inactive(true) - """ - def setForceLimitY(min, max, enable): - """ - Sets the min/max force limit along the Y axis and activates or deactivates the limits in the servo controller. - - @type min: float - @param min: the minimum value of the force along the Y axis. - @type max: float - @param max: the maximum value of the force along the Y axis. - @type enable: boolean - @param enable: - True: the force will be limited to the min/max - - False: the force will not be limited - """ - def getForceLimitZ(): - """ - Returns the min/max force limit along the Z axis used by the servo controller. - - @rtype: list [min, max, enabled] - @return: A three item list, containing the min and max limits of the force as float - and whether the limits are active(true) or inactive(true) - """ - def setForceLimitZ(min, max, enable): - """ - Sets the min/max force limit along the Z axis and activates or deactivates the limits in the servo controller. - - @type min: float - @param min: the minimum value of the force along the Z axis. - @type max: float - @param max: the maximum value of the force along the Z axis. - @type enable: boolean - @param enable: - True: the force will be limited to the min/max - - False: the force will not be limited - """ - def getPID(): - """ - Returns the PID coefficient of the servo controller. - - @rtype: list [P, I, D] - @return: A three item list, containing the PID coefficient as floats: - P : proportional coefficient - I : Integral coefficient - D : Derivate coefficient - """ - def setPID(P, I, D): - """ - Sets the PID coefficients of the servo controller. - - @type P: flat - @param P: proportional coefficient - @type I: float - @param I: Integral coefficient - @type D: float - @param D: Derivate coefficient - """ - - diff --git a/source/gameengine/PyDoc/KX_ParentActuator.py b/source/gameengine/PyDoc/KX_ParentActuator.py deleted file mode 100644 index 6d6e0937257..00000000000 --- a/source/gameengine/PyDoc/KX_ParentActuator.py +++ /dev/null @@ -1,23 +0,0 @@ -# $Id: KX_ParentActuator.py 2615 2004-06-02 12:43:27Z kester $ -# Documentation for KX_ParentActuator -from SCA_IActuator import * - -class KX_ParentActuator(SCA_IActuator): - """ - The parent actuator can set or remove an objects parent object. - """ - def setObject(object): - """ - Sets the object to set as parent. - - Object can be either a L{KX_GameObject} or the name of the object. - - @type object: L{KX_GameObject}, string or None - """ - def getObject(name_only = 1): - """ - Returns the name of the object to change to. - @type name_only: bool - @param name_only: optional argument, when 0 return a KX_GameObject - @rtype: string, KX_GameObject or None if no object is set - """ diff --git a/source/gameengine/PyDoc/KX_PolyProxy.py b/source/gameengine/PyDoc/KX_PolyProxy.py deleted file mode 100644 index bcd42c2ac2e..00000000000 --- a/source/gameengine/PyDoc/KX_PolyProxy.py +++ /dev/null @@ -1,100 +0,0 @@ -# $Id$ -# Documentation for the polygon proxy class - -class KX_PolyProxy: - """ - A polygon holds the index of the vertex forming the poylgon. - - Note: - The polygon attributes are read-only, you need to retrieve the vertex proxy if you want - to change the vertex settings. - - @ivar matname: The name of polygon material, empty if no material. - @type matname: string - @ivar material: The material of the polygon - @type material: L{KX_PolygonMaterial} or KX_BlenderMaterial - @ivar texture: The texture name of the polygon. - @type texture: string - @ivar matid: The material index of the polygon, use this to retrieve vertex proxy from mesh proxy - @type matid: integer - @ivar v1: vertex index of the first vertex of the polygon, use this to retrieve vertex proxy from mesh proxy - @type v1: integer - @ivar v2: vertex index of the second vertex of the polygon, use this to retrieve vertex proxy from mesh proxy - @type v2: integer - @ivar v3: vertex index of the third vertex of the polygon, use this to retrieve vertex proxy from mesh proxy - @type v3: integer - @ivar v4: vertex index of the fourth vertex of the polygon, 0 if polygon has only 3 vertex - use this to retrieve vertex proxy from mesh proxy - @type v4: integer - @ivar visible: visible state of the polygon: 1=visible, 0=invisible - @type visible: integer - @ivar collide: collide state of the polygon: 1=receives collision, 0=collision free. - @type collide: integer - """ - - def getMaterialName(): - """ - Returns the polygon material name with MA prefix - - @rtype: string - @return: material name - """ - def getMaterial(): - """ - Returns the polygon material - - @rtype: L{KX_PolygonMaterial} or KX_BlenderMaterial - """ - def getTextureName(): - """ - Returns the polygon texture name - - @rtype: string - @return: texture name - """ - def getMaterialIndex(): - """ - Returns the material bucket index of the polygon. - This index and the ones returned by getVertexIndex() are needed to retrieve the vertex proxy from L{KX_MeshProxy}. - - @rtype: integer - @return: the material index in the mesh - """ - def getNumVertex(): - """ - Returns the number of vertex of the polygon. - - @rtype: integer - @return: number of vertex, 3 or 4. - """ - def isVisible(): - """ - Returns whether the polygon is visible or not - - @rtype: integer - @return: 0=invisible, 1=visible - """ - def isCollider(): - """ - Returns whether the polygon is receives collision or not - - @rtype: integer - @return: 0=collision free, 1=receives collision - """ - def getVertexIndex(vertex): - """ - Returns the mesh vertex index of a polygon vertex - This index and the one returned by getMaterialIndex() are needed to retrieve the vertex proxy from L{KX_MeshProxy}. - - @type vertex: integer - @param vertex: index of the vertex in the polygon: 0->3 - @rtype: integer - @return: mesh vertex index - """ - def getMesh(): - """ - Returns a mesh proxy - - @rtype: L{KX_MeshProxy} - @return: mesh proxy - """ diff --git a/source/gameengine/PyDoc/KX_PolygonMaterial.py b/source/gameengine/PyDoc/KX_PolygonMaterial.py deleted file mode 100644 index cfc4257f95d..00000000000 --- a/source/gameengine/PyDoc/KX_PolygonMaterial.py +++ /dev/null @@ -1,281 +0,0 @@ -# $Id$ - -class KX_PolygonMaterial: - """ - This is the interface to materials in the game engine. - - Materials define the render state to be applied to mesh objects. - - Warning: Some of the methods/variables are CObjects. If you mix these up, - you will crash blender. - - This example requires: - - PyOpenGL http://pyopengl.sourceforge.net/ - - GLEWPy http://glewpy.sourceforge.net/ - Example:: - - import GameLogic - import OpenGL - from OpenGL.GL import * - from OpenGL.GLU import * - import glew - from glew import * - - glewInit() - - vertex_shader = \"\"\" - - void main(void) - { - gl_Position = ftransform(); - } - \"\"\" - - fragment_shader =\"\"\" - - void main(void) - { - gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); - } - \"\"\" - - class MyMaterial: - def __init__(self): - self.pass_no = 0 - # Create a shader - self.m_program = glCreateProgramObjectARB() - # Compile the vertex shader - self.shader(GL_VERTEX_SHADER_ARB, (vertex_shader)) - # Compile the fragment shader - self.shader(GL_FRAGMENT_SHADER_ARB, (fragment_shader)) - # Link the shaders together - self.link() - - def PrintInfoLog(self, tag, object): - \"\"\" - PrintInfoLog prints the GLSL compiler log - \"\"\" - print "Tag: def PrintGLError(self, tag = ""): - - def PrintGLError(self, tag = ""): - \"\"\" - Prints the current GL error status - \"\"\" - if len(tag): - print tag - err = glGetError() - if err != GL_NO_ERROR: - print "GL Error: %s\\n"%(gluErrorString(err)) - - def shader(self, type, shaders): - \"\"\" - shader compiles a GLSL shader and attaches it to the current - program. - - type should be either GL_VERTEX_SHADER_ARB or GL_FRAGMENT_SHADER_ARB - shaders should be a sequence of shader source to compile. - \"\"\" - # Create a shader object - shader_object = glCreateShaderObjectARB(type) - - # Add the source code - glShaderSourceARB(shader_object, len(shaders), shaders) - - # Compile the shader - glCompileShaderARB(shader_object) - - # Print the compiler log - self.PrintInfoLog("vertex shader", shader_object) - - # Check if compiled, and attach if it did - compiled = glGetObjectParameterivARB(shader_object, GL_OBJECT_COMPILE_STATUS_ARB) - if compiled: - glAttachObjectARB(self.m_program, shader_object) - - # Delete the object (glAttachObjectARB makes a copy) - glDeleteObjectARB(shader_object) - - # print the gl error log - self.PrintGLError() - - def link(self): - \"\"\" - Links the shaders together. - \"\"\" - # clear error indicator - glGetError() - - glLinkProgramARB(self.m_program) - - self.PrintInfoLog("link", self.m_program) - - linked = glGetObjectParameterivARB(self.m_program, GL_OBJECT_LINK_STATUS_ARB) - if not linked: - print "Shader failed to link" - return - - glValidateProgramARB(self.m_program) - valid = glGetObjectParameterivARB(self.m_program, GL_OBJECT_VALIDATE_STATUS_ARB) - if not valid: - print "Shader failed to validate" - return - - def activate(self, rasty, cachingInfo, mat): - self.pass_no+=1 - if (self.pass_no == 1): - glDisable(GL_COLOR_MATERIAL) - glUseProgramObjectARB(self.m_program) - return True - - glEnable(GL_COLOR_MATERIAL) - glUseProgramObjectARB(0) - self.pass_no = 0 - return False - - obj = GameLogic.getCurrentController().getOwner() - - mesh = obj.getMesh(0) - - for mat in mesh.materials: - mat.setCustomMaterial(MyMaterial()) - print mat.texture - - @ivar texture: Texture name - @type texture: string (read only) - - @ivar gl_texture: OpenGL texture handle (eg for glBindTexture(GL_TEXTURE_2D, gl_texture) - @type gl_texture: integer (read only) - - @ivar material: Material name - @type material: string (read only) - - @ivar tface: Texture face properties - @type tface: CObject (read only) - - @ivar tile: Texture is tiling - @type tile: boolean - @ivar tilexrep: Number of tile repetitions in x direction. - @type tilexrep: integer - @ivar tileyrep: Number of tile repetitions in y direction. - @type tileyrep: integer - - @ivar drawingmode: Drawing mode for the material. - - 2 (drawingmode & 4) Textured - - 4 (drawingmode & 16) Light - - 14 (drawingmode & 16384) 3d Polygon Text - @type drawingmode: bitfield - - @ivar transparent: This material is transparent. All meshes with this - material will be rendered after non transparent meshes from back - to front. - @type transparent: boolean - - @ivar zsort: Transparent polygons in meshes with this material will be sorted back to - front before rendering. - Non-Transparent polygons will be sorted front to back before rendering. - @type zsort: boolean - - @ivar lightlayer: Light layers this material affects. - @type lightlayer: bitfield. - - @ivar triangle: Mesh data with this material is triangles. It's probably not safe to change this. - @type triangle: boolean - - @ivar diffuse: The diffuse colour of the material. black = [0.0, 0.0, 0.0] white = [1.0, 1.0, 1.0] - @type diffuse: list [r, g, b] - @ivar specular: The specular colour of the material. black = [0.0, 0.0, 0.0] white = [1.0, 1.0, 1.0] - @type specular: list [r, g, b] - @ivar shininess: The shininess (specular exponent) of the material. 0.0 <= shininess <= 128.0 - @type shininess: float - @ivar specularity: The amount of specular of the material. 0.0 <= specularity <= 1.0 - @type specularity: float - """ - def updateTexture(tface, rasty): - """ - Updates a realtime animation. - - @param tface: Texture face (eg mat.tface) - @type tface: CObject - @param rasty: Rasterizer - @type rasty: CObject - """ - def setTexture(tface): - """ - Sets texture render state. - - Example:: - mat.setTexture(mat.tface) - - @param tface: Texture face - @type tface: CObject - """ - def activate(rasty, cachingInfo): - """ - Sets material parameters for this object for rendering. - - Material Parameters set: - 1. Texture - 2. Backface culling - 3. Line drawing - 4. Specular Colour - 5. Shininess - 6. Diffuse Colour - 7. Polygon Offset. - - @param rasty: Rasterizer instance. - @type rasty: CObject - @param cachingInfo: Material cache instance. - @type cachingInfo: CObject - """ - def setCustomMaterial(material): - """ - Sets the material state setup object. - - Using this method, you can extend or completely replace the gameengine material - to do your own advanced multipass effects. - - Use this method to register your material class. Instead of the normal material, - your class's activate method will be called just before rendering the mesh. - This should setup the texture, material, and any other state you would like. - It should return True to render the mesh, or False if you are finished. You should - clean up any state Blender does not set before returning False. - - Activate Method Definition:: - def activate(self, rasty, cachingInfo, material): - - Example:: - class PyMaterial: - def __init__(self): - self.pass_no = -1 - - def activate(self, rasty, cachingInfo, material): - # Activate the material here. - # - # The activate method will be called until it returns False. - # Every time the activate method returns True the mesh will - # be rendered. - # - # rasty is a CObject for passing to material.updateTexture() - # and material.activate() - # cachingInfo is a CObject for passing to material.activate() - # material is the KX_PolygonMaterial instance this material - # was added to - - # default material properties: - self.pass_no += 1 - if self.pass_no == 0: - material.activate(rasty, cachingInfo) - # Return True to do this pass - return True - - # clean up and return False to finish. - self.pass_no = -1 - return False - - # Create a new Python Material and pass it to the renderer. - mat.setCustomMaterial(PyMaterial()) - - @param material: The material object. - @type material: instance - """ - diff --git a/source/gameengine/PyDoc/KX_RadarSensor.py b/source/gameengine/PyDoc/KX_RadarSensor.py deleted file mode 100644 index 64be858371a..00000000000 --- a/source/gameengine/PyDoc/KX_RadarSensor.py +++ /dev/null @@ -1,31 +0,0 @@ -# $Id$ -# Documentation for KX_RadarSensor -from KX_NearSensor import * - -class KX_RadarSensor(KX_NearSensor): - """ - Radar sensor is a near sensor with a conical sensor object. - """ - - def getConeOrigin(): - """ - Returns the origin of the cone with which to test. The origin - is in the middle of the cone. - - @rtype: list [x, y, z] - """ - - def getConeTarget(): - """ - Returns the center of the bottom face of the cone with which to test. - - @rtype: list [x, y, z] - """ - - def getConeHeight(): - """ - Returns the height of the cone with which to test. - - @rtype: float - """ - diff --git a/source/gameengine/PyDoc/KX_RaySensor.py b/source/gameengine/PyDoc/KX_RaySensor.py deleted file mode 100644 index e487edcb655..00000000000 --- a/source/gameengine/PyDoc/KX_RaySensor.py +++ /dev/null @@ -1,33 +0,0 @@ -# $Id$ -# Documentation for KX_RaySensor -from SCA_ISensor import * - -class KX_RaySensor(SCA_ISensor): - """ - A ray sensor detects the first object in a given direction. - """ - - def getHitObject(): - """ - Returns the game object that was hit by this ray. - - @rtype: KX_GameObject - """ - def getHitPosition(): - """ - Returns the position (in worldcoordinates) where the object was hit by this ray. - - @rtype: list [x, y, z] - """ - def getHitNormal(): - """ - Returns the normal (in worldcoordinates) of the object at the location where the object was hit by this ray. - - @rtype: list [nx, ny, nz] - """ - def getRayDirection(): - """ - Returns the direction from the ray (in worldcoordinates) - - @rtype: list [dx, dy, dz] - """ diff --git a/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py b/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py deleted file mode 100644 index c3b2e947ddb..00000000000 --- a/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py +++ /dev/null @@ -1,92 +0,0 @@ -# $Id$ -# Documentation for KX_SCA_AddObjectActuator -from SCA_IActuator import * - -class KX_SCA_AddObjectActuator(SCA_IActuator): - """ - Edit Object Actuator (in Add Object Mode) - - @warning: An Add Object actuator will be ignored if at game start, the linked object doesn't exist - (or is empty) or the linked object is in an active layer. - - This will genereate a warning in the console: - - C{ERROR: GameObject I{OBName} has a AddObjectActuator I{ActuatorName} without object (in 'nonactive' layer)} - """ - def setObject(object): - """ - Sets the game object to add. - - A copy of the object will be added to the scene when the actuator is activated. - - If the object does not exist, this function is ignored. - - object can either be a L{KX_GameObject} or the name of an object or None. - - @type object: L{KX_GameObject}, string or None - """ - def getObject(name_only = 0): - """ - Returns the name of the game object to be added. - - Returns None if no game object has been assigned to be added. - @type name_only: bool - @param name_only: optional argument, when 0 return a KX_GameObject - @rtype: string, KX_GameObject or None if no object is set - """ - def setTime(time): - """ - Sets the lifetime of added objects, in frames. - - If time == 0, the object will last forever. - - @type time: integer - @param time: The minimum value for time is 0. - """ - def getTime(): - """ - Returns the lifetime of the added object, in frames. - - @rtype: integer - """ - def setLinearVelocity(vx, vy, vz): - """ - Sets the initial linear velocity of added objects. - - @type vx: float - @param vx: the x component of the initial linear velocity. - @type vy: float - @param vy: the y component of the initial linear velocity. - @type vz: float - @param vz: the z component of the initial linear velocity. - """ - def getLinearVelocity(): - """ - Returns the initial linear velocity of added objects. - - @rtype: list [vx, vy, vz] - """ - def setAngularVelocity(vx, vy, vz): - """ - Sets the initial angular velocity of added objects. - - @type vx: float - @param vx: the x component of the initial angular velocity. - @type vy: float - @param vy: the y component of the initial angular velocity. - @type vz: float - @param vz: the z component of the initial angular velocity. - """ - def getAngularVelocity(): - """ - Returns the initial angular velocity of added objects. - - @rtype: list [vx, vy, vz] - """ - def getLastCreatedObject(): - """ - Returns the last object created by this actuator. - - @rtype: L{KX_GameObject} - @return: A L{KX_GameObject} or None if no object has been created. - """ diff --git a/source/gameengine/PyDoc/KX_SCA_EndObjectActuator.py b/source/gameengine/PyDoc/KX_SCA_EndObjectActuator.py deleted file mode 100644 index 8a7c79bb52b..00000000000 --- a/source/gameengine/PyDoc/KX_SCA_EndObjectActuator.py +++ /dev/null @@ -1,11 +0,0 @@ -# $Id$ -# Documentation for KX_SCA_EndObjectActuator -from SCA_IActuator import * - -class KX_SCA_EndObjectActuator(SCA_IActuator): - """ - Edit Object Actuator (in End Object mode) - - This actuator has no python methods. - """ - diff --git a/source/gameengine/PyDoc/KX_SCA_ReplaceMeshActuator.py b/source/gameengine/PyDoc/KX_SCA_ReplaceMeshActuator.py deleted file mode 100644 index 498f6072e23..00000000000 --- a/source/gameengine/PyDoc/KX_SCA_ReplaceMeshActuator.py +++ /dev/null @@ -1,74 +0,0 @@ -# $Id$ -# Documentation for KX_SCA_ReplaceMeshActuator -from SCA_IActuator import * - -class KX_SCA_ReplaceMeshActuator(SCA_IActuator): - """ - Edit Object actuator, in Replace Mesh mode. - - Example:: - # Level-of-detail - # Switch a game object's mesh based on its depth in the camera view. - # +----------+ +-----------+ +-------------------------------------+ - # | Always +-----+ Python +-----+ Edit Object (Replace Mesh) LOD.Mesh | - # +----------+ +-----------+ +-------------------------------------+ - import GameLogic - - # List detail meshes here - # Mesh (name, near, far) - # Meshes overlap so that they don't 'pop' when on the edge of the distance. - meshes = ((".Hi", 0.0, -20.0), - (".Med", -15.0, -50.0), - (".Lo", -40.0, -100.0) - ) - - co = GameLogic.getCurrentController() - obj = co.getOwner() - act = co.getActuator("LOD." + obj.getName()) - cam = GameLogic.getCurrentScene().active_camera - - def Depth(pos, plane): - return pos[0]*plane[0] + pos[1]*plane[1] + pos[2]*plane[2] + plane[3] - - # Depth is negative and decreasing further from the camera - depth = Depth(obj.position, cam.world_to_camera[2]) - - newmesh = None - curmesh = None - # Find the lowest detail mesh for depth - for mesh in meshes: - if depth < mesh[1] and depth > mesh[2]: - newmesh = mesh - if "ME" + obj.getName() + mesh[0] == act.getMesh(): - curmesh = mesh - - if newmesh != None and "ME" + obj.getName() + newmesh[0] != act.getMesh(): - # The mesh is a different mesh - switch it. - # Check the current mesh is not a better fit. - if curmesh == None or curmesh[1] < depth or curmesh[2] > depth: - act.setMesh(obj.getName() + newmesh[0]) - GameLogic.addActiveActuator(act, True) - - @warning: Replace mesh actuators will be ignored if at game start, the - named mesh doesn't exist. - - This will generate a warning in the console: - - C{ERROR: GameObject I{OBName} ReplaceMeshActuator I{ActuatorName} without object} - """ - def setMesh(name): - """ - Sets the name of the mesh that will replace the current one. - When the name is None it will unset the mesh value so no action is taken. - - @type name: string or None - """ - def getMesh(): - """ - Returns the name of the mesh that will replace the current one. - - Returns None if no mesh has been scheduled to be added. - - @rtype: string or None - """ - diff --git a/source/gameengine/PyDoc/KX_Scene.py b/source/gameengine/PyDoc/KX_Scene.py deleted file mode 100644 index 4a0a7a9556d..00000000000 --- a/source/gameengine/PyDoc/KX_Scene.py +++ /dev/null @@ -1,70 +0,0 @@ -# $Id$ -# Documentation for KX_Scene.py - -class KX_Scene: - """ - Scene. - - The activity culling stuff is supposed to disable logic bricks when their owner gets too far - from the active camera. It was taken from some code lurking at the back of KX_Scene - who knows - what it does! - - Example:: - import GameLogic - - # get the scene - scene = GameLogic.getCurrentScene() - - # print all the objects in the scene - for obj in scene.getObjectList(): - print obj.getName() - - # get an object named 'Cube' - obj = scene.getObjectList()["OBCube"] - - # get the first object in the scene. - obj = scene.getObjectList()[0] - - Example:: - # Get the depth of an object in the camera view. - import GameLogic - - obj = GameLogic.getCurrentController().getOwner() - cam = GameLogic.getCurrentScene().active_camera - - # Depth is negative and decreasing further from the camera - depth = obj.position[0]*cam.world_to_camera[2][0] + obj.position[1]*cam.world_to_camera[2][1] + obj.position[2]*cam.world_to_camera[2][2] + cam.world_to_camera[2][3] - - @bug: All attributes are read only at the moment. - - @ivar name: The scene's name - @type name: string - @ivar active_camera: The current active camera - @type active_camera: L{KX_Camera} - @ivar suspended: True if the scene is suspended. - @type suspended: boolean - @ivar activity_culling: True if the scene is activity culling - @type activity_culling: boolean - @ivar activity_culling_radius: The distance outside which to do activity culling. Measured in manhattan distance. - @type activity_culling_radius: float - """ - - def getLightList(): - """ - Returns the list of lights in the scene. - - @rtype: list [L{KX_Light}] - """ - def getObjectList(): - """ - Returns the list of objects in the scene. - - @rtype: list [L{KX_GameObject}] - """ - def getName(): - """ - Returns the name of the scene. - - @rtype: string - """ - diff --git a/source/gameengine/PyDoc/KX_SceneActuator.py b/source/gameengine/PyDoc/KX_SceneActuator.py deleted file mode 100644 index cfb40ae072f..00000000000 --- a/source/gameengine/PyDoc/KX_SceneActuator.py +++ /dev/null @@ -1,55 +0,0 @@ -# $Id$ -# Documentation for KX_SceneActuator -from SCA_IActuator import * - -class KX_SceneActuator(SCA_IActuator): - """ - Scene Actuator logic brick. - - @warning: Scene actuators that use a scene name will be ignored if at game start, the - named scene doesn't exist or is empty - - This will generate a warning in the console: - - C{ERROR: GameObject I{OBName} has a SceneActuator I{ActuatorName} (SetScene) without scene} - """ - def setUseRestart(flag): - """ - Set flag to True to restart the scene. - - @type flag: boolean - """ - def setScene(scene): - """ - Sets the name of the scene to change to/overlay/underlay/remove/suspend/resume. - - @type scene: string - """ - def setCamera(camera): - """ - Sets the camera to change to. - - Camera can be either a L{KX_Camera} or the name of the camera. - - @type camera: L{KX_Camera} or string - """ - def getUseRestart(): - """ - Returns True if the scene will be restarted. - - @rtype: boolean - """ - def getScene(): - """ - Returns the name of the scene to change to/overlay/underlay/remove/suspend/resume. - - Returns an empty string ("") if no scene has been set. - - @rtype: string - """ - def getCamera(): - """ - Returns the name of the camera to change to. - - @rtype: string - """ diff --git a/source/gameengine/PyDoc/KX_SoundActuator.py b/source/gameengine/PyDoc/KX_SoundActuator.py deleted file mode 100644 index 072af5b816c..00000000000 --- a/source/gameengine/PyDoc/KX_SoundActuator.py +++ /dev/null @@ -1,145 +0,0 @@ -# $Id$ -# Documentation for KX_SoundActuator -from SCA_IActuator import * - -class KX_SoundActuator(SCA_IActuator): - """ - Sound Actuator. - - The L{startSound()}, L{pauseSound()} and L{stopSound()} do not require - the actuator to be activated - they act instantly. - - @group Play Methods: startSound, pauseSound, stopSound - """ - def setFilename(filename): - """ - Sets the filename of the sound this actuator plays. - - @type filename: string - """ - def getFilename(): - """ - Returns the filename of the sound this actuator plays. - - @rtype: string - """ - def startSound(): - """ - Starts the sound. - """ - def pauseSound(): - """ - Pauses the sound. - """ - def stopSound(): - """ - Stops the sound. - """ - def setGain(gain): - """ - Sets the gain (volume) of the sound - - @type gain: float - @param gain: 0.0 (quiet) <= gain <= 1.0 (loud) - """ - def getGain(): - """ - Gets the gain (volume) of the sound. - - @rtype: float - """ - def setPitch(pitch): - """ - Sets the pitch of the sound. - - @type pitch: float - """ - def getPitch(): - """ - Returns the pitch of the sound. - - @rtype: float - """ - def setRollOffFactor(rolloff): - """ - Sets the rolloff factor for the sounds. - - Rolloff defines the rate of attenuation as the sound gets further away. - Higher rolloff factors shorten the distance at which the sound can be heard. - - @type rolloff: float - """ - def getRollOffFactor(): - """ - Returns the rolloff factor for the sound. - - @rtype: float - """ - def setLooping(loop): - """ - Sets the loop mode of the actuator. - - @bug: There are no constants defined for this method! - @param loop: - Play Stop 1 - - Play End 2 - - Loop Stop 3 - - Loop End 4 - - Bidirection Stop 5 - - Bidirection End 6 - @type loop: integer - """ - def getLooping(): - """ - Returns the current loop mode of the actuator. - - @rtype: integer - """ - def setPosition(x, y, z): - """ - Sets the position this sound will come from. - - @type x: float - @param x: The x coordinate of the sound. - @type y: float - @param y: The y coordinate of the sound. - @type z: float - @param z: The z coordinate of the sound. - """ - def setVelocity(vx, vy, vz): - """ - Sets the velocity this sound is moving at. - - The sound's pitch is determined from the velocity. - - @type vx: float - @param vx: The vx coordinate of the sound. - @type vy: float - @param vy: The vy coordinate of the sound. - @type vz: float - @param vz: The vz coordinate of the sound. - """ - def setOrientation(o11, o12, o13, o21, o22, o23, o31, o32, o33): - """ - Sets the orientation of the sound. - - The nine parameters specify a rotation matrix:: - | o11, o12, o13 | - | o21, o22, o23 | - | o31, o32, o33 | - """ - - def setType(mode): - """ - Sets the operation mode of the actuator. - - @param mode: KX_SOUNDACT_PLAYSTOP, KX_SOUNDACT_PLAYEND, KX_SOUNDACT_LOOPSTOP, KX_SOUNDACT_LOOPEND, KX_SOUNDACT_LOOPBIDIRECTIONAL, KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP - @type mode: integer - """ - - def getType(): - """ - Returns the operation mode of the actuator. - - @rtype: integer - @return: KX_SOUNDACT_PLAYSTOP, KX_SOUNDACT_PLAYEND, KX_SOUNDACT_LOOPSTOP, KX_SOUNDACT_LOOPEND, KX_SOUNDACT_LOOPBIDIRECTIONAL, KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP - """ diff --git a/source/gameengine/PyDoc/KX_StateActuator.py b/source/gameengine/PyDoc/KX_StateActuator.py deleted file mode 100644 index fb6ae5a3621..00000000000 --- a/source/gameengine/PyDoc/KX_StateActuator.py +++ /dev/null @@ -1,26 +0,0 @@ -# $Id$ -# Documentation for KX_StateActuator -from SCA_IActuator import * - -class KX_StateActuator(SCA_IActuator): - """ - State actuator changes the state mask of parent object. - """ - def setOperation(op): - """ - Set the type of bit operation to be applied on object state mask. - Use setMask() to specify the bits that will be modified. - - @param op: bit operation (0=Copy, 1=Add, 2=Substract, 3=Invert) - @type op: integer - """ - def setMask(mask): - """ - Set the value that defines the bits that will be modified by the operation. - The bits that are 1 in the value will be updated in the object state, - the bits that are 0 are will be left unmodified expect for the Copy operation - which copies the value to the object state. - - @param mask: bits that will be modified - @type mask: integer - """ diff --git a/source/gameengine/PyDoc/KX_TouchSensor.py b/source/gameengine/PyDoc/KX_TouchSensor.py deleted file mode 100644 index f2cc101af10..00000000000 --- a/source/gameengine/PyDoc/KX_TouchSensor.py +++ /dev/null @@ -1,50 +0,0 @@ -# $Id$ -# Documentation for KX_TouchSensor -from SCA_ISensor import * - -class KX_TouchSensor(SCA_ISensor): - """ - Touch sensor detects collisions between objects. - """ - def setProperty(name): - """ - Set the property or material to collide with. Use - setTouchMaterial() to switch between properties and - materials. - @type name: string - """ - def getProperty(): - """ - Returns the property or material to collide with. Use - getTouchMaterial() to find out whether this sensor - looks for properties or materials. - - @rtype: string - """ - - def getHitObject(): - """ - Returns the last object hit by this touch sensor. - - @rtype: L{KX_GameObject} - """ - def getHitObjectList(): - """ - Returns a list of all objects hit in the last frame. - - Only objects that have the requisite material/property are listed. - - @rtype: list [L{KX_GameObject}] - """ - def getTouchMaterial(): - """ - Returns KX_TRUE if this sensor looks for a specific material, - KX_FALSE if it looks for a specific property. - """ - def setTouchMaterial(flag): - """ - Set flag to KX_TRUE to switch on positive pulse mode, - KX_FALSE to switch off positive pulse mode. - - @type flag: KX_TRUE or KX_FALSE. - """ diff --git a/source/gameengine/PyDoc/KX_TrackToActuator.py b/source/gameengine/PyDoc/KX_TrackToActuator.py deleted file mode 100644 index 948302991b7..00000000000 --- a/source/gameengine/PyDoc/KX_TrackToActuator.py +++ /dev/null @@ -1,57 +0,0 @@ -# $Id$ -# Documentation for KX_TrackToActuator -from SCA_IActuator import * - -class KX_TrackToActuator(SCA_IActuator): - """ - Edit Object actuator in Track To mode. - - @warning: Track To Actuators will be ignored if at game start, the - object to track to is invalid. - - This will generate a warning in the console: - - C{ERROR: GameObject I{OBName} no object in EditObjectActuator I{ActuatorName}} - - """ - def setObject(object): - """ - Sets the object to track. - - @type object: L{KX_GameObject}, string or None - @param object: Either a reference to a game object or the name of the object to track. - """ - def getObject(name_only): - """ - Returns the name of the object to track. - - @type name_only: bool - @param name_only: optional argument, when 0 return a KX_GameObject - @rtype: string, KX_GameObject or None if no object is set - """ - def setTime(time): - """ - Sets the time in frames with which to delay the tracking motion. - - @type time: integer - """ - def getTime(): - """ - Returns the time in frames with which the tracking motion is delayed. - - @rtype: integer - """ - def setUse3D(use3d): - """ - Sets the tracking motion to use 3D. - - @type use3d: boolean - @param use3d: - True: allow the tracking motion to extend in the z-direction. - - False: lock the tracking motion to the x-y plane. - """ - def getUse3D(): - """ - Returns True if the tracking motion will track in the z direction. - - @rtype: boolean - """ diff --git a/source/gameengine/PyDoc/KX_VertexProxy.py b/source/gameengine/PyDoc/KX_VertexProxy.py deleted file mode 100644 index 8dc2752c037..00000000000 --- a/source/gameengine/PyDoc/KX_VertexProxy.py +++ /dev/null @@ -1,122 +0,0 @@ -# $Id$ -# Documentation for the vertex proxy class - -class KX_VertexProxy: - """ - A vertex holds position, UV, colour and normal information. - - Note: - The physics simulation is NOT currently updated - physics will not respond - to changes in the vertex position. - - @ivar XYZ: The position of the vertex. - @type XYZ: list [x, y, z] - @ivar UV: The texture coordinates of the vertex. - @type UV: list [u, v] - @ivar normal: The normal of the vertex - @type normal: list [nx, ny, nz] - @ivar colour: The colour of the vertex. - Black = [0.0, 0.0, 0.0, 1.0], White = [1.0, 1.0, 1.0, 1.0] - @type colour: list [r, g, b, a] - @ivar color: Synonym for colour. - - @group Position: x, y, z - @ivar x: The x coordinate of the vertex. - @type x: float - @ivar y: The y coordinate of the vertex. - @type y: float - @ivar z: The z coordinate of the vertex. - @type z: float - - @group Texture Coordinates: u, v - @ivar u: The u texture coordinate of the vertex. - @type u: float - @ivar v: The v texture coordinate of the vertex. - @type v: float - - @group Colour: r, g, b, a - @ivar r: The red component of the vertex colour. 0.0 <= r <= 1.0 - @type r: float - @ivar g: The green component of the vertex colour. 0.0 <= g <= 1.0 - @type g: float - @ivar b: The blue component of the vertex colour. 0.0 <= b <= 1.0 - @type b: float - @ivar a: The alpha component of the vertex colour. 0.0 <= a <= 1.0 - @type a: float - """ - - def getXYZ(): - """ - Gets the position of this vertex. - - @rtype: list [x, y, z] - @return: this vertexes position in local coordinates. - """ - def setXYZ(pos): - """ - Sets the position of this vertex. - - @type pos: list [x, y, z] - @param pos: the new position for this vertex in local coordinates. - """ - def getUV(): - """ - Gets the UV (texture) coordinates of this vertex. - - @rtype: list [u, v] - @return: this vertexes UV (texture) coordinates. - """ - def setUV(uv): - """ - Sets the UV (texture) coordinates of this vertex. - - @type uv: list [u, v] - """ - def getRGBA(): - """ - Gets the colour of this vertex. - - The colour is represented as four bytes packed into an integer value. The colour is - packed as RGBA. - - Since Python offers no way to get each byte without shifting, you must use the struct module to - access colour in an machine independent way. - - Because of this, it is suggested you use the r, g, b and a attributes or the colour attribute instead. - - Example:: - import struct; - col = struct.unpack('4B', struct.pack('I', v.getRGBA())) - # col = (r, g, b, a) - # black = ( 0, 0, 0, 255) - # white = (255, 255, 255, 255) - - @rtype: integer - @return: packed colour. 4 byte integer with one byte per colour channel in RGBA format. - """ - def setRGBA(col): - """ - Sets the colour of this vertex. - - See getRGBA() for the format of col, and its relevant problems. Use the r, g, b and a attributes - or the colour attribute instead. - - setRGBA() also accepts a four component list as argument col. The list represents the colour as [r, g, b, a] - with black = [0.0, 0.0, 0.0, 1.0] and white = [1.0, 1.0, 1.0, 1.0] - - Example:: - v.setRGBA(0xff0000ff) # Red - v.setRGBA(0xff00ff00) # Green on little endian, transparent purple on big endian - v.setRGBA([1.0, 0.0, 0.0, 1.0]) # Red - v.setRGBA([0.0, 1.0, 0.0, 1.0]) # Green on all platforms. - - @type col: integer or list [r, g, b, a] - @param col: the new colour of this vertex in packed RGBA format. - """ - def getNormal(): - """ - Gets the normal vector of this vertex. - - @rtype: list [nx, ny, nz] - @return: normalised normal vector. - """ diff --git a/source/gameengine/PyDoc/KX_VisibilityActuator.py b/source/gameengine/PyDoc/KX_VisibilityActuator.py deleted file mode 100644 index 22499f25d81..00000000000 --- a/source/gameengine/PyDoc/KX_VisibilityActuator.py +++ /dev/null @@ -1,17 +0,0 @@ -# $Id$ -# Documentation for KX_VisibilityActuator -from SCA_IActuator import * - -class KX_VisibilityActuator(SCA_IActuator): - """ - Visibility Actuator. - """ - def set(visible): - """ - Sets whether the actuator makes its parent object visible or invisible. - - @param visible: - True: Makes its parent visible. - - False: Makes its parent invisible. - """ - -
\ No newline at end of file diff --git a/source/gameengine/PyDoc/Rasterizer.py b/source/gameengine/PyDoc/Rasterizer.py index 6a67cdcc71b..bafcfece473 100644 --- a/source/gameengine/PyDoc/Rasterizer.py +++ b/source/gameengine/PyDoc/Rasterizer.py @@ -43,7 +43,6 @@ Example Uses an L{SCA_MouseSensor}, and two L{KX_ObjectActuator}s to implement M @var KX_BLENDER_GLSL_MATERIAL: Materials approximating blender materials with GLSL. """ - def getWindowWidth(): """ Gets the width of the window (in pixels) @@ -105,6 +104,13 @@ def setMistColor(rgb): @type rgb: list [r, g, b] """ + +def setAmbientColor(rgb): + """ + Sets the color of ambient light. + + @type rgb: list [r, g, b] + """ def setMistStart(start): """ @@ -121,6 +127,13 @@ def setMistEnd(end): @type end: float """ +def disableMist(): + """ + Disables mist. + + @note: Set any of the mist properties to enable mist. + """ + def setEyeSeparation(eyesep): """ Sets the eye separation for stereo mode. @@ -194,3 +207,15 @@ def drawLine(fromVec,toVec,color): @type color: list [r, g, b] """ +def enableMotionBlur(factor): + """ + Enable the motion blue effect. + + @param factor: the ammount of motion blur to display. + @type factor: float [0.0 - 1.0] + """ + +def disableMotionBlur(): + """ + Disable the motion blue effect. + """ diff --git a/source/gameengine/PyDoc/SCA_ANDController.py b/source/gameengine/PyDoc/SCA_ANDController.py deleted file mode 100644 index 1717e613595..00000000000 --- a/source/gameengine/PyDoc/SCA_ANDController.py +++ /dev/null @@ -1,11 +0,0 @@ -# $Id$ -# Documentation for SCA_ANDController -from SCA_IController import * - -class SCA_ANDController(SCA_IController): - """ - An AND controller activates only when all linked sensors are activated. - - There are no special python methods for this controller. - """ - diff --git a/source/gameengine/PyDoc/SCA_AlwaysSensor.py b/source/gameengine/PyDoc/SCA_AlwaysSensor.py deleted file mode 100644 index 54ab07a8a99..00000000000 --- a/source/gameengine/PyDoc/SCA_AlwaysSensor.py +++ /dev/null @@ -1,9 +0,0 @@ -# $Id$ -# Documentation for SCA_AlwaysSensor -from SCA_ISensor import * - -class SCA_AlwaysSensor(SCA_ISensor): - """ - This sensor is always activated. - """ - diff --git a/source/gameengine/PyDoc/SCA_DelaySensor.py b/source/gameengine/PyDoc/SCA_DelaySensor.py deleted file mode 100644 index 19df589ea7b..00000000000 --- a/source/gameengine/PyDoc/SCA_DelaySensor.py +++ /dev/null @@ -1,56 +0,0 @@ -# $Id$ -# Documentation for SCA_DelaySensor -from SCA_ISensor import * - -class SCA_DelaySensor(SCA_ISensor): - """ - The Delay sensor generates positive and negative triggers at precise time, - expressed in number of frames. The delay parameter defines the length - of the initial OFF period. A positive trigger is generated at the end of this period. - The duration parameter defines the length of the ON period following the OFF period. - There is a negative trigger at the end of the ON period. If duration is 0, the sensor - stays ON and there is no negative trigger. - The sensor runs the OFF-ON cycle once unless the repeat option is set: the - OFF-ON cycle repeats indefinately (or the OFF cycle if duration is 0). - Use SCA_ISensor::reset() at any time to restart sensor. - """ - def setDelay(delay): - """ - Set the initial delay before the positive trigger. - - @param delay: length of the initial OFF period as number of frame, 0 for immediate trigger - @type delay: integer - """ - def setDuration(duration): - """ - Set the duration of the ON pulse after initial delay and the generation of the positive trigger. - If duration is greater than 0, a negative trigger is sent at the end of the ON pulse. - - @param duration: length of the ON period in number of frame after the initial OFF period - @type duration: integer - """ - def setRepeat(repeat): - """ - Set if the sensor repeat mode. - - @param repeat: 1 if the OFF-ON cycle should be repeated indefinately, 0 if it should run once. - @type repeat: integer - """ - def getDelay(): - """ - Return the delay parameter value. - - @rtype: integer - """ - def getDuration(): - """ - Return the duration parameter value - - @rtype: integer - """ - def getRepeat(): - """ - Return the repeat parameter value - - @rtype: KX_TRUE or KX_FALSE - """ diff --git a/source/gameengine/PyDoc/SCA_IActuator.py b/source/gameengine/PyDoc/SCA_IActuator.py deleted file mode 100644 index ac47c15dc78..00000000000 --- a/source/gameengine/PyDoc/SCA_IActuator.py +++ /dev/null @@ -1,9 +0,0 @@ -# $Id$ -# Documentation for SCA_IActuator -from SCA_ILogicBrick import * - -class SCA_IActuator(SCA_ILogicBrick): - """ - Base class for all actuator logic bricks. - """ - diff --git a/source/gameengine/PyDoc/SCA_IController.py b/source/gameengine/PyDoc/SCA_IController.py deleted file mode 100644 index f83e7c97dce..00000000000 --- a/source/gameengine/PyDoc/SCA_IController.py +++ /dev/null @@ -1,9 +0,0 @@ -# $Id$ -# Documentation for KX_CameraActuator -from SCA_ILogicBrick import * - -class SCA_IController(SCA_ILogicBrick): - """ - Base class for all controller logic bricks. - """ - diff --git a/source/gameengine/PyDoc/SCA_ILogicBrick.py b/source/gameengine/PyDoc/SCA_ILogicBrick.py deleted file mode 100644 index ea09fcaea37..00000000000 --- a/source/gameengine/PyDoc/SCA_ILogicBrick.py +++ /dev/null @@ -1,32 +0,0 @@ -# $Id$ -# Documentation for the logic brick base class SCA_ILogicBrick -from KX_GameObject import * - -class SCA_ILogicBrick: - """ - Base class for all logic bricks. - """ - - def getOwner(): - """ - Gets the game object associated with this logic brick. - - @rtype: L{KX_GameObject} - """ - def setExecutePriority(priority): - """ - Sets the priority of this logic brick. - - This determines the order controllers are evaluated, and actuators are activated. - Bricks with lower priority will be executed first. - - @type priority: integer - @param priority: the priority of this logic brick. - """ - def getExecutePriority(): - """ - Gets the execution priority of this logic brick. - - @rtype: integer - @return: this logic bricks current priority. - """ diff --git a/source/gameengine/PyDoc/SCA_ISensor.py b/source/gameengine/PyDoc/SCA_ISensor.py deleted file mode 100644 index 14858505e24..00000000000 --- a/source/gameengine/PyDoc/SCA_ISensor.py +++ /dev/null @@ -1,91 +0,0 @@ -# $Id$ -# Documentation for SCA_ISensor -from SCA_ILogicBrick import * - -class SCA_ISensor(SCA_ILogicBrick): - """ - Base class for all sensor logic bricks. - """ - - def isPositive(): - """ - True if this sensor brick is in a positive state. - """ - - def isTriggered(): - """ - True if this sensor brick has triggered the current controller. - """ - - def getUsePosPulseMode(): - """ - True if the sensor is in positive pulse mode. - """ - def setUsePosPulseMode(pulse): - """ - Sets positive pulse mode. - - @type pulse: boolean - @param pulse: If True, will activate positive pulse mode for this sensor. - """ - def getFrequency(): - """ - The frequency for pulse mode sensors. - - @rtype: integer - @return: the pulse frequency in 1/50 sec. - """ - def setFrequency(freq): - """ - Sets the frequency for pulse mode sensors. - - @type freq: integer - @return: the pulse frequency in 1/50 sec. - """ - def getUseNegPulseMode(): - """ - True if the sensor is in negative pulse mode. - """ - def setUseNegPulseMode(pulse): - """ - Sets negative pulse mode. - - @type pulse: boolean - @param pulse: If True, will activate negative pulse mode for this sensor. - """ - def getInvert(): - """ - True if this sensor activates on negative events. - """ - def setInvert(invert): - """ - Sets if this sensor activates on positive or negative events. - - @type invert: boolean - @param invert: true if activates on negative events; false if activates on positive events. - """ - def getLevel(): - """ - Returns whether this sensor is a level detector or a edge detector. - It makes a difference only in case of logic state transition (state actuator). - A level detector will immediately generate a pulse, negative or positive - depending on the sensor condition, as soon as the state is activated. - A edge detector will wait for a state change before generating a pulse. - - @rtype: boolean - @return: true if sensor is level sensitive, false if it is edge sensitive - """ - def setLevel(level): - """ - Set whether to detect level or edge transition when entering a state. - - @param level: Detect level instead of edge? (KX_TRUE, KX_FALSE) - @type level: boolean - """ - def reset(): - """ - Reset sensor internal state, effect depends on the type of sensor and settings. - - The sensor is put in its initial state as if it was just activated. - """ - diff --git a/source/gameengine/PyDoc/SCA_JoystickSensor.py b/source/gameengine/PyDoc/SCA_JoystickSensor.py deleted file mode 100644 index d1dab9afcaf..00000000000 --- a/source/gameengine/PyDoc/SCA_JoystickSensor.py +++ /dev/null @@ -1,106 +0,0 @@ -# $Id: SCA_RandomSensor.py 15444 2008-07-05 17:05:05Z lukep $ -# Documentation for SCA_RandomSensor -from SCA_ISensor import * - -class SCA_JoystickSensor(SCA_ISensor): - """ - This sensor detects player joystick events. - """ - - def getIndex(): - """ - Returns the joystick index to use (from 1 to 8). - @rtype: integer - """ - def setIndex(index): - """ - Sets the joystick index to use. - @param index: The index of this joystick sensor, Clamped between 1 and 8. - @type index: integer - @note: This is only useful when you have more then 1 joystick connected to your computer - multiplayer games. - """ - def getAxis(): - """ - Returns the current axis this sensor reacts to. See L{getAxisValue()<SCA_JoystickSensor.getAxisValue>} for the current axis state. - @rtype: list - @return: 2 values returned are [axisIndex, axisDirection] - see L{setAxis()<SCA_JoystickSensor.setAxis>} for their purpose. - @note: When the "All Events" toggle is set, this option has no effect. - """ - def setAxis(axisIndex, axisDirection): - """ - @param axisIndex: Set the axis index to use when detecting axis movement. - @type axisIndex: integer from 1 to 2 - @param axisDirection: Set the axis direction used for detecting motion. 0:right, 1:up, 2:left, 3:down. - @type axisDirection: integer from 0 to 3 - @note: When the "All Events" toggle is set, this option has no effect. - """ - def getAxisValue(): - """ - Returns the state of the joysticks axis. See differs to L{getAxis()<SCA_JoystickSensor.getAxis>} returning the current state of the joystick. - @rtype: list - @return: 4 values, each spesifying the value of an axis between -32767 and 32767 depending on how far the axis is pushed, 0 for nothing. - - The first 2 values are used by most joysticks and gamepads for directional control. 3rd and 4th values are only on some joysticks and can be used for arbitary controls. - - left:[-32767, 0, ...], right:[32767, 0, ...], up:[0, -32767, ...], down:[0, 32767, ...] - @note: Some gamepads only set the axis on and off like a button. - """ - def getThreshold(): - """ - Get the axis threshold. See L{setThreshold()<SCA_JoystickSensor.setThreshold>} for details. - @rtype: integer - """ - def setThreshold(threshold): - """ - Set the axis threshold. - @param threshold: Joystick axis motion below this threshold wont trigger an event. Use values between (0 and 32767), lower values are more sensitive. - @type threshold: integer - """ - def getButton(): - """ - Returns the button index the sensor reacts to. See L{getButtonValue()<SCA_JoystickSensor.getButtonValue>} for a list of pressed buttons. - @rtype: integer - @note: When the "All Events" toggle is set, this option has no effect. - """ - def setButton(index): - """ - Sets the button index the sensor reacts to when the "All Events" option is not set. - @note: When the "All Events" toggle is set, this option has no effect. - """ - def getButtonValue(): - """ - Returns a list containing the indicies of the currently pressed buttons. - @rtype: list - """ - def getHat(): - """ - Returns the current hat direction this sensor is set to. - [hatNumber, hatDirection]. - @rtype: list - @note: When the "All Events" toggle is set, this option has no effect. - """ - def setHat(index): - """ - Sets the hat index the sensor reacts to when the "All Events" option is not set. - @type index: integer - """ - def getNumAxes(): - """ - Returns the number of axes for the joystick at this index. - @rtype: integer - """ - def getNumButtons(): - """ - Returns the number of buttons for the joystick at this index. - @rtype: integer - """ - def getNumHats(): - """ - Returns the number of hats for the joystick at this index. - @rtype: integer - """ - def isConnected(): - """ - Returns True if a joystick is detected at this joysticks index. - @rtype: bool - """ diff --git a/source/gameengine/PyDoc/SCA_KeyboardSensor.py b/source/gameengine/PyDoc/SCA_KeyboardSensor.py deleted file mode 100644 index 2f741f7d6a2..00000000000 --- a/source/gameengine/PyDoc/SCA_KeyboardSensor.py +++ /dev/null @@ -1,58 +0,0 @@ -# $Id$ -# Documentation for SCA_KeyboardSensor -from SCA_ISensor import * - -class SCA_KeyboardSensor(SCA_ISensor): - """ - A keyboard sensor detects player key presses. - - See module L{GameKeys} for keycode values. - """ - - def getKey(): - """ - Returns the key code this sensor is looking for. - """ - - def setKey(keycode): - """ - Set the key this sensor should listen for. - - @type keycode: keycode from L{GameKeys} module - """ - - def getHold1(): - """ - Returns the key code for the first modifier this sensor is looking for. - """ - - def setHold1(): - """ - Sets the key code for the first modifier this sensor should look for. - """ - - def getHold2(): - """ - Returns the key code for the second modifier this sensor is looking for. - """ - - def setHold2(): - """ - Sets the key code for the second modifier this sensor should look for. - """ - - def getPressedKeys(): - """ - Get a list of keys that have either been pressed, or just released this frame. - - @rtype: list of key status. [[keycode, status]] - """ - - def getCurrentlyPressedKeys(): - """ - Get a list of currently pressed keys that have either been pressed, or just released - - @rtype: list of key status. [[keycode, status]] - """ - - diff --git a/source/gameengine/PyDoc/SCA_MouseSensor.py b/source/gameengine/PyDoc/SCA_MouseSensor.py deleted file mode 100644 index 06b261f67fa..00000000000 --- a/source/gameengine/PyDoc/SCA_MouseSensor.py +++ /dev/null @@ -1,23 +0,0 @@ -# $Id$ -# Documentation for SCA_MouseSensor -from SCA_ISensor import * - -class SCA_MouseSensor(SCA_ISensor): - """ - Mouse Sensor logic brick. - """ - - def getXPosition(): - """ - Gets the x coordinate of the mouse. - - @rtype: integer - @return: the current x coordinate of the mouse, in frame coordinates (pixels) - """ - def getYPosition(): - """ - Gets the y coordinate of the mouse. - - @rtype: integer - @return: the current y coordinate of the mouse, in frame coordinates (pixels). - """ diff --git a/source/gameengine/PyDoc/SCA_ORController.py b/source/gameengine/PyDoc/SCA_ORController.py deleted file mode 100644 index eeeb9de3afe..00000000000 --- a/source/gameengine/PyDoc/SCA_ORController.py +++ /dev/null @@ -1,11 +0,0 @@ -# $Id$ -# Documentation for SCA_ORController -from SCA_IController import * - -class SCA_ORController(SCA_IController): - """ - An OR controller activates when any connected sensor activates. - - There are no special python methods for this controller. - """ - diff --git a/source/gameengine/PyDoc/SCA_PropertyActuator.py b/source/gameengine/PyDoc/SCA_PropertyActuator.py deleted file mode 100644 index dc1233ddfb7..00000000000 --- a/source/gameengine/PyDoc/SCA_PropertyActuator.py +++ /dev/null @@ -1,38 +0,0 @@ -# $Id$ -# Documentation for SCA_PropertyActuator -from SCA_IActuator import * - -class SCA_PropertyActuator(SCA_IActuator): - """ - Property Actuator - """ - def setProperty(prop): - """ - Set the property on which to operate. - - If there is no property of this name, the call is ignored. - - @type prop: string - @param prop: The name of the property to set. - """ - def getProperty(): - """ - Returns the name of the property on which to operate. - - @rtype: string - """ - def setValue(value): - """ - Set the value with which the actuator operates. - - If the value is not compatible with the type of the - property, the subsequent action is ignored. - - @type value: string - """ - def getValue(): - """ - Gets the value with which this actuator operates. - - @rtype: string - """ diff --git a/source/gameengine/PyDoc/SCA_PropertySensor.py b/source/gameengine/PyDoc/SCA_PropertySensor.py deleted file mode 100644 index 22de8d8b986..00000000000 --- a/source/gameengine/PyDoc/SCA_PropertySensor.py +++ /dev/null @@ -1,57 +0,0 @@ -# $Id$ -# Documentation for SCA_PropertySensor -from SCA_ISensor import * - -class SCA_PropertySensor(SCA_ISensor): - """ - Activates when the game object property matches. - """ - - def getType(): - """ - Gets when to activate this sensor. - - @return: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL, - KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED, - or KX_PROPSENSOR_EXPRESSION. - """ - - def setType(checktype): - """ - Set the type of check to perform. - - @type checktype: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL, - KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED, - or KX_PROPSENSOR_EXPRESSION. - """ - - def getProperty(): - """ - Return the property with which the sensor operates. - - @rtype: string - @return: the name of the property this sensor is watching. - """ - def setProperty(name): - """ - Sets the property with which to operate. If there is no property - of that name, this call is ignored. - - @type name: string. - """ - def getValue(): - """ - Return the value with which the sensor compares to the value of the property. - - @rtype: string - @return: the value of the property this sensor is watching. - """ - def setValue(value): - """ - Set the value with which the sensor operates. If the value - is not compatible with the type of the property, the subsequent - action is ignored. - - @type value: string - """ - diff --git a/source/gameengine/PyDoc/SCA_PythonController.py b/source/gameengine/PyDoc/SCA_PythonController.py deleted file mode 100644 index 6d91736d636..00000000000 --- a/source/gameengine/PyDoc/SCA_PythonController.py +++ /dev/null @@ -1,57 +0,0 @@ -# $Id$ -# Documentation for SCA_PythonController -from SCA_IController import * - -class SCA_PythonController(SCA_IController): - """ - A Python controller uses a Python script to activate it's actuators, - based on it's sensors. - """ - - def getSensors(): - """ - Gets a list of all sensors attached to this controller. - - @rtype: list [L{SCA_ISensor}] - """ - def getSensor(name): - """ - Gets the named linked sensor. - - @type name: string - @rtype: L{SCA_ISensor} - """ - def getActuators(): - """ - Gets a list of all actuators linked to this controller. - - @rtype: list [L{SCA_IActuator}] - """ - def getActuator(name): - """ - Gets the named linked actuator. - - @type name: string - @rtype: L{SCA_IActuator} - """ - def getScript(): - """ - Gets the Python script this controller executes. - - @rtype: string - """ - def setScript(script): - """ - Sets the Python script this controller executes. - - @type script: string. - """ - def getState(): - """ - Get the controllers state bitmask, this can be used with the GameObject's state to test if the the controller is active. - This for instance will always be true however you could compare with a previous state to see when the state was activated. - GameLogic.getCurrentController().getState() & GameLogic.getCurrentController().getOwner().getState() - - @rtype: int - """ - diff --git a/source/gameengine/PyDoc/SCA_RandomActuator.py b/source/gameengine/PyDoc/SCA_RandomActuator.py deleted file mode 100644 index 353b398b1ff..00000000000 --- a/source/gameengine/PyDoc/SCA_RandomActuator.py +++ /dev/null @@ -1,143 +0,0 @@ -# $Id$ -# Documentation for SCA_RandomActuator -from SCA_IActuator import * - -class SCA_RandomActuator(SCA_IActuator): - """ - Random Actuator - """ - def setSeed(seed): - """ - Sets the seed of the random number generator. - - Equal seeds produce equal series. If the seed is 0, - the generator will produce the same value on every call. - - @type seed: integer - """ - def getSeed(): - """ - Returns the initial seed of the generator. - - @rtype: integer - """ - def getPara1(): - """ - Returns the first parameter of the active distribution. - - Refer to the documentation of the generator types for the meaning - of this value. - - @rtype: float - """ - def getPara2(): - """ - Returns the second parameter of the active distribution. - - Refer to the documentation of the generator types for the meaning - of this value. - - @rtype: float - """ - def getDistribution(): - """ - Returns the type of random distribution. - - @rtype: distribution type - @return: KX_RANDOMACT_BOOL_CONST, KX_RANDOMACT_BOOL_UNIFORM, KX_RANDOMACT_BOOL_BERNOUILLI, - KX_RANDOMACT_INT_CONST, KX_RANDOMACT_INT_UNIFORM, KX_RANDOMACT_INT_POISSON, - KX_RANDOMACT_FLOAT_CONST, KX_RANDOMACT_FLOAT_UNIFORM, KX_RANDOMACT_FLOAT_NORMAL, - KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL - """ - def setProperty(property): - """ - Set the property to which the random value is assigned. - - If the generator and property types do not match, the assignment is ignored. - - @type property: string - @param property: The name of the property to set. - """ - def getProperty(): - """ - Returns the name of the property to set. - - @rtype: string - """ - def setBoolConst(value): - """ - Sets this generator to produce a constant boolean value. - - @param value: The value to return. - @type value: boolean - """ - def setBoolUniform(): - """ - Sets this generator to produce a uniform boolean distribution. - - The generator will generate True or False with 50% chance. - """ - def setBoolBernouilli(value): - """ - Sets this generator to produce a Bernouilli distribution. - - @param value: Specifies the proportion of False values to produce. - - 0.0: Always generate True - - 1.0: Always generate False - @type value: float - """ - def setIntConst(value): - """ - Sets this generator to always produce the given value. - - @param value: the value this generator produces. - @type value: integer - """ - def setIntUniform(lower_bound, upper_bound): - """ - Sets this generator to produce a random value between the given lower and - upper bounds (inclusive). - - @type lower_bound: integer - @type upper_bound: integer - """ - def setIntPoisson(value): - """ - Generate a Poisson-distributed number. - - This performs a series of Bernouilli tests with parameter value. - It returns the number of tries needed to achieve succes. - - @type value: float - """ - def setFloatConst(value): - """ - Always generate the given value. - - @type value: float - """ - def setFloatUniform(lower_bound, upper_bound): - """ - Generates a random float between lower_bound and upper_bound with a - uniform distribution. - - @type lower_bound: float - @type upper_bound: float - """ - def setFloatNormal(mean, standard_deviation): - """ - Generates a random float from the given normal distribution. - - @type mean: float - @param mean: The mean (average) value of the generated numbers - @type standard_deviation: float - @param standard_deviation: The standard deviation of the generated numbers. - """ - def setFloatNegativeExponential(half_life): - """ - Generate negative-exponentially distributed numbers. - - The half-life 'time' is characterized by half_life. - - @type half_life: float - """ diff --git a/source/gameengine/PyDoc/SCA_RandomSensor.py b/source/gameengine/PyDoc/SCA_RandomSensor.py deleted file mode 100644 index 940b8f879ff..00000000000 --- a/source/gameengine/PyDoc/SCA_RandomSensor.py +++ /dev/null @@ -1,28 +0,0 @@ -# $Id$ -# Documentation for SCA_RandomSensor -from SCA_ISensor import * - -class SCA_RandomSensor(SCA_ISensor): - """ - This sensor activates randomly. - """ - - def setSeed(seed): - """ - Sets the seed of the random number generator. - - If the seed is 0, the generator will produce the same value on every call. - - @type seed: integer. - """ - def getSeed(): - """ - Returns the initial seed of the generator. Equal seeds produce equal random - series. - - @rtype: integer - """ - def getLastDraw(): - """ - Returns the last random number generated. - """ diff --git a/source/gameengine/PyDoc/SConscript b/source/gameengine/PyDoc/SConscript index ac0b163d7bd..ed9712ba273 100644 --- a/source/gameengine/PyDoc/SConscript +++ b/source/gameengine/PyDoc/SConscript @@ -3,26 +3,27 @@ Import ('env') from optparse import OptionParser -try: - import epydoc -except ImportError: - print "No epydoc install detected, Python API Docs will not be generated " -if epydoc: - from epydoc.docbuilder import build_doc_index - from epydoc import cli - names = env.Glob("source/gameengine/PyDoc/*.py") - docindex = build_doc_index(names) - optvalues = cli.OPTION_DEFAULTS - optvalues["verbose"] = 1 - optvalues["target"] = env["BF_DOCDIR"]+"/BGE_API/" - optvalues["url"] = "http://www.blender.org" - optvalues["top"] = "Game Engine API" - optvalues["name"] = "Blender" - optvalues["noprivate"] = 1 - optvalues["noframes"] = 1 - optvalues["names"] = names - optparser = OptionParser() - optparser.set_defaults(**optvalues) - (options, args) = optparser.parse_args([]) - cli.write_html(docindex, options) +import epydoc +from epydoc.docbuilder import build_doc_index +from epydoc import cli +names = env.Glob("source/gameengine/PyDoc/*.py") +docindex = build_doc_index(names) +optvalues = cli.OPTION_DEFAULTS +optvalues["verbose"] = 1 +optvalues["quiet"] = 0 +optvalues["include_source_code"] = 0 +optvalues["inheritance"] = "included" +optvalues["show_private"] = 0 +optvalues["target"] = env["BF_DOCDIR"]+"/BGE_API/" +optvalues["url"] = "http://www.blender.org" +optvalues["top"] = "Game Engine API" +optvalues["name"] = "Blender" +optvalues["noprivate"] = 1 +optvalues["noframes"] = 1 +optvalues["names"] = names +optparser = OptionParser() +optparser.set_defaults(**optvalues) +(options, args) = optparser.parse_args([]) +print "Writing Game Engine epydocs to \"%s\"" % optvalues["target"] +cli.write_html(docindex, options) diff --git a/source/gameengine/PyDoc/WhatsNew.py b/source/gameengine/PyDoc/WhatsNew.py deleted file mode 100644 index 64bef7ee1c8..00000000000 --- a/source/gameengine/PyDoc/WhatsNew.py +++ /dev/null @@ -1,34 +0,0 @@ -# $Id$ -""" -New Python Functionality in this Version of Blender -=================================================== - -This document lists what has been changed in the Game Engine Python API. - -Blender CVS - - Added L{KX_GameObject}.getDistanceTo() method. (thanks Charlie C) - - Added L{KX_PolygonMaterial} module - -Blender 2.36 ------------- - - Added L{KX_CameraActuator} methods (thanks snail) - -Blender 2.35 ------------- - - Added tic rate methods to L{GameLogic} - - Added stereo eye separation and focal length methods to L{Rasterizer}. - - Fixed L{Rasterizer}.makeScreenshot() method. - - Added setLogicTicRate() and setPhysicsTicRate() to L{GameLogic} - -Blender 2.34 ------------- - - - Added getType() and setType() to L{BL_ActionActuator} and L{KX_SoundActuator} (sgefant) - - New Scene module: L{KX_Scene} - - New Camera module: L{KX_Camera} - - New Light module: L{KX_Light} - - Added attributes to L{KX_GameObject}, L{KX_VertexProxy} - - L{KX_SCA_AddObjectActuator}.setObject(), L{KX_TrackToActuator}.setObject() and - L{KX_SceneActuator}.setCamera() now accept L{KX_GameObject}s as parameters - -""" diff --git a/source/gameengine/PyDoc/bge_api_validate_py.txt b/source/gameengine/PyDoc/bge_api_validate_py.txt new file mode 100644 index 00000000000..ebd74c06bb3 --- /dev/null +++ b/source/gameengine/PyDoc/bge_api_validate_py.txt @@ -0,0 +1,136 @@ +#~ 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; version 2 of the License. + +#~ 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. + +# This script must run from a logic brick so it has access to the game engine api +# it assumes the root blender source directory is the current working directory +# +# Currently it only prints missing modules and methods (not attributes) + +import sys, os + +BGE_API_DOC_PATH = 'source/gameengine/PyDoc' + + +mods = ['GameLogic', 'Rasterizer', 'GameKeys'] +mods_dict = {} +for m in mods: + mods_dict[m] = sys.modules[m] + + +import GameTypes +type_members = {} + +for type_name in dir(GameTypes): + if type_name.startswith('__'): + continue + + type_object = getattr(GameTypes, type_name) + + members = [] + type_members[type_object.__name__] = members + + for member in type_object.__dict__.keys(): + if member.startswith('__'): + continue + + # print type_object.__name__ + '.' + k + members.append(member) + + + +doc_dir= os.path.join(os.getcwd(), BGE_API_DOC_PATH) + +if doc_dir not in sys.path: + sys.path.append(doc_dir) + + +def check_attribute(class_ob, member): + doc = class_ob.__doc__ + if not doc: + return False + + for l in doc.split('\n'): + l = l.strip() + + ''' + @ivar foo: blah blah + to + foo + + ''' + + if l.startswith('@ivar') or l.startswith('@var'): + var = l.split()[1].split(':')[0] + + if var == member: + return True + + return False + + + + + + +print '\n\n\nChecking Docs' + +PRINT_OK = False + +pymod = sys.modules['GameTypes'] +del sys.modules['GameTypes'] # temp remove +mod = __import__('GameTypes') # get the python module +reload(mod) # incase were editing it +sys.modules['GameTypes'] = pymod + +for type_name in sorted(type_members.keys()): + members = type_members[type_name] + + try: + type_class = getattr(mod, type_name) + except: + print "missing class: %s.%s - %s" % (type_name, type_name, str(sorted(members))) + continue + + for member in sorted(members): + try: + getattr(type_class, member) + if PRINT_OK: + print "\tfound: %s.%s" % (type_name, member) + except: + if check_attribute(type_class, member): + if PRINT_OK: + print "\tfound attr: %s.%s" % (type_name, member) + else: + print "\tmissing: %s.%s" % (type_name, member) + + +# Now check the modules +for mod_name, pymod in mods_dict.iteritems(): + print pymod + del sys.modules[mod_name] + + # Now well get the python version + pydoc = __import__(mod_name) + pydoc = reload(pydoc) # avoid using the out dated pyc file only + print pydoc.__file__ + + for member in sorted(dir(pymod)): + if hasattr(pydoc, member) or check_attribute(pydoc, member): + if PRINT_OK: + print "\tfound module attr: %s.%s" % (mod_name, member) + else: + print "\tmissing module attr: %s.%s" % (mod_name, member) + + # Restore real module + sys.modules[mod_name] = pymod + + +sys.path.pop() # remove the pydoc dir from our import paths + + diff --git a/source/gameengine/PyDoc/epy_docgen.sh b/source/gameengine/PyDoc/epy_docgen.sh index b243101ddcb..dd30256f42f 100644..100755 --- a/source/gameengine/PyDoc/epy_docgen.sh +++ b/source/gameengine/PyDoc/epy_docgen.sh @@ -7,5 +7,10 @@ # set posix locale so regex works properly for [A-Z]*.py LC_ALL=POSIX -epydoc --debug -v -o BPY_GE --url "http://www.blender.org" --top GameLogic \ - --name "Blender GameEngine" --no-private --no-frames *.py +epydoc --debug -v -o BPY_GE --url "http://www.blender.org" --top API_intro \ + --name "Blender GameEngine" --no-private --no-sourcecode --inheritance=included \ + *.py \ + ../../../source/blender/python/api2_2x/doc/BGL.py \ + ../../../source/blender/python/api2_2x/doc/Mathutils.py \ + ../../../source/blender/python/api2_2x/doc/Geometry.py + diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt index 6d53ee53471..51d1f5001dd 100644 --- a/source/gameengine/Rasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/CMakeLists.txt @@ -27,13 +27,15 @@ FILE(GLOB SRC *.cpp) SET(INC - . - ../../../source/kernel/gen_system - ../../../intern/string - ../../../intern/moto/include - ../../../extern/glew/include - ../Expressions - ${PYTHON_INC} + . + ../../../source/kernel/gen_system + ../../../source/blender/makesdna + ../../../source/gameengine/SceneGraph + ../../../intern/string + ../../../intern/moto/include + ../../../extern/glew/include + ../Expressions + ${PYTHON_INC} ) BLENDERLIB(bf_rasterizer "${SRC}" "${INC}") diff --git a/source/gameengine/Rasterizer/Makefile b/source/gameengine/Rasterizer/Makefile index 917f70c7108..eafa2ded2f2 100644 --- a/source/gameengine/Rasterizer/Makefile +++ b/source/gameengine/Rasterizer/Makefile @@ -40,6 +40,8 @@ CPPFLAGS += -I$(OPENGL_HEADERS) CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I../../kernel/gen_system +CPPFLAGS += -I../../blender/makesdna +CPPFLAGS += -I../SceneGraph CPPFLAGS += -I../BlenderRoutines CPPFLAGS += -I../Expressions diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp index 6e5553d4781..239031866ca 100644 --- a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp @@ -58,16 +58,14 @@ RAS_2DFilterManager::RAS_2DFilterManager(): texturewidth(-1), textureheight(-1), canvaswidth(-1), canvasheight(-1), -numberoffilters(0) +numberoffilters(0), need_tex_update(true) { isshadersupported = GLEW_ARB_shader_objects && GLEW_ARB_fragment_shader && GLEW_ARB_multitexture; + /* used to return before 2.49 but need to initialize values so dont */ if(!isshadersupported) - { std::cout<<"shaders not supported!" << std::endl; - return; - } int passindex; for(passindex =0; passindex<MAX_RENDER_PASS; passindex++) @@ -78,6 +76,7 @@ numberoffilters(0) m_gameObjects[passindex] = NULL; } texname[0] = texname[1] = texname[2] = -1; + errorprinted= false; } RAS_2DFilterManager::~RAS_2DFilterManager() @@ -85,76 +84,107 @@ RAS_2DFilterManager::~RAS_2DFilterManager() FreeTextures(); } +void RAS_2DFilterManager::PrintShaderErrors(unsigned int shader, const char *task, const char *code) +{ + GLcharARB log[5000]; + GLsizei length = 0; + const char *c, *pos, *end; + int line = 1; + + if(errorprinted) + return; + + errorprinted= true; + + glGetInfoLogARB(shader, sizeof(log), &length, log); + end = code + strlen(code); + + printf("2D Filter GLSL Shader: %s error:\n", task); + + c = code; + while ((c < end) && (pos = strchr(c, '\n'))) { + printf("%2d ", line); + fwrite(c, (pos+1)-c, 1, stdout); + c = pos+1; + line++; + } + printf("%s", c); + + printf("%s\n", log); +} + unsigned int RAS_2DFilterManager::CreateShaderProgram(const char* shadersource) { - GLuint program = 0; - GLuint fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER); - GLint success; + GLuint program = 0; + GLuint fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER); + GLint success; - glShaderSourceARB(fShader, 1, (const char**)&shadersource, NULL); + glShaderSourceARB(fShader, 1, (const char**)&shadersource, NULL); - glCompileShaderARB(fShader); + glCompileShaderARB(fShader); - glGetObjectParameterivARB(fShader, GL_COMPILE_STATUS, &success); - if(!success) - { - /*Shader Comile Error*/ - std::cout << "2dFilters - Shader compile error" << std::endl; - return 0; - } - - program = glCreateProgramObjectARB(); - glAttachObjectARB(program, fShader); - glLinkProgramARB(program); - glGetObjectParameterivARB(program, GL_LINK_STATUS, &success); - if (!success) - { - /*Program Link Error*/ - std::cout << "2dFilters - Shader program link error" << std::endl; - return 0; - } - - glValidateProgramARB(program); - glGetObjectParameterivARB(program, GL_VALIDATE_STATUS, &success); - if (!success) - { - /*Program Validation Error*/ - std::cout << "2dFilters - Shader program validation error" << std::endl; - return 0; - } + glGetObjectParameterivARB(fShader, GL_COMPILE_STATUS, &success); + if(!success) + { + /*Shader Comile Error*/ + PrintShaderErrors(fShader, "compile", shadersource); + return 0; + } + + program = glCreateProgramObjectARB(); + glAttachObjectARB(program, fShader); + + glLinkProgramARB(program); + glGetObjectParameterivARB(program, GL_LINK_STATUS, &success); + if (!success) + { + /*Program Link Error*/ + PrintShaderErrors(fShader, "link", shadersource); + return 0; + } + + glValidateProgramARB(program); + glGetObjectParameterivARB(program, GL_VALIDATE_STATUS, &success); + if (!success) + { + /*Program Validation Error*/ + PrintShaderErrors(fShader, "validate", shadersource); + return 0; + } - return program; + return program; } unsigned int RAS_2DFilterManager::CreateShaderProgram(int filtermode) { - switch(filtermode) - { - case RAS_2DFILTER_BLUR: - return CreateShaderProgram(BlurFragmentShader); - case RAS_2DFILTER_SHARPEN: - return CreateShaderProgram(SharpenFragmentShader); - case RAS_2DFILTER_DILATION: - return CreateShaderProgram(DilationFragmentShader); - case RAS_2DFILTER_EROSION: - return CreateShaderProgram(ErosionFragmentShader); - case RAS_2DFILTER_LAPLACIAN: - return CreateShaderProgram(LaplacionFragmentShader); - case RAS_2DFILTER_SOBEL: - return CreateShaderProgram(SobelFragmentShader); - case RAS_2DFILTER_PREWITT: - return CreateShaderProgram(PrewittFragmentShader); - case RAS_2DFILTER_GRAYSCALE: - return CreateShaderProgram(GrayScaleFragmentShader); - case RAS_2DFILTER_SEPIA: - return CreateShaderProgram(SepiaFragmentShader); - case RAS_2DFILTER_INVERT: - return CreateShaderProgram(InvertFragmentShader); - } - return 0; + switch(filtermode) + { + case RAS_2DFILTER_BLUR: + return CreateShaderProgram(BlurFragmentShader); + case RAS_2DFILTER_SHARPEN: + return CreateShaderProgram(SharpenFragmentShader); + case RAS_2DFILTER_DILATION: + return CreateShaderProgram(DilationFragmentShader); + case RAS_2DFILTER_EROSION: + return CreateShaderProgram(ErosionFragmentShader); + case RAS_2DFILTER_LAPLACIAN: + return CreateShaderProgram(LaplacionFragmentShader); + case RAS_2DFILTER_SOBEL: + return CreateShaderProgram(SobelFragmentShader); + case RAS_2DFILTER_PREWITT: + return CreateShaderProgram(PrewittFragmentShader); + case RAS_2DFILTER_GRAYSCALE: + return CreateShaderProgram(GrayScaleFragmentShader); + case RAS_2DFILTER_SEPIA: + return CreateShaderProgram(SepiaFragmentShader); + case RAS_2DFILTER_INVERT: + return CreateShaderProgram(InvertFragmentShader); + } + return 0; } -void RAS_2DFilterManager::AnalyseShader(int passindex, vector<STR_String>& propNames) + +void RAS_2DFilterManager::AnalyseShader(int passindex, vector<STR_String>& propNames) { texflag[passindex] = 0; if(glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture") != -1) @@ -185,50 +215,50 @@ void RAS_2DFilterManager::StartShaderProgram(int passindex) glActiveTextureARB(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texname[0]); - if (uniformLoc != -1) - { + if (uniformLoc != -1) + { glUniform1iARB(uniformLoc, 0); - } + } - /* send depth texture to glsl program if it needs */ + /* send depth texture to glsl program if it needs */ if(texflag[passindex] & 0x1){ - uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture"); - glActiveTextureARB(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, texname[1]); + uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture"); + glActiveTextureARB(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texname[1]); - if (uniformLoc != -1) - { - glUniform1iARB(uniformLoc, 1); - } - } + if (uniformLoc != -1) + { + glUniform1iARB(uniformLoc, 1); + } + } - /* send luminance texture to glsl program if it needs */ + /* send luminance texture to glsl program if it needs */ if(texflag[passindex] & 0x2){ - uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture"); - glActiveTextureARB(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, texname[2]); - - if (uniformLoc != -1) - { - glUniform1iARB(uniformLoc, 2); - } + uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture"); + glActiveTextureARB(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, texname[2]); + + if (uniformLoc != -1) + { + glUniform1iARB(uniformLoc, 2); + } } uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_TextureCoordinateOffset"); - if (uniformLoc != -1) - { - glUniform2fvARB(uniformLoc, 9, textureoffsets); - } + if (uniformLoc != -1) + { + glUniform2fvARB(uniformLoc, 9, textureoffsets); + } uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureWidth"); - if (uniformLoc != -1) - { + if (uniformLoc != -1) + { glUniform1fARB(uniformLoc,texturewidth); - } + } uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTextureHeight"); - if (uniformLoc != -1) - { + if (uniformLoc != -1) + { glUniform1fARB(uniformLoc,textureheight); - } + } int i, objProperties = m_properties[passindex].size(); for(i=0; i<objProperties; i++) @@ -249,11 +279,11 @@ void RAS_2DFilterManager::EndShaderProgram() void RAS_2DFilterManager::FreeTextures() { - if(texname[0]!=-1) + if(texname[0]!=(unsigned int)-1) glDeleteTextures(1, (GLuint*)&texname[0]); - if(texname[1]!=-1) + if(texname[1]!=(unsigned int)-1) glDeleteTextures(1, (GLuint*)&texname[1]); - if(texname[2]!=-1) + if(texname[2]!=(unsigned int)-1) glDeleteTextures(1, (GLuint*)&texname[2]); } @@ -300,20 +330,20 @@ void RAS_2DFilterManager::UpdateOffsetMatrix(RAS_ICanvas* canvas) RAS_Rect canvas_rect = canvas->GetWindowArea(); canvaswidth = canvas->GetWidth(); canvasheight = canvas->GetHeight(); + texturewidth = canvaswidth + canvas_rect.GetLeft(); textureheight = canvasheight + canvas_rect.GetBottom(); - GLint i,j; i = 0; - while ((1 << i) <= texturewidth) - i++; - texturewidth = (1 << (i)); + while ((1 << i) <= texturewidth) + i++; + texturewidth = (1 << (i)); - // Now for height - i = 0; - while ((1 << i) <= textureheight) - i++; - textureheight = (1 << (i)); + // Now for height + i = 0; + while ((1 << i) <= textureheight) + i++; + textureheight = (1 << (i)); GLfloat xInc = 1.0f / (GLfloat)texturewidth; GLfloat yInc = 1.0f / (GLfloat)textureheight; @@ -328,6 +358,23 @@ void RAS_2DFilterManager::UpdateOffsetMatrix(RAS_ICanvas* canvas) } } +void RAS_2DFilterManager::UpdateCanvasTextureCoord(unsigned int * viewport) +{ + /* + This function update canvascoord[]. + These parameters are used to create texcoord[1] + That way we can access the texcoord relative to the canvas: + (0.0,0.0) bottom left, (1.0,1.0) top right, (0.5,0.5) center + */ + canvascoord[0] = (GLfloat) viewport[0] / viewport[2]; + canvascoord[0] *= -1; + canvascoord[1] = (GLfloat) (texturewidth - viewport[0]) / viewport[2]; + + canvascoord[2] = (GLfloat) viewport[1] / viewport[3]; + canvascoord[2] *= -1; + canvascoord[3] = (GLfloat)(textureheight - viewport[1]) / viewport[3]; +} + void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) { bool need_depth=false; @@ -355,12 +402,21 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) if(num_filters <= 0) return; + GLuint viewport[4]={0}; + glGetIntegerv(GL_VIEWPORT,(GLint *)viewport); + if(canvaswidth != canvas->GetWidth() || canvasheight != canvas->GetHeight()) { UpdateOffsetMatrix(canvas); + UpdateCanvasTextureCoord((unsigned int*)viewport); + need_tex_update = true; + } + + if(need_tex_update) + { SetupTextures(need_depth, need_luminance); + need_tex_update = false; } - GLuint viewport[4]={0}; if(need_depth){ glActiveTextureARB(GL_TEXTURE1); @@ -371,18 +427,18 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) if(need_luminance){ glActiveTextureARB(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, texname[2]); - glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, 0, 0 , texturewidth,textureheight, 0); + glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, 0, 0, texturewidth,textureheight, 0); } - glGetIntegerv(GL_VIEWPORT,(GLint *)viewport); glViewport(0,0, texturewidth, textureheight); glDisable(GL_DEPTH_TEST); + glPushMatrix(); //GL_MODELVIEW + glLoadIdentity(); // GL_MODELVIEW glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); + glPushMatrix(); glLoadIdentity(); for(passindex =0; passindex<MAX_RENDER_PASS; passindex++) @@ -398,10 +454,10 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) glBegin(GL_QUADS); glColor4f(1.f, 1.f, 1.f, 1.f); - glTexCoord2f(1.0, 1.0); glVertex2f(1,1); - glTexCoord2f(0.0, 1.0); glVertex2f(-1,1); - glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1); - glTexCoord2f(1.0, 0.0); glVertex2f(1,-1); + glTexCoord2f(1.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[1], canvascoord[3]); glVertex2f(1,1); + glTexCoord2f(0.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[0], canvascoord[3]); glVertex2f(-1,1); + glTexCoord2f(0.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[0], canvascoord[2]); glVertex2f(-1,-1); + glTexCoord2f(1.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[1], canvascoord[2]); glVertex2f(1,-1); glEnd(); } } @@ -409,6 +465,9 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) glEnable(GL_DEPTH_TEST); glViewport(viewport[0],viewport[1],viewport[2],viewport[3]); EndShaderProgram(); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); } void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* gameObj, RAS_2DFILTER_MODE mode, int pass, STR_String& text) @@ -417,7 +476,7 @@ void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* game return; if(pass<0 || pass>=MAX_RENDER_PASS) return; - + need_tex_update = true; if(mode == RAS_2DFILTER_DISABLED) { m_enabled[pass] = 0; diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.h b/source/gameengine/Rasterizer/RAS_2DFilterManager.h index c16bd41dd0e..99d4ea595ab 100644 --- a/source/gameengine/Rasterizer/RAS_2DFilterManager.h +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.h @@ -30,6 +30,10 @@ #define MAX_RENDER_PASS 100 +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class RAS_2DFilterManager { private: @@ -38,12 +42,15 @@ private: void AnalyseShader(int passindex, vector<STR_String>& propNames); void StartShaderProgram(int passindex); void EndShaderProgram(); + void PrintShaderErrors(unsigned int shader, const char *task, const char *code); void SetupTextures(bool depth, bool luminance); void FreeTextures(); void UpdateOffsetMatrix(RAS_ICanvas* canvas); - + void UpdateCanvasTextureCoord(unsigned int * viewport); + + float canvascoord[4]; float textureoffsets[18]; float view[4]; /* texname[0] contains render to texture, texname[1] contains depth texture, texname[2] contains luminance texture*/ @@ -58,6 +65,8 @@ private: short texflag[MAX_RENDER_PASS]; bool isshadersupported; + bool errorprinted; + bool need_tex_update; unsigned int m_filters[MAX_RENDER_PASS]; short m_enabled[MAX_RENDER_PASS]; @@ -92,5 +101,12 @@ public: void RenderFilters(RAS_ICanvas* canvas); void EnableFilter(vector<STR_String>& propNames, void* gameObj, RAS_2DFILTER_MODE mode, int pass, STR_String& text); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_2DFilterManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.cpp b/source/gameengine/Rasterizer/RAS_BucketManager.cpp index f7938bb62e6..8b3c4990a7a 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.cpp +++ b/source/gameengine/Rasterizer/RAS_BucketManager.cpp @@ -113,16 +113,23 @@ void RAS_BucketManager::OrderBuckets(const MT_Transform& cameratrans, BucketList const MT_Vector3 pnorm(cameratrans.getBasis()[2]); for (bit = buckets.begin(); bit != buckets.end(); ++bit) - for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) - if (!mit->IsCulled()) - size++; + { + SG_DList::iterator<RAS_MeshSlot> mit((*bit)->GetActiveMeshSlots()); + for(mit.begin(); !mit.end(); ++mit) + size++; + } slots.resize(size); for (bit = buckets.begin(); bit != buckets.end(); ++bit) - for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) - if (!mit->IsCulled()) - slots[i++].set(&*mit, *bit, pnorm); + { + RAS_MaterialBucket* bucket = *bit; + RAS_MeshSlot* ms; + // remove the mesh slot form the list, it culls them automatically for next frame + while((ms = bucket->GetNextActiveMeshSlot())) { + slots[i++].set(ms, bucket, pnorm); + } + } if(alpha) sort(slots.begin(), slots.end(), backtofront()); @@ -148,6 +155,10 @@ void RAS_BucketManager::RenderAlphaBuckets( while(sit->m_bucket->ActivateMaterial(cameratrans, rasty, rendertools)) sit->m_bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *(sit->m_ms)); + + // make this mesh slot culled automatically for next frame + // it will be culled out by frustrum culling + sit->m_ms->SetCulled(true); } rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED); @@ -157,11 +168,26 @@ void RAS_BucketManager::RenderSolidBuckets( const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools) { BucketList::iterator bit; - list<RAS_MeshSlot>::iterator mit; rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED); for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) { +#if 1 + RAS_MaterialBucket* bucket = *bit; + RAS_MeshSlot* ms; + // remove the mesh slot form the list, it culls them automatically for next frame + while((ms = bucket->GetNextActiveMeshSlot())) + { + rendertools->SetClientObject(rasty, ms->m_clientObj); + while (bucket->ActivateMaterial(cameratrans, rasty, rendertools)) + bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *ms); + + // make this mesh slot culled automatically for next frame + // it will be culled out by frustrum culling + ms->SetCulled(true); + } +#else + list<RAS_MeshSlot>::iterator mit; for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { if (mit->IsCulled()) continue; @@ -170,7 +196,12 @@ void RAS_BucketManager::RenderSolidBuckets( while ((*bit)->ActivateMaterial(cameratrans, rasty, rendertools)) (*bit)->RenderMeshSlot(cameratrans, rasty, rendertools, *mit); + + // make this mesh slot culled automatically for next frame + // it will be culled out by frustrum culling + mit->SetCulled(true); } +#endif } /* this code draws meshes order front-to-back instead to reduce overdraw. @@ -268,3 +299,21 @@ void RAS_BucketManager::ReleaseDisplayLists(RAS_IPolyMaterial *mat) } } +void RAS_BucketManager::ReleaseMaterials(RAS_IPolyMaterial * mat) +{ + BucketList::iterator bit; + list<RAS_MeshSlot>::iterator mit; + + for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) { + if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) { + (*bit)->GetPolyMaterial()->ReleaseMaterial(); + } + } + + for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) { + if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) { + (*bit)->GetPolyMaterial()->ReleaseMaterial(); + } + } +} + diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.h b/source/gameengine/Rasterizer/RAS_BucketManager.h index 74526f365a0..dcac41ab6e9 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.h +++ b/source/gameengine/Rasterizer/RAS_BucketManager.h @@ -58,6 +58,7 @@ public: void OptimizeBuckets(MT_Scalar distance); void ReleaseDisplayLists(RAS_IPolyMaterial * material = NULL); + void ReleaseMaterials(RAS_IPolyMaterial * material = NULL); private: void OrderBuckets(const MT_Transform& cameratrans, BucketList& buckets, vector<sortedmeshslot>& slots, bool alpha); @@ -66,6 +67,12 @@ private: RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools); void RenderAlphaBuckets(const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools); + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_BucketManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__RAS_BUCKETMANAGER diff --git a/source/gameengine/Rasterizer/RAS_CameraData.h b/source/gameengine/Rasterizer/RAS_CameraData.h index e3af43fb839..c8f4d9a0a17 100644 --- a/source/gameengine/Rasterizer/RAS_CameraData.h +++ b/source/gameengine/Rasterizer/RAS_CameraData.h @@ -32,6 +32,7 @@ struct RAS_CameraData { float m_lens; + float m_scale; float m_clipstart; float m_clipend; bool m_perspective; @@ -42,10 +43,11 @@ struct RAS_CameraData int m_viewporttop; float m_focallength; - RAS_CameraData(float lens = 35.0, float clipstart = 0.1, float clipend = 5000.0, bool perspective = true, + RAS_CameraData(float lens = 35.0, float scale = 6.0, float clipstart = 0.1, float clipend = 5000.0, bool perspective = true, float focallength = 0.0f, bool viewport = false, int viewportleft = 0, int viewportbottom = 0, int viewportright = 0, int viewporttop = 0) : m_lens(lens), + m_scale(scale), m_clipstart(clipstart), m_clipend(clipend), m_perspective(perspective), diff --git a/source/gameengine/Rasterizer/RAS_Deformer.h b/source/gameengine/Rasterizer/RAS_Deformer.h index 3332ac4c0a7..6f4cd425c6c 100644 --- a/source/gameengine/Rasterizer/RAS_Deformer.h +++ b/source/gameengine/Rasterizer/RAS_Deformer.h @@ -34,23 +34,64 @@ #pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning #endif //WIN32 +#include <stdlib.h> #include "GEN_Map.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + +struct DerivedMesh; +class RAS_MeshObject; + class RAS_Deformer { public: - RAS_Deformer(){}; + RAS_Deformer() : m_pMesh(NULL), m_bDynamic(false) {}; virtual ~RAS_Deformer(){}; virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map)=0; virtual bool Apply(class RAS_IPolyMaterial *polymat)=0; virtual bool Update(void)=0; - virtual RAS_Deformer *GetReplica(class KX_GameObject* replica)=0; + virtual bool UpdateBuckets(void)=0; + virtual RAS_Deformer *GetReplica()=0; + virtual void ProcessReplica()=0; virtual bool SkipVertexTransform() { return false; } + virtual bool ShareVertexArray() + { + return true; + } + virtual bool UseVertexArray() + { + return true; + } + // true when deformer produces varying vertex (shape or armature) + bool IsDynamic() + { + return m_bDynamic; + } + virtual struct DerivedMesh* GetFinalMesh() + { + return NULL; + } + virtual class RAS_MeshObject* GetRasMesh() + { + /* m_pMesh does not seem to be being used?? */ + return NULL; + } + virtual float (* GetTransVerts(int *tot))[3] { *tot= 0; return NULL; } + protected: class RAS_MeshObject *m_pMesh; + bool m_bDynamic; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_Deformer"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Rasterizer/RAS_FramingManager.cpp b/source/gameengine/Rasterizer/RAS_FramingManager.cpp index e2bbca48bb5..ea18ffb2298 100644 --- a/source/gameengine/Rasterizer/RAS_FramingManager.cpp +++ b/source/gameengine/Rasterizer/RAS_FramingManager.cpp @@ -72,6 +72,39 @@ ComputeDefaultFrustum( void RAS_FramingManager:: +ComputeDefaultOrtho( + const float camnear, + const float camfar, + const float scale, + const float design_aspect_ratio, + RAS_FrameFrustum & frustum +) +{ + float halfSize = scale*0.5f; + float sizeX; + float sizeY; + + if (design_aspect_ratio > 1.f) { + // halfsize defines the width + sizeX = halfSize; + sizeY = halfSize/design_aspect_ratio; + } else { + // halfsize defines the height + sizeX = halfSize * design_aspect_ratio; + sizeY = halfSize; + } + + frustum.x2 = sizeX; + frustum.x1 = -frustum.x2; + frustum.y2 = sizeY; + frustum.y1 = -frustum.y2; + frustum.camnear = -camfar; + frustum.camfar = camfar; +} + + + void +RAS_FramingManager:: ComputeBestFitViewRect( const RAS_Rect &availableViewport, const float design_aspect_ratio, @@ -227,5 +260,73 @@ ComputeFrustum( } } + void +RAS_FramingManager:: + ComputeOrtho( + const RAS_FrameSettings &settings, + const RAS_Rect &availableViewport, + const RAS_Rect &viewport, + const float scale, + const float camnear, + const float camfar, + RAS_FrameFrustum &frustum + ) +{ + RAS_FrameSettings::RAS_FrameType type = settings.FrameType(); + + const float design_width = float(settings.DesignAspectWidth()); + const float design_height = float(settings.DesignAspectHeight()); + + float design_aspect_ratio = float(1); + + if (design_height == float(0)) { + // well this is ill defined + // lets just scale the thing + type = RAS_FrameSettings::e_frame_scale; + } else { + design_aspect_ratio = design_width/design_height; + } + + + ComputeDefaultOrtho( + camnear, + camfar, + scale, + design_aspect_ratio, + frustum + ); + + switch (type) { + + case RAS_FrameSettings::e_frame_extend: + { + RAS_Rect vt; + ComputeBestFitViewRect( + availableViewport, + design_aspect_ratio, + vt + ); + + // now scale the calculated frustum by the difference + // between vt and the viewport in each axis. + // These are always > 1 + + float x_scale = float(viewport.GetWidth())/float(vt.GetWidth()); + float y_scale = float(viewport.GetHeight())/float(vt.GetHeight()); + + frustum.x1 *= x_scale; + frustum.x2 *= x_scale; + frustum.y1 *= y_scale; + frustum.y2 *= y_scale; + + break; + } + case RAS_FrameSettings::e_frame_scale : + case RAS_FrameSettings::e_frame_bars: + default : + break; + } + +} diff --git a/source/gameengine/Rasterizer/RAS_FramingManager.h b/source/gameengine/Rasterizer/RAS_FramingManager.h index 9cb59f300f7..3ae794c430a 100644 --- a/source/gameengine/Rasterizer/RAS_FramingManager.h +++ b/source/gameengine/Rasterizer/RAS_FramingManager.h @@ -29,6 +29,10 @@ #ifndef RAS_FRAMINGMANAGER_H #define RAS_FRAMINGMANAGER_H +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class RAS_Rect; /** @@ -55,7 +59,6 @@ class RAS_Rect; class RAS_FrameSettings { public : - /** * enum defining the policy to use * in each axis. @@ -154,6 +157,13 @@ private : float m_bar_b; unsigned int m_design_aspect_width; unsigned int m_design_aspect_height; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_FrameSettings"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; struct RAS_FrameFrustum @@ -163,6 +173,13 @@ struct RAS_FrameFrustum float x2,y2; }; +/* must match R_CULLING_... from DNA_scene_types.h */ +enum RAS_CullingMode +{ + RAS_CULLING_DBVT = 0, + RAS_CULLING_NORMAL, + RAS_CULLING_NONE +}; /** * @section RAS_FramingManager @@ -202,6 +219,18 @@ public : static void + ComputeOrtho( + const RAS_FrameSettings &settings, + const RAS_Rect &availableViewport, + const RAS_Rect &viewport, + const float scale, + const float camnear, + const float camfar, + RAS_FrameFrustum &frustum + ); + + static + void ComputeFrustum( const RAS_FrameSettings &settings, const RAS_Rect &availableViewport, @@ -212,9 +241,6 @@ public : RAS_FrameFrustum &frustum ); - -private : - static void ComputeDefaultFrustum( @@ -227,6 +253,18 @@ private : static void + ComputeDefaultOrtho( + const float camnear, + const float camfar, + const float scale, + const float design_aspect_ratio, + RAS_FrameFrustum & frustum + ); + +private : + + static + void ComputeBestFitViewRect( const RAS_Rect &availableViewport, const float design_aspect_ratio, @@ -246,6 +284,13 @@ private : RAS_FramingManager( const RAS_FramingManager & ); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_FramingManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Rasterizer/RAS_ICanvas.h b/source/gameengine/Rasterizer/RAS_ICanvas.h index f3f817a943d..dae4fb3f4d2 100644 --- a/source/gameengine/Rasterizer/RAS_ICanvas.h +++ b/source/gameengine/Rasterizer/RAS_ICanvas.h @@ -33,6 +33,10 @@ * 2D rendering device context. The connection from 3d rendercontext to 2d surface. */ +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class RAS_Rect; @@ -173,6 +177,13 @@ public: MakeScreenShot( const char* filename )=0; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_ICanvas"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__RAS_ICANVAS diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp index fb3607f89f4..033daabc48f 100644 --- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp +++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp @@ -29,20 +29,75 @@ #include "RAS_IPolygonMaterial.h" #include "RAS_IRasterizer.h" +#include "DNA_image_types.h" +#include "DNA_meshdata_types.h" + #ifdef HAVE_CONFIG_H #include <config.h> #endif +void RAS_IPolyMaterial::Initialize( + const STR_String& texname, + const STR_String& matname, + int materialindex, + int tile, + int tilexrep, + int tileyrep, + int mode, + int transp, + bool alpha, + bool zsort) +{ + m_texturename = texname; + m_materialname = matname; + m_materialindex = materialindex; + m_tile = tile; + m_tilexrep = tilexrep; + m_tileyrep = tileyrep; + m_drawingmode = mode; + m_transp = transp; + m_alpha = alpha; + m_zsort = zsort; + m_polymatid = m_newpolymatid++; + m_flag = 0; + m_multimode = 0; + m_shininess = 35.0; + m_specular.setValue(0.5,0.5,0.5); + m_specularity = 1.0; + m_diffuse.setValue(0.5,0.5,0.5); +} + +RAS_IPolyMaterial::RAS_IPolyMaterial() + : m_texturename("__Dummy_Texture_Name__"), + m_materialname("__Dummy_Material_Name__"), + m_tile(0), + m_tilexrep(0), + m_tileyrep(0), + m_drawingmode (0), + m_transp(0), + m_alpha(false), + m_zsort(false), + m_materialindex(0), + m_polymatid(0), + m_flag(0), + m_multimode(0) +{ + m_shininess = 35.0; + m_specular = MT_Vector3(0.5,0.5,0.5); + m_specularity = 1.0; + m_diffuse = MT_Vector3(0.5,0.5,0.5); +} + RAS_IPolyMaterial::RAS_IPolyMaterial(const STR_String& texname, const STR_String& matname, + int materialindex, int tile, int tilexrep, int tileyrep, int mode, int transp, bool alpha, - bool zsort, - int lightlayer) + bool zsort) : m_texturename(texname), m_materialname(matname), m_tile(tile), @@ -52,7 +107,7 @@ RAS_IPolyMaterial::RAS_IPolyMaterial(const STR_String& texname, m_transp(transp), m_alpha(alpha), m_zsort(zsort), - m_lightlayer(lightlayer), + m_materialindex(materialindex), m_polymatid(m_newpolymatid++), m_flag(0), m_multimode(0) @@ -95,6 +150,15 @@ bool RAS_IPolyMaterial::Equals(const RAS_IPolyMaterial& lhs) const } } + +void RAS_IPolyMaterial::GetMaterialRGBAColor(unsigned char *rgba) const +{ + *rgba++ = 0xFF; + *rgba++ = 0xFF; + *rgba++ = 0xFF; + *rgba++ = 0xFF; +} + bool RAS_IPolyMaterial::Less(const RAS_IPolyMaterial& rhs) const { if (Equals(rhs)) @@ -103,11 +167,6 @@ bool RAS_IPolyMaterial::Less(const RAS_IPolyMaterial& rhs) const return m_polymatid < rhs.m_polymatid; } -int RAS_IPolyMaterial::GetLightLayer() const -{ - return m_lightlayer; -} - bool RAS_IPolyMaterial::IsAlpha() const { return m_alpha || m_zsort; @@ -143,7 +202,26 @@ const STR_String& RAS_IPolyMaterial::GetTextureName() const return m_texturename; } -const unsigned int RAS_IPolyMaterial::GetFlag() const +int RAS_IPolyMaterial::GetMaterialIndex() const +{ + return m_materialindex; +} + +Material *RAS_IPolyMaterial::GetBlenderMaterial() const +{ + return NULL; +} + +Scene* RAS_IPolyMaterial::GetBlenderScene() const +{ + return NULL; +} + +void RAS_IPolyMaterial::ReleaseMaterial() +{ +} + +unsigned int RAS_IPolyMaterial::GetFlag() const { return m_flag; } diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h index 218dd91cb30..af909dfa731 100644 --- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h +++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h @@ -38,7 +38,14 @@ #include "MT_Vector3.h" #include "STR_HashedString.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class RAS_IRasterizer; +struct MTFace; +struct Material; +struct Scene; enum MaterialProps { @@ -70,7 +77,7 @@ protected: int m_transp; bool m_alpha; bool m_zsort; - int m_lightlayer; + int m_materialindex; unsigned int m_polymatid; static unsigned int m_newpolymatid; @@ -79,7 +86,6 @@ protected: unsigned int m_flag;//MaterialProps int m_multimode; // sum of values public: - MT_Vector3 m_diffuse; float m_shininess; MT_Vector3 m_specular; @@ -96,16 +102,27 @@ public: SHADOW =8192 }; + RAS_IPolyMaterial(); RAS_IPolyMaterial(const STR_String& texname, const STR_String& matname, + int materialindex, int tile, int tilexrep, int tileyrep, int mode, int transp, bool alpha, - bool zsort, - int lightlayer); + bool zsort); + void Initialize(const STR_String& texname, + const STR_String& matname, + int materialindex, + int tile, + int tilexrep, + int tileyrep, + int mode, + int transp, + bool alpha, + bool zsort); virtual ~RAS_IPolyMaterial() {}; /** @@ -130,7 +147,7 @@ public: virtual bool Equals(const RAS_IPolyMaterial& lhs) const; bool Less(const RAS_IPolyMaterial& rhs) const; - int GetLightLayer() const; + //int GetLightLayer() const; bool IsAlpha() const; bool IsZSort() const; unsigned int hash() const; @@ -138,15 +155,26 @@ public: const STR_String& GetMaterialName() const; dword GetMaterialNameHash() const; const STR_String& GetTextureName() const; - const unsigned int GetFlag() const; + unsigned int GetFlag() const; + int GetMaterialIndex() const; + virtual Material* GetBlenderMaterial() const; + virtual Scene* GetBlenderScene() const; + virtual void ReleaseMaterial(); + virtual void GetMaterialRGBAColor(unsigned char *rgba) const; virtual bool UsesLighting(RAS_IRasterizer *rasty) const; virtual bool UsesObjectColor() const; - /* * PreCalculate texture gen */ - virtual void OnConstruction(){} + virtual void OnConstruction(int layer){} + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_IPolyMaterial"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; inline bool operator ==( const RAS_IPolyMaterial & rhs,const RAS_IPolyMaterial & lhs) diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h index 411b28fa3b7..05406413941 100644 --- a/source/gameengine/Rasterizer/RAS_IRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h @@ -43,6 +43,10 @@ #include <vector> using namespace std; +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class RAS_ICanvas; class RAS_IPolyMaterial; @@ -57,7 +61,6 @@ typedef vector< KX_IndexArray* > vecIndexArrays; class RAS_IRasterizer { public: - RAS_IRasterizer(RAS_ICanvas* canv){}; virtual ~RAS_IRasterizer(){}; /** @@ -113,6 +116,7 @@ public: RAS_STEREO_ANAGLYPH, RAS_STEREO_SIDEBYSIDE, RAS_STEREO_VINTERLACE, + RAS_STEREO_DOME, RAS_STEREO_MAXSTEREO }; @@ -200,6 +204,7 @@ public: * @return true if stereo mode is enabled. */ virtual bool Stereo()=0; + virtual StereoMode GetStereoMode()=0; virtual bool InterlacedStereo()=0; /** * Sets which eye buffer subsequent primitives will be rendered to. @@ -248,12 +253,14 @@ public: * Sets the modelview matrix. */ virtual void SetViewMatrix(const MT_Matrix4x4 & mat, - const MT_Vector3& campos, - const MT_Point3 &camLoc, - const MT_Quaternion &camOrientQuat)=0; + const MT_Matrix3x3 & ori, + const MT_Point3 & pos, + bool perspective)=0; /** */ virtual const MT_Point3& GetCameraPosition()=0; + virtual bool GetCameraOrtho()=0; + /** */ virtual void SetFog(float start, @@ -276,6 +283,7 @@ public: /** */ virtual void DisableFog()=0; + virtual bool IsFogEnabled()=0; virtual void SetBackColor(float red, float green, @@ -321,6 +329,26 @@ public: float focallength = 0.0f, bool perspective = true )=0; + + /** + * Generates a orthographic projection matrix from the specified frustum. + * @param left the left clipping plane + * @param right the right clipping plane + * @param bottom the bottom clipping plane + * @param top the top clipping plane + * @param frustnear the near clipping plane + * @param frustfar the far clipping plane + * @return a 4x4 matrix representing the projection transform. + */ + virtual MT_Matrix4x4 GetOrthoMatrix( + float left, + float right, + float bottom, + float top, + float frustnear, + float frustfar + )=0; + /** * Sets the specular color component of the lighting equation. */ @@ -358,6 +386,8 @@ public: virtual void SetPolygonOffset(float mult, float add) = 0; virtual void DrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color)=0; + virtual void FlushDebugLines()=0; + virtual void SetTexCoordNum(int num) = 0; @@ -380,6 +410,13 @@ public: virtual void SetBlendingMode(int blendmode)=0; virtual void SetFrontFace(bool ccw)=0; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_IRasterizer"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__RAS_IRASTERIZER diff --git a/source/gameengine/Rasterizer/RAS_IRenderTools.h b/source/gameengine/Rasterizer/RAS_IRenderTools.h index 57f331e64cb..5d52ddc9688 100644 --- a/source/gameengine/Rasterizer/RAS_IRenderTools.h +++ b/source/gameengine/Rasterizer/RAS_IRenderTools.h @@ -36,6 +36,10 @@ #include <vector> #include <algorithm> +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class RAS_IPolyMaterial; struct RAS_LightObject; @@ -58,10 +62,6 @@ public: RAS_TEXT_PADDED, RAS_TEXT_MAX }; - enum RAS_LIGHT_MODE { - RAS_LIGHT_NONE = -1, - RAS_LIGHT_OBJECT_LAYER = 0 - }; RAS_IRenderTools( ) : @@ -134,7 +134,8 @@ public: virtual void ProcessLighting( - int layer, + RAS_IRasterizer *rasty, + bool uselights, const MT_Transform& trans )=0; @@ -183,6 +184,13 @@ public: virtual void Render2DFilters(RAS_ICanvas* canvas)=0; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_IRenderTools"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__RAS_IRENDERTOOLS diff --git a/source/gameengine/Rasterizer/RAS_LightObject.h b/source/gameengine/Rasterizer/RAS_LightObject.h index 4c54857dc39..b45a35e4266 100644 --- a/source/gameengine/Rasterizer/RAS_LightObject.h +++ b/source/gameengine/Rasterizer/RAS_LightObject.h @@ -39,7 +39,9 @@ struct RAS_LightObject LIGHT_NORMAL }; bool m_modified; - int m_layer; + int m_layer; + void *m_scene; + void *m_light; float m_energy; float m_distance; @@ -54,7 +56,6 @@ struct RAS_LightObject float m_spotblend; LightType m_type; - MT_CmMatrix4x4* m_worldmatrix; bool m_nodiffuse; bool m_nospecular; diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp index ad8d7ebd5b0..8e90c9a1c08 100644 --- a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp +++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp @@ -42,7 +42,7 @@ /* mesh slot */ -RAS_MeshSlot::RAS_MeshSlot() +RAS_MeshSlot::RAS_MeshSlot() : SG_QList() { m_clientObj = NULL; m_pDeformer = NULL; @@ -56,16 +56,19 @@ RAS_MeshSlot::RAS_MeshSlot() m_DisplayList = NULL; m_bDisplayList = true; m_joinSlot = NULL; + m_pDerivedMesh = NULL; } RAS_MeshSlot::~RAS_MeshSlot() { - vector<RAS_DisplayArray*>::iterator it; + RAS_DisplayArrayList::iterator it; +#ifdef USE_SPLIT Split(true); while(m_joinedSlots.size()) m_joinedSlots.front()->Split(true); +#endif for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { (*it)->m_users--; @@ -79,12 +82,13 @@ RAS_MeshSlot::~RAS_MeshSlot() } } -RAS_MeshSlot::RAS_MeshSlot(const RAS_MeshSlot& slot) +RAS_MeshSlot::RAS_MeshSlot(const RAS_MeshSlot& slot) : SG_QList() { - vector<RAS_DisplayArray*>::iterator it; + RAS_DisplayArrayList::iterator it; m_clientObj = NULL; m_pDeformer = NULL; + m_pDerivedMesh = NULL; m_OpenGLMatrix = NULL; m_mesh = slot.m_mesh; m_bucket = slot.m_bucket; @@ -203,7 +207,7 @@ RAS_DisplayArray *RAS_MeshSlot::CurrentDisplayArray() void RAS_MeshSlot::SetDisplayArray(int numverts) { - vector<RAS_DisplayArray*>::iterator it; + RAS_DisplayArrayList::iterator it; RAS_DisplayArray *darray = NULL; for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { @@ -277,6 +281,63 @@ void RAS_MeshSlot::AddPolygonVertex(int offset) m_endindex++; } +void RAS_MeshSlot::SetDeformer(RAS_Deformer* deformer) +{ + if (deformer && m_pDeformer != deformer) { + RAS_DisplayArrayList::iterator it; + if (deformer->ShareVertexArray()) { + // this deformer uses the base vertex array, first release the current ones + for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { + (*it)->m_users--; + if((*it)->m_users == 0) + delete *it; + } + m_displayArrays.clear(); + // then hook to the base ones + RAS_MeshMaterial *mmat = m_mesh->GetMeshMaterial(m_bucket->GetPolyMaterial()); + if (mmat && mmat->m_baseslot) { + m_displayArrays = mmat->m_baseslot->m_displayArrays; + for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { + (*it)->m_users++; + } + } + } + else { + // no sharing + // we create local copy of RAS_DisplayArray when we have a deformer: + // this way we can avoid conflict between the vertex cache of duplicates + for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { + if (deformer->UseVertexArray()) { + // the deformer makes use of vertex array, make sure we have our local copy + if ((*it)->m_users > 1) { + // only need to copy if there are other users + // note that this is the usual case as vertex arrays are held by the material base slot + RAS_DisplayArray *newarray = new RAS_DisplayArray(*(*it)); + newarray->m_users = 1; + (*it)->m_users--; + *it = newarray; + } + } else { + // the deformer is not using vertex array (Modifier), release them + (*it)->m_users--; + if((*it)->m_users == 0) + delete *it; + } + } + if (!deformer->UseVertexArray()) { + m_displayArrays.clear(); + m_startarray = 0; + m_startvertex = 0; + m_startindex = 0; + m_endarray = 0; + m_endvertex = 0; + m_endindex = 0; + } + } + } + m_pDeformer = deformer; +} + bool RAS_MeshSlot::Equals(RAS_MeshSlot *target) { if(!m_OpenGLMatrix || !target->m_OpenGLMatrix) @@ -295,7 +356,7 @@ bool RAS_MeshSlot::Equals(RAS_MeshSlot *target) bool RAS_MeshSlot::Join(RAS_MeshSlot *target, MT_Scalar distance) { - vector<RAS_DisplayArray*>::iterator it; + RAS_DisplayArrayList::iterator it; iterator mit; size_t i; @@ -330,6 +391,9 @@ bool RAS_MeshSlot::Join(RAS_MeshSlot *target, MT_Scalar distance) for(begin(mit); !end(mit); next(mit)) for(i=mit.startvertex; i<mit.endvertex; i++) mit.vertex[i].Transform(transform, ntransform); + + /* We know we'll need a list at least this big, reserve in advance */ + target->m_displayArrays.reserve(target->m_displayArrays.size() + m_displayArrays.size()); for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { target->m_displayArrays.push_back(*it); @@ -357,7 +421,7 @@ bool RAS_MeshSlot::Split(bool force) { list<RAS_MeshSlot*>::iterator jit; RAS_MeshSlot *target = m_joinSlot; - vector<RAS_DisplayArray*>::iterator it, jt; + RAS_DisplayArrayList::iterator it, jt; iterator mit; size_t i, found0 = 0, found1 = 0; @@ -417,21 +481,21 @@ bool RAS_MeshSlot::Split(bool force) return false; } + +#ifdef USE_SPLIT bool RAS_MeshSlot::IsCulled() { - list<RAS_MeshSlot*>::iterator it; - if(m_joinSlot) return true; if(!m_bCulled) return false; - + list<RAS_MeshSlot*>::iterator it; for(it=m_joinedSlots.begin(); it!=m_joinedSlots.end(); it++) if(!(*it)->m_bCulled) return false; - return true; } +#endif /* material bucket sorting */ @@ -513,13 +577,13 @@ list<RAS_MeshSlot>::iterator RAS_MaterialBucket::msEnd() bool RAS_MaterialBucket::ActivateMaterial(const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools *rendertools) { - if (!rasty->SetMaterial(*m_material)) + bool uselights; + + if(!rasty->SetMaterial(*m_material)) return false; - if (m_material->UsesLighting(rasty)) - rendertools->ProcessLighting(RAS_IRenderTools::RAS_LIGHT_OBJECT_LAYER, cameratrans); - else - rendertools->ProcessLighting(-1, cameratrans); + uselights= m_material->UsesLighting(rasty); + rendertools->ProcessLighting(rasty, uselights, cameratrans); return true; } @@ -553,7 +617,7 @@ void RAS_MaterialBucket::RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRa // then it won't have texture coordinates for actual drawing. also // for zsort we can't make a display list, since the polygon order // changes all the time. - if(ms.m_pDeformer) + if(ms.m_pDeformer && ms.m_pDeformer->IsDynamic()) ms.m_bDisplayList = false; else if(!ms.m_DisplayList && rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW) ms.m_bDisplayList = false; diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.h b/source/gameengine/Rasterizer/RAS_MaterialBucket.h index 475f01d549a..dc9abbfbddf 100644 --- a/source/gameengine/Rasterizer/RAS_MaterialBucket.h +++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.h @@ -32,6 +32,7 @@ #include "RAS_TexVert.h" #include "GEN_Map.h" #include "STR_HashedString.h" +#include "SG_QList.h" #include "MT_Transform.h" #include "RAS_IPolygonMaterial.h" @@ -69,6 +70,7 @@ class RAS_DisplayArray; class RAS_MeshSlot; class RAS_MeshMaterial; class RAS_MaterialBucket; +struct DerivedMesh; /* An array with data used for OpenGL drawing */ @@ -77,8 +79,11 @@ class RAS_DisplayArray public: vector<RAS_TexVert> m_vertex; vector<unsigned short> m_index; + /* LINE currently isnt used */ enum { LINE = 2, TRIANGLE = 3, QUAD = 4 } m_type; //RAS_MeshSlot *m_origSlot; + + /* Number of RAS_MeshSlot using this array */ int m_users; enum { BUCKET_MAX_INDEX = 65535 }; @@ -86,9 +91,13 @@ public: }; /* Entry of a RAS_MeshObject into RAS_MaterialBucket */ +typedef std::vector<RAS_DisplayArray*> RAS_DisplayArrayList; -class RAS_MeshSlot +// The QList is used to link the mesh slots to the object +// The DList is used to link the visible mesh slots to the material bucket +class RAS_MeshSlot : public SG_QList { + friend class RAS_ListRasterizer; private: // indices into display arrays int m_startarray; @@ -97,7 +106,7 @@ private: int m_endindex; int m_startvertex; int m_endvertex; - vector<RAS_DisplayArray*> m_displayArrays; + RAS_DisplayArrayList m_displayArrays; // for construction only RAS_DisplayArray* m_currentArray; @@ -108,6 +117,7 @@ public: RAS_MeshObject* m_mesh; void* m_clientObj; RAS_Deformer* m_pDeformer; + DerivedMesh* m_pDerivedMesh; double* m_OpenGLMatrix; // visibility bool m_bVisible; @@ -146,6 +156,7 @@ public: /* used during construction */ void SetDisplayArray(int numverts); RAS_DisplayArray *CurrentDisplayArray(); + void SetDeformer(RAS_Deformer* deformer); void AddPolygon(int numverts); int AddVertex(const RAS_TexVert& tv); @@ -155,7 +166,19 @@ public: bool Split(bool force=false); bool Join(RAS_MeshSlot *target, MT_Scalar distance); bool Equals(RAS_MeshSlot *target); +#ifdef USE_SPLIT bool IsCulled(); +#else + bool IsCulled() { return m_bCulled; } +#endif + void SetCulled(bool culled) { m_bCulled = culled; } + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_MeshSlot"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; /* Used by RAS_MeshObject, to point to it's slots in a bucket */ @@ -165,8 +188,14 @@ class RAS_MeshMaterial public: RAS_MeshSlot *m_baseslot; class RAS_MaterialBucket *m_bucket; - GEN_Map<GEN_HashedPtr,RAS_MeshSlot*> m_slots; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_MeshMaterial"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; /* Contains a list of display arrays with the same material, @@ -202,11 +231,30 @@ public: class RAS_MeshSlot* CopyMesh(class RAS_MeshSlot *ms); void RemoveMesh(class RAS_MeshSlot* ms); void Optimize(MT_Scalar distance); + void ActivateMesh(RAS_MeshSlot* slot) + { + m_activeMeshSlotsHead.AddBack(slot); + } + SG_DList& GetActiveMeshSlots() + { + return m_activeMeshSlotsHead; + } + RAS_MeshSlot* GetNextActiveMeshSlot() + { + return (RAS_MeshSlot*)m_activeMeshSlotsHead.Remove(); + } private: - list<RAS_MeshSlot> m_meshSlots; + list<RAS_MeshSlot> m_meshSlots; // all the mesh slots RAS_IPolyMaterial* m_material; + SG_DList m_activeMeshSlotsHead; // only those which must be rendered + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_MaterialBucket"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__RAS_MATERIAL_BUCKET diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.cpp b/source/gameengine/Rasterizer/RAS_MeshObject.cpp index a907994bf57..0995d5acdd5 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.cpp +++ b/source/gameengine/Rasterizer/RAS_MeshObject.cpp @@ -90,9 +90,8 @@ struct RAS_MeshObject::fronttoback STR_String RAS_MeshObject::s_emptyname = ""; -RAS_MeshObject::RAS_MeshObject(Mesh* mesh, int lightlayer) - : m_lightlayer(lightlayer), - m_bModified(true), +RAS_MeshObject::RAS_MeshObject(Mesh* mesh) + : m_bModified(true), m_bMeshModified(true), m_mesh(mesh), m_bDeformed(false) @@ -112,10 +111,10 @@ bool RAS_MeshObject::MeshModified() return m_bMeshModified; } -unsigned int RAS_MeshObject::GetLightLayer() -{ - return m_lightlayer; -} +//unsigned int RAS_MeshObject::GetLightLayer() +//{ +// return m_lightlayer; +//} @@ -179,14 +178,14 @@ list<RAS_MeshMaterial>::iterator RAS_MeshObject::GetLastMaterial() -void RAS_MeshObject::SetName(STR_String name) +void RAS_MeshObject::SetName(const char *name) { m_name = name; } -const STR_String& RAS_MeshObject::GetName() +STR_String& RAS_MeshObject::GetName() { return m_name; } @@ -215,6 +214,19 @@ RAS_MeshMaterial *RAS_MeshObject::GetMeshMaterial(RAS_IPolyMaterial *mat) return NULL; } +int RAS_MeshObject::GetMaterialId(RAS_IPolyMaterial *mat) +{ + list<RAS_MeshMaterial>::iterator mit; + int imat; + + /* find a mesh material */ + for(imat=0, mit = m_materials.begin(); mit != m_materials.end(); mit++, imat++) + if(mit->m_bucket->GetPolyMaterial() == mat) + return imat; + + return -1; +} + RAS_Polygon* RAS_MeshObject::AddPolygon(RAS_MaterialBucket *bucket, int numverts) { RAS_MeshMaterial *mmat; @@ -229,6 +241,7 @@ RAS_Polygon* RAS_MeshObject::AddPolygon(RAS_MaterialBucket *bucket, int numverts RAS_MeshMaterial meshmat; meshmat.m_bucket = bucket; meshmat.m_baseslot = meshmat.m_bucket->AddMesh(numverts); + meshmat.m_baseslot->m_mesh = this; m_materials.push_back(meshmat); mmat = &m_materials.back(); } @@ -291,7 +304,7 @@ void RAS_MeshObject::AddVertex(RAS_Polygon *poly, int i, slot = mmat->m_baseslot; darray = slot->CurrentDisplayArray(); - if(!flat) { + { /* Shared Vertex! */ /* find vertices shared between faces, with the restriction * that they exist in the same display array, and have the * same uv coordinate etc */ @@ -319,7 +332,7 @@ void RAS_MeshObject::AddVertex(RAS_Polygon *poly, int i, slot->AddPolygonVertex(offset); poly->SetVertexOffset(i, offset); - if(!flat) { + { /* Shared Vertex! */ SharedVertex shared; shared.m_darray = darray; shared.m_offset = offset; @@ -368,16 +381,48 @@ RAS_TexVert* RAS_MeshObject::GetVertex(unsigned int matid, return NULL; } -void RAS_MeshObject::AddMeshUser(void *clientobj) +const float* RAS_MeshObject::GetVertexLocation(unsigned int orig_index) +{ + vector<SharedVertex>& sharedmap = m_sharedvertex_map[orig_index]; + vector<SharedVertex>::iterator it= sharedmap.begin(); + return it->m_darray->m_vertex[it->m_offset].getXYZ(); +} + +void RAS_MeshObject::AddMeshUser(void *clientobj, SG_QList *head, RAS_Deformer* deformer) { list<RAS_MeshMaterial>::iterator it; + list<RAS_MeshMaterial>::iterator mit; for(it = m_materials.begin();it!=m_materials.end();++it) { /* always copy from the base slot, which is never removed * since new objects can be created with the same mesh data */ + if (deformer && !deformer->UseVertexArray()) + { + // HACK! + // this deformer doesn't use vertex array => derive mesh + // we must keep only the mesh slots that have unique material id + // this is to match the derived mesh drawing function + // Need a better solution in the future: scan the derive mesh and create vertex array + RAS_IPolyMaterial* curmat = it->m_bucket->GetPolyMaterial(); + if (curmat->GetFlag() & RAS_BLENDERGLSL) + { + for(mit = m_materials.begin(); mit != it; ++mit) + { + RAS_IPolyMaterial* mat = mit->m_bucket->GetPolyMaterial(); + if ((mat->GetFlag() & RAS_BLENDERGLSL) && + mat->GetMaterialIndex() == curmat->GetMaterialIndex()) + // no need to convert current mesh slot + break; + } + if (mit != it) + continue; + } + } RAS_MeshSlot *ms = it->m_bucket->CopyMesh(it->m_baseslot); ms->m_clientObj = clientobj; + ms->SetDeformer(deformer); it->m_slots.insert(clientobj, ms); + head->QAddBack(ms); } } @@ -389,7 +434,7 @@ void RAS_MeshObject::UpdateBuckets(void* clientobj, bool culled) { list<RAS_MeshMaterial>::iterator it; - + for(it = m_materials.begin();it!=m_materials.end();++it) { RAS_MeshSlot **msp = it->m_slots[clientobj]; @@ -404,9 +449,13 @@ void RAS_MeshObject::UpdateBuckets(void* clientobj, ms->m_RGBAcolor = rgbavec; ms->m_bVisible = visible; ms->m_bCulled = culled || !visible; + if (!ms->m_bCulled) + ms->m_bucket->ActivateMesh(ms); /* split if necessary */ +#ifdef USE_SPLIT ms->Split(); +#endif } } diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.h b/source/gameengine/Rasterizer/RAS_MeshObject.h index 0d35a2f402b..1738423c4f3 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.h +++ b/source/gameengine/Rasterizer/RAS_MeshObject.h @@ -45,6 +45,7 @@ #include "GEN_HashedPtr.h" struct Mesh; +class RAS_Deformer; /* RAS_MeshObject is a mesh used for rendering. It stores polygons, * but the actual vertices and index arrays are stored in material @@ -54,7 +55,6 @@ class RAS_MeshObject { private: unsigned int m_debugcolor; - int m_lightlayer; bool m_bModified; bool m_bMeshModified; @@ -76,7 +76,7 @@ protected: public: // for now, meshes need to be in a certain layer (to avoid sorting on lights in realtime) - RAS_MeshObject(Mesh* mesh, int lightlayer); + RAS_MeshObject(Mesh* mesh); virtual ~RAS_MeshObject(); @@ -89,15 +89,16 @@ public: RAS_MeshMaterial* GetMeshMaterial(unsigned int matid); RAS_MeshMaterial* GetMeshMaterial(RAS_IPolyMaterial *mat); + int GetMaterialId(RAS_IPolyMaterial *mat); list<RAS_MeshMaterial>::iterator GetFirstMaterial(); list<RAS_MeshMaterial>::iterator GetLastMaterial(); - unsigned int GetLightLayer(); + //unsigned int GetLightLayer(); /* name */ - void SetName(STR_String name); - const STR_String& GetName(); + void SetName(const char *name); + STR_String& GetName(); /* modification state */ bool MeshModified(); @@ -124,12 +125,13 @@ public: /* vertex and polygon acces */ int NumVertices(RAS_IPolyMaterial* mat); RAS_TexVert* GetVertex(unsigned int matid, unsigned int index); + const float* GetVertexLocation(unsigned int orig_index); int NumPolygons(); RAS_Polygon* GetPolygon(int num) const; /* buckets */ - virtual void AddMeshUser(void *clientobj); + virtual void AddMeshUser(void *clientobj, SG_QList *head, RAS_Deformer* deformer); virtual void UpdateBuckets( void* clientobj, double* oglmatrix, @@ -139,6 +141,13 @@ public: bool culled); void RemoveFromBuckets(void *clientobj); + void EndConversion() { +#if 0 + m_sharedvertex_map.clear(); // SharedVertex + vector<vector<SharedVertex> > shared_null(0); + shared_null.swap( m_sharedvertex_map ); /* really free the memory */ +#endif + } /* colors */ void DebugColor(unsigned int abgr); @@ -147,6 +156,16 @@ public: /* polygon sorting by Z for alpha */ void SortPolygons(RAS_MeshSlot& ms, const MT_Transform &transform); + + bool HasColliderPolygon() { + int numpolys= NumPolygons(); + for (int p=0; p<numpolys; p++) + if (m_Polygons[p]->IsCollider()) + return true; + + return false; + } + /* for construction to find shared vertices */ struct SharedVertex { RAS_DisplayArray *m_darray; @@ -154,6 +173,13 @@ public: }; vector<vector<SharedVertex> > m_sharedvertex_map; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_MeshObject"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__RAS_MESHOBJECT diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt index e4403ace69f..f2b97bedb2f 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt @@ -27,12 +27,18 @@ FILE(GLOB SRC *.cpp) SET(INC - ../../../../source/kernel/gen_system - ../../../../intern/string - ../../../../intern/moto/include - ../../../../source/gameengine/Rasterizer - ../../../../extern/glew/include - ../../../../source/blender/gpu + ../../../../source/kernel/gen_system + ../../../../intern/string + ../../../../intern/moto/include + ../../../../source/gameengine/Rasterizer + ../../../../source/gameengine/Ketsji + ../../../../source/gameengine/SceneGraph + ../../../../extern/glew/include + ../../../../source/blender/gpu + ../../../../source/blender/makesdna + ../../../../source/blender/blenkernel + ../../../../source/blender/blenlib + ../../../../source/blender/blenloader ) BLENDERLIB(bf_oglrasterizer "${SRC}" "${INC}") diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile index aee485a22be..0327714dc5f 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile @@ -42,8 +42,14 @@ CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I../../../kernel/gen_system CPPFLAGS += -I../../../blender/gpu +CPPFLAGS += -I../../../blender/makesdna +CPPFLAGS += -I../../../blender/blenlib +CPPFLAGS += -I../../../blender/blenkernel CPPFLAGS += -I../../BlenderRoutines +CPPFLAGS += -I../../Ketsji +CPPFLAGS += -I../../SceneGraph CPPFLAGS += -I.. +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include ifeq ($(OS),darwin) CPPFLAGS += -fpascal-strings diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp index 2c4b55ff964..014169f8838 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp @@ -104,9 +104,11 @@ bool RAS_ListSlot::End() RAS_ListRasterizer::RAS_ListRasterizer(RAS_ICanvas* canvas, bool useVertexArrays, bool lock) : RAS_VAOpenGLRasterizer(canvas, lock), - mUseVertexArrays(useVertexArrays) + mUseVertexArrays(useVertexArrays), + mATI(false) { - // -- + if (!strcmp((const char*)glGetString(GL_VENDOR), "ATI Technologies Inc.")) + mATI = true; } RAS_ListRasterizer::~RAS_ListRasterizer() @@ -116,13 +118,24 @@ RAS_ListRasterizer::~RAS_ListRasterizer() void RAS_ListRasterizer::RemoveListSlot(RAS_ListSlot* list) { - RAS_Lists::iterator it = mLists.begin(); - while(it != mLists.end()) { - if (it->second == list) { - mLists.erase(it); - break; + if (list->m_flag & LIST_DERIVEDMESH) { + RAS_DerivedMeshLists::iterator it = mDerivedMeshLists.begin(); + while(it != mDerivedMeshLists.end()) { + if (it->second == list) { + mDerivedMeshLists.erase(it); + break; + } + it++; + } + } else { + RAS_ArrayLists::iterator it = mArrayLists.begin(); + while(it != mArrayLists.end()) { + if (it->second == list) { + mArrayLists.erase(it); + break; + } + it++; } - it++; } } @@ -136,12 +149,25 @@ RAS_ListSlot* RAS_ListRasterizer::FindOrAdd(RAS_MeshSlot& ms) */ RAS_ListSlot* localSlot = (RAS_ListSlot*)ms.m_DisplayList; if(!localSlot) { - RAS_Lists::iterator it = mLists.find(&ms); - if(it == mLists.end()) { - localSlot = new RAS_ListSlot(this); - mLists.insert(std::pair<RAS_MeshSlot*, RAS_ListSlot*>(&ms, localSlot)); + if (ms.m_pDerivedMesh) { + // that means that we draw based on derived mesh, a display list is possible + // Note that we come here only for static derived mesh + RAS_DerivedMeshLists::iterator it = mDerivedMeshLists.find(ms.m_pDerivedMesh); + if(it == mDerivedMeshLists.end()) { + localSlot = new RAS_ListSlot(this); + localSlot->m_flag |= LIST_DERIVEDMESH; + mDerivedMeshLists.insert(std::pair<DerivedMesh*, RAS_ListSlot*>(ms.m_pDerivedMesh, localSlot)); + } else { + localSlot = static_cast<RAS_ListSlot*>(it->second->AddRef()); + } } else { - localSlot = static_cast<RAS_ListSlot*>(it->second->AddRef()); + RAS_ArrayLists::iterator it = mArrayLists.find(ms.m_displayArrays); + if(it == mArrayLists.end()) { + localSlot = new RAS_ListSlot(this); + mArrayLists.insert(std::pair<RAS_DisplayArrayList, RAS_ListSlot*>(ms.m_displayArrays, localSlot)); + } else { + localSlot = static_cast<RAS_ListSlot*>(it->second->AddRef()); + } } } MT_assert(localSlot); @@ -150,12 +176,12 @@ RAS_ListSlot* RAS_ListRasterizer::FindOrAdd(RAS_MeshSlot& ms) void RAS_ListRasterizer::ReleaseAlloc() { - RAS_Lists::iterator it = mLists.begin(); - while(it != mLists.end()) { + for(RAS_ArrayLists::iterator it = mArrayLists.begin();it != mArrayLists.end();++it) delete it->second; - it++; - } - mLists.clear(); + mArrayLists.clear(); + for (RAS_DerivedMeshLists::iterator it = mDerivedMeshLists.begin();it != mDerivedMeshLists.end();++it) + delete it->second; + mDerivedMeshLists.clear(); } void RAS_ListRasterizer::IndexPrimitives(RAS_MeshSlot& ms) @@ -172,8 +198,8 @@ void RAS_ListRasterizer::IndexPrimitives(RAS_MeshSlot& ms) return; } } - - if (mUseVertexArrays) + // derived mesh cannot use vertex array + if (mUseVertexArrays && !ms.m_pDerivedMesh) RAS_VAOpenGLRasterizer::IndexPrimitives(ms); else RAS_OpenGLRasterizer::IndexPrimitives(ms); @@ -204,7 +230,7 @@ void RAS_ListRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms) // workaround: note how we do not use vertex arrays for making display // lists, since glVertexAttribPointerARB doesn't seem to work correct // in display lists on ATI? either a bug in the driver or in Blender .. - if (mUseVertexArrays && !localSlot) + if (mUseVertexArrays && !mATI && !ms.m_pDerivedMesh) RAS_VAOpenGLRasterizer::IndexPrimitivesMulti(ms); else RAS_OpenGLRasterizer::IndexPrimitivesMulti(ms); diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h index 96d6d2a995d..cff48081f02 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h @@ -9,6 +9,7 @@ class RAS_ListRasterizer; class RAS_ListSlot : public KX_ListSlot { + friend class RAS_ListRasterizer; unsigned int m_list; unsigned int m_flag; RAS_ListRasterizer* m_rasty; @@ -32,15 +33,21 @@ enum RAS_ListSlotFlags { LIST_NOCREATE =8, LIST_BEGIN =16, LIST_END =32, - LIST_REGEN =64 + LIST_REGEN =64, + LIST_DERIVEDMESH=128, }; -typedef std::map<class RAS_MeshSlot*, RAS_ListSlot*> RAS_Lists; +struct DerivedMesh; + +typedef std::map<RAS_DisplayArrayList, RAS_ListSlot*> RAS_ArrayLists; +typedef std::map<DerivedMesh*, RAS_ListSlot*> RAS_DerivedMeshLists; class RAS_ListRasterizer : public RAS_VAOpenGLRasterizer { bool mUseVertexArrays; - RAS_Lists mLists; + bool mATI; + RAS_ArrayLists mArrayLists; + RAS_DerivedMeshLists mDerivedMeshLists; RAS_ListSlot* FindOrAdd(class RAS_MeshSlot& ms); void ReleaseAlloc(); @@ -59,6 +66,13 @@ public: virtual void SetDrawingMode(int drawingmode); virtual bool QueryLists(){return true;} + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_ListRasterizer"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp index 87a0a1d8b9e..d16348defb2 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp @@ -35,11 +35,20 @@ #include "RAS_Rect.h" #include "RAS_TexVert.h" +#include "RAS_MeshObject.h" #include "MT_CmMatrix4x4.h" #include "RAS_IRenderTools.h" // rendering text #include "GPU_draw.h" #include "GPU_material.h" +#include "GPU_extensions.h" + +#include "DNA_image_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_material_types.h" +#include "DNA_scene_types.h" + +#include "BKE_DerivedMesh.h" /** * 32x32 bit masks for vinterlace stereo mode @@ -59,6 +68,8 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas) m_2DCanvas(canvas), m_fogenabled(false), m_time(0.0), + m_campos(0.0f, 0.0f, 0.0f), + m_camortho(false), m_stereomode(RAS_STEREO_NOSTEREO), m_curreye(RAS_STEREO_LEFTEYE), m_eyeseparation(0.0), @@ -70,7 +81,7 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas) m_motionblurvalue(-1.0), m_texco_num(0), m_attrib_num(0), - m_last_blendmode(GPU_BLEND_SOLID), + //m_last_blendmode(GPU_BLEND_SOLID), m_last_frontface(true), m_materialCachingInfo(0) { @@ -107,7 +118,8 @@ bool RAS_OpenGLRasterizer::Init() glDisable(GL_BLEND); glDisable(GL_ALPHA_TEST); - m_last_blendmode = GPU_BLEND_SOLID; + //m_last_blendmode = GPU_BLEND_SOLID; + GPU_set_material_blend_mode(GPU_BLEND_SOLID); glFrontFace(GL_CCW); m_last_frontface = true; @@ -199,6 +211,10 @@ void RAS_OpenGLRasterizer::DisableFog() m_fogenabled = false; } +bool RAS_OpenGLRasterizer::IsFogEnabled() +{ + return m_fogenabled; +} void RAS_OpenGLRasterizer::DisplayFog() @@ -273,7 +289,8 @@ bool RAS_OpenGLRasterizer::BeginFrame(int drawingmode, double time) glDisable(GL_BLEND); glDisable(GL_ALPHA_TEST); - m_last_blendmode = GPU_BLEND_SOLID; + //m_last_blendmode = GPU_BLEND_SOLID; + GPU_set_material_blend_mode(GPU_BLEND_SOLID); glFrontFace(GL_CCW); m_last_frontface = true; @@ -325,18 +342,23 @@ void RAS_OpenGLRasterizer::ClearCachingInfo(void) m_materialCachingInfo = 0; } - -void RAS_OpenGLRasterizer::EndFrame() +void RAS_OpenGLRasterizer::FlushDebugLines() { - glDisable(GL_LIGHTING); - glDisable(GL_TEXTURE_2D); + if(!m_debugLines.size()) + return; + + // DrawDebugLines + GLboolean light, tex; + + light= glIsEnabled(GL_LIGHTING); + tex= glIsEnabled(GL_TEXTURE_2D); + + if(light) glDisable(GL_LIGHTING); + if(tex) glDisable(GL_TEXTURE_2D); - //DrawDebugLines glBegin(GL_LINES); for (unsigned int i=0;i<m_debugLines.size();i++) { - - glColor4f(m_debugLines[i].m_color[0],m_debugLines[i].m_color[1],m_debugLines[i].m_color[2],1.f); const MT_Scalar* fromPtr = &m_debugLines[i].m_from.x(); const MT_Scalar* toPtr= &m_debugLines[i].m_to.x(); @@ -346,7 +368,17 @@ void RAS_OpenGLRasterizer::EndFrame() } glEnd(); + if(light) glEnable(GL_LIGHTING); + if(tex) glEnable(GL_TEXTURE_2D); + m_debugLines.clear(); +} + +void RAS_OpenGLRasterizer::EndFrame() +{ + + + FlushDebugLines(); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); m_2DCanvas->EndFrame(); @@ -406,21 +438,23 @@ void RAS_OpenGLRasterizer::SetRenderArea() break; } } - void RAS_OpenGLRasterizer::SetStereoMode(const StereoMode stereomode) { m_stereomode = stereomode; } - +RAS_IRasterizer::StereoMode RAS_OpenGLRasterizer::GetStereoMode() +{ + return m_stereomode; +} bool RAS_OpenGLRasterizer::Stereo() { - if(m_stereomode == RAS_STEREO_NOSTEREO) - return false; - else + if(m_stereomode > RAS_STEREO_NOSTEREO) // > 0 return true; + else + return false; } bool RAS_OpenGLRasterizer::InterlacedStereo() @@ -684,6 +718,51 @@ void RAS_OpenGLRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms) IndexPrimitivesInternal(ms, true); } +static bool current_wireframe; +static RAS_MaterialBucket *current_bucket; +static RAS_IPolyMaterial *current_polymat; +static RAS_MeshSlot *current_ms; +static RAS_MeshObject *current_mesh; +static int current_blmat_nr; +static GPUVertexAttribs current_gpu_attribs; +static int CheckMaterialDM(int matnr, void *attribs) +{ + // only draw the current material + if (matnr != current_blmat_nr) + return 0; + GPUVertexAttribs *gattribs = (GPUVertexAttribs *)attribs; + if (gattribs) + memcpy(gattribs, ¤t_gpu_attribs, sizeof(GPUVertexAttribs)); + return 1; +} +static int CheckTexfaceDM(void *mcol, int index) +{ + + // index is the original face index, retrieve the polygon + RAS_Polygon* polygon = (index >= 0 && index < current_mesh->NumPolygons()) ? + current_mesh->GetPolygon(index) : NULL; + if (polygon && polygon->GetMaterial() == current_bucket) { + // must handle color. + if (current_wireframe) + return 2; + if (current_ms->m_bObjectColor) { + MT_Vector4& rgba = current_ms->m_RGBAcolor; + glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); + // don't use mcol + return 2; + } + if (!mcol) { + // we have to set the color from the material + unsigned char rgba[4]; + current_polymat->GetMaterialRGBAColor(rgba); + glColor4ubv((const GLubyte *)rgba); + return 2; + } + return 1; + } + return 0; +} + void RAS_OpenGLRasterizer::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi) { bool obcolor = ms.m_bObjectColor; @@ -691,6 +770,34 @@ void RAS_OpenGLRasterizer::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi) MT_Vector4& rgba = ms.m_RGBAcolor; RAS_MeshSlot::iterator it; + if (ms.m_pDerivedMesh) { + // mesh data is in derived mesh, + current_bucket = ms.m_bucket; + current_polymat = current_bucket->GetPolyMaterial(); + current_ms = &ms; + current_mesh = ms.m_mesh; + current_wireframe = wireframe; + MCol *mcol = (MCol*)ms.m_pDerivedMesh->getFaceDataArray(ms.m_pDerivedMesh, CD_MCOL); + if (current_polymat->GetFlag() & RAS_BLENDERGLSL) { + // GetMaterialIndex return the original mface material index, + // increment by 1 to match what derived mesh is doing + current_blmat_nr = current_polymat->GetMaterialIndex()+1; + // For GLSL we need to retrieve the GPU material attribute + Material* blmat = current_polymat->GetBlenderMaterial(); + Scene* blscene = current_polymat->GetBlenderScene(); + if (!wireframe && blscene && blmat) + GPU_material_vertex_attributes(GPU_material_from_blender(blscene, blmat), ¤t_gpu_attribs); + else + memset(¤t_gpu_attribs, 0, sizeof(current_gpu_attribs)); + // DM draw can mess up blending mode, restore at the end + int current_blend_mode = GPU_get_material_blend_mode(); + ms.m_pDerivedMesh->drawFacesGLSL(ms.m_pDerivedMesh, CheckMaterialDM); + GPU_set_material_blend_mode(current_blend_mode); + } else { + ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol); + } + return; + } // iterate over display arrays, each containing an index + vertex array for(ms.begin(it); !ms.end(it); ms.next(it)) { RAS_TexVert *vertex; @@ -754,8 +861,9 @@ void RAS_OpenGLRasterizer::SetProjectionMatrix(MT_CmMatrix4x4 &mat) glMatrixMode(GL_PROJECTION); double* matrix = &mat(0,0); glLoadMatrixd(matrix); -} + m_camortho= (mat(3, 3) != 0.0f); +} void RAS_OpenGLRasterizer::SetProjectionMatrix(const MT_Matrix4x4 & mat) { @@ -765,6 +873,8 @@ void RAS_OpenGLRasterizer::SetProjectionMatrix(const MT_Matrix4x4 & mat) mat.getValue(matrix); /* Internally, MT_Matrix4x4 uses doubles (MT_Scalar). */ glLoadMatrixd(matrix); + + m_camortho= (mat[3][3] != 0.0f); } MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix( @@ -775,13 +885,13 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix( float frustnear, float frustfar, float focallength, - bool + bool ){ MT_Matrix4x4 result; double mat[16]; // correction for stereo - if(m_stereomode != RAS_STEREO_NOSTEREO) + if(Stereo()) { float near_div_focallength; // next 2 params should be specified on command line and in Blender publisher @@ -816,17 +926,40 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix( return result; } +MT_Matrix4x4 RAS_OpenGLRasterizer::GetOrthoMatrix( + float left, + float right, + float bottom, + float top, + float frustnear, + float frustfar +){ + MT_Matrix4x4 result; + double mat[16]; + + // stereo is meaning less for orthographic, disable it + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(left, right, bottom, top, frustnear, frustfar); + + glGetDoublev(GL_PROJECTION_MATRIX, mat); + result.setValue(mat); + + return result; +} + // next arguments probably contain redundant info, for later... -void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Vector3& campos, - const MT_Point3 &, const MT_Quaternion &camOrientQuat) +void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, + const MT_Matrix3x3 & camOrientMat3x3, + const MT_Point3 & pos, + bool perspective) { m_viewmatrix = mat; // correction for stereo - if(m_stereomode != RAS_STEREO_NOSTEREO) + if(Stereo() && perspective) { - MT_Matrix3x3 camOrientMat3x3(camOrientQuat); MT_Vector3 unitViewDir(0.0, -1.0, 0.0); // minus y direction, Blender convention MT_Vector3 unitViewupVec(0.0, 0.0, 1.0); MT_Vector3 viewDir, viewupVec; @@ -872,7 +1005,7 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Vecto glMatrixMode(GL_MODELVIEW); glLoadMatrixd(glviewmat); - m_campos = campos; + m_campos = pos; } @@ -881,6 +1014,10 @@ const MT_Point3& RAS_OpenGLRasterizer::GetCameraPosition() return m_campos; } +bool RAS_OpenGLRasterizer::GetCameraOrtho() +{ + return m_camortho; +} void RAS_OpenGLRasterizer::SetCullFace(bool enable) { @@ -964,6 +1101,8 @@ void RAS_OpenGLRasterizer::DisableMotionBlur() void RAS_OpenGLRasterizer::SetBlendingMode(int blendmode) { + GPU_set_material_blend_mode(blendmode); +/* if(blendmode == m_last_blendmode) return; @@ -990,6 +1129,7 @@ void RAS_OpenGLRasterizer::SetBlendingMode(int blendmode) } m_last_blendmode = blendmode; +*/ } void RAS_OpenGLRasterizer::SetFrontFace(bool ccw) diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h index 0717cce0ce8..db0f97bf46f 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h @@ -80,6 +80,7 @@ class RAS_OpenGLRasterizer : public RAS_IRasterizer MT_Matrix4x4 m_viewmatrix; MT_Matrix4x4 m_viewinvmatrix; MT_Point3 m_campos; + bool m_camortho; StereoMode m_stereomode; StereoEye m_curreye; @@ -99,7 +100,7 @@ protected: TexCoGen m_attrib[RAS_MAX_ATTRIB]; int m_texco_num; int m_attrib_num; - int m_last_blendmode; + //int m_last_blendmode; bool m_last_frontface; /** Stores the caching information for the last material activated. */ @@ -137,6 +138,7 @@ public: virtual void SetRenderArea(); virtual void SetStereoMode(const StereoMode stereomode); + virtual RAS_IRasterizer::StereoMode GetStereoMode(); virtual bool Stereo(); virtual bool InterlacedStereo(); virtual void SetEye(const StereoEye eye); @@ -161,12 +163,13 @@ public: virtual void SetProjectionMatrix(const MT_Matrix4x4 & mat); virtual void SetViewMatrix( const MT_Matrix4x4 & mat, - const MT_Vector3& campos, - const MT_Point3 &camLoc, - const MT_Quaternion &camOrientQuat + const MT_Matrix3x3 & ori, + const MT_Point3 & pos, + bool perspective ); virtual const MT_Point3& GetCameraPosition(); + virtual bool GetCameraOrtho(); virtual void SetFog( float start, @@ -187,6 +190,7 @@ public: void DisableFog(); virtual void DisplayFog(); + virtual bool IsFogEnabled(); virtual void SetBackColor( float red, @@ -212,6 +216,15 @@ public: bool perspective ); + virtual MT_Matrix4x4 GetOrthoMatrix( + float left, + float right, + float bottom, + float top, + float frustnear, + float frustfar + ); + virtual void SetSpecularity( float specX, float specY, @@ -237,6 +250,8 @@ public: virtual void SetPolygonOffset(float mult, float add); + virtual void FlushDebugLines(); + virtual void DrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color) { OglDebugLine line; @@ -274,6 +289,13 @@ public: virtual void SetBlendingMode(int blendmode); virtual void SetFrontFace(bool ccw); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_OpenGLRasterizer"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__RAS_OPENGLRASTERIZER diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp index 2cb3b52adfb..00f0f27b6c1 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp @@ -110,6 +110,12 @@ void RAS_VAOpenGLRasterizer::IndexPrimitives(RAS_MeshSlot& ms) RAS_MeshSlot::iterator it; GLenum drawmode; + if (ms.m_pDerivedMesh) { + // cannot be handled here, pass to RAS_OpenGLRasterizer + RAS_OpenGLRasterizer::IndexPrimitivesInternal(ms, false); + return; + } + if(!wireframe) glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -167,6 +173,12 @@ void RAS_VAOpenGLRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms) RAS_MeshSlot::iterator it; GLenum drawmode; + if (ms.m_pDerivedMesh) { + // cannot be handled here, pass to RAS_OpenGLRasterizer + RAS_OpenGLRasterizer::IndexPrimitivesInternal(ms, true); + return; + } + if(!wireframe) EnableTextures(true); diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.h index 766bbfbed0e..6112c1a4d98 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.h @@ -58,6 +58,12 @@ private: //virtual bool QueryArrays(){return true;} //virtual bool QueryLists(){return m_Lock;} + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_VAOpenGLRasterizer"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__KX_VERTEXARRAYOPENGLRASTERIZER diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript index 8d46528f7f0..fb4c685f8d3 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript @@ -5,5 +5,7 @@ sources = env.Glob('*.cpp') incs = '. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/Rasterizer #source/gameengine/BlenderRoutines ' incs += ' #source/blender/gpu #extern/glew/include ' + env['BF_OPENGL_INC'] +incs += ' #source/blender/gameengine/Ketsji #source/gameengine/SceneGraph #source/blender/makesdna #source/blender/blenkernel' +incs += ' #intern/guardedalloc #source/blender/blenlib' -env.BlenderLib ( 'bf_oglrasterizer', Split(sources), Split(incs), [], libtype=['game','player'], priority=[40, 120] ) +env.BlenderLib ( 'bf_oglrasterizer', Split(sources), Split(incs), [], libtype=['core','player'], priority=[350,75], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/Rasterizer/RAS_Polygon.cpp b/source/gameengine/Rasterizer/RAS_Polygon.cpp index 50331d7a664..87c5118c5fb 100644 --- a/source/gameengine/Rasterizer/RAS_Polygon.cpp +++ b/source/gameengine/Rasterizer/RAS_Polygon.cpp @@ -31,6 +31,7 @@ #endif #include "RAS_Polygon.h" +#include "RAS_MeshObject.h" /* only for GetVertexOffsetAbs */ RAS_Polygon::RAS_Polygon(RAS_MaterialBucket* bucket, RAS_DisplayArray *darray, int numvert) { @@ -39,7 +40,7 @@ RAS_Polygon::RAS_Polygon(RAS_MaterialBucket* bucket, RAS_DisplayArray *darray, i m_offset[0]= m_offset[1]= m_offset[2]= m_offset[3]= 0; m_numvert = numvert; - m_edgecode = 255; +// m_edgecode = 255; m_polyflags = 0; } @@ -63,6 +64,21 @@ int RAS_Polygon::GetVertexOffset(int i) return m_offset[i]; } +int RAS_Polygon::GetVertexOffsetAbs(RAS_MeshObject *mesh, int i) +{ + /* hack that only works because there can only ever be 2 different + * GetDisplayArray's per mesh. if this uses a different display array to the first + * then its incices are offset. + * if support for edges is added back this would need to be changed. */ + RAS_DisplayArray* darray= mesh->GetPolygon(0)->GetDisplayArray(); + + if(m_darray != darray) + return m_offset[i] + darray->m_vertex.size(); + + return m_offset[i]; +} + +/* int RAS_Polygon::GetEdgeCode() { return m_edgecode; @@ -71,7 +87,7 @@ int RAS_Polygon::GetEdgeCode() void RAS_Polygon::SetEdgeCode(int edgecode) { m_edgecode = edgecode; -} +}*/ bool RAS_Polygon::IsVisible() @@ -96,6 +112,17 @@ void RAS_Polygon::SetCollider(bool visible) else m_polyflags &= ~COLLIDER; } +bool RAS_Polygon::IsTwoside() +{ + return (m_polyflags & TWOSIDE) != 0; +} + +void RAS_Polygon::SetTwoside(bool twoside) +{ + if(twoside) m_polyflags |= TWOSIDE; + else m_polyflags &= ~TWOSIDE; +} + RAS_MaterialBucket* RAS_Polygon::GetMaterial() { return m_bucket; diff --git a/source/gameengine/Rasterizer/RAS_Polygon.h b/source/gameengine/Rasterizer/RAS_Polygon.h index 18526ba45f7..bd8cfe0be28 100644 --- a/source/gameengine/Rasterizer/RAS_Polygon.h +++ b/source/gameengine/Rasterizer/RAS_Polygon.h @@ -35,6 +35,10 @@ #include <vector> using namespace std; +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + /* polygon flags */ class RAS_Polygon @@ -46,13 +50,18 @@ class RAS_Polygon unsigned short m_numvert; /* flags */ +#if 1 + unsigned short m_polyflags; +#else unsigned char m_edgecode; unsigned char m_polyflags; - +#endif + public: enum { VISIBLE = 1, - COLLIDER = 2 + COLLIDER = 2, + TWOSIDE = 4 }; RAS_Polygon(RAS_MaterialBucket* bucket, RAS_DisplayArray* darray, int numvert); @@ -63,10 +72,12 @@ public: void SetVertexOffset(int i, unsigned short offset); int GetVertexOffset(int i); + int GetVertexOffsetAbs(RAS_MeshObject *mesh, int i); /* accounts for quad and tri arrays, slower, for python */ // each bit is for a visible edge, starting with bit 1 for the first edge, bit 2 for second etc. - int GetEdgeCode(); - void SetEdgeCode(int edgecode); + // - Not used yet! +/* int GetEdgeCode(); + void SetEdgeCode(int edgecode); */ bool IsVisible(); void SetVisible(bool visible); @@ -74,8 +85,17 @@ public: bool IsCollider(); void SetCollider(bool collider); + bool IsTwoside(); + void SetTwoside(bool twoside); + RAS_MaterialBucket* GetMaterial(); RAS_DisplayArray* GetDisplayArray(); + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_Polygon"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/Rasterizer/RAS_Rect.h b/source/gameengine/Rasterizer/RAS_Rect.h index 4cd0c636cfd..ca7435673c9 100644 --- a/source/gameengine/Rasterizer/RAS_Rect.h +++ b/source/gameengine/Rasterizer/RAS_Rect.h @@ -30,6 +30,10 @@ #ifndef _RAS_RECT #define _RAS_RECT +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + /** * @section interface class. * RAS_Rect just encodes a simple rectangle. @@ -89,6 +93,12 @@ public: { m_y2 = y2; } + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_Rect"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif // _RAS_RECT diff --git a/source/gameengine/Rasterizer/RAS_TexVert.cpp b/source/gameengine/Rasterizer/RAS_TexVert.cpp index b92965ed1cc..8eee24ac7f0 100644 --- a/source/gameengine/Rasterizer/RAS_TexVert.cpp +++ b/source/gameengine/Rasterizer/RAS_TexVert.cpp @@ -59,10 +59,10 @@ const MT_Point3& RAS_TexVert::xyz() void RAS_TexVert::SetRGBA(const MT_Vector4& rgba) { unsigned char *colp = (unsigned char*) &m_rgba; - colp[0] = (unsigned char) (rgba[0]*255.0); - colp[1] = (unsigned char) (rgba[1]*255.0); - colp[2] = (unsigned char) (rgba[2]*255.0); - colp[3] = (unsigned char) (rgba[3]*255.0); + colp[0] = (unsigned char) (rgba[0]*255.0f); + colp[1] = (unsigned char) (rgba[1]*255.0f); + colp[2] = (unsigned char) (rgba[2]*255.0f); + colp[3] = (unsigned char) (rgba[3]*255.0f); } @@ -71,7 +71,10 @@ void RAS_TexVert::SetXYZ(const MT_Point3& xyz) xyz.getValue(m_localxyz); } - +void RAS_TexVert::SetXYZ(const float *xyz) +{ + m_localxyz[0]= xyz[0]; m_localxyz[1]= xyz[1]; m_localxyz[2]= xyz[2]; +} void RAS_TexVert::SetUV(const MT_Point2& uv) { @@ -110,16 +113,20 @@ void RAS_TexVert::SetTangent(const MT_Vector3& tangent) tangent.getValue(m_tangent); } + // compare two vertices, and return TRUE if both are almost identical (they can be shared) bool RAS_TexVert::closeTo(const RAS_TexVert* other) { - return (m_flag == other->m_flag && + return ( + /* m_flag == other->m_flag && */ + /* at the moment the face only stores the smooth/flat setting so dont bother comparing it */ m_rgba == other->m_rgba && MT_fuzzyEqual(MT_Vector3(m_normal), MT_Vector3(other->m_normal)) && MT_fuzzyEqual(MT_Vector3(m_tangent), MT_Vector3(other->m_tangent)) && MT_fuzzyEqual(MT_Vector2(m_uv1), MT_Vector2(other->m_uv1)) && - MT_fuzzyEqual(MT_Vector2(m_uv2), MT_Vector2(other->m_uv2)) && // p -- - MT_fuzzyEqual(MT_Vector3(m_localxyz), MT_Vector3(other->m_localxyz))) ; + MT_fuzzyEqual(MT_Vector2(m_uv2), MT_Vector2(other->m_uv2)) /* && + MT_fuzzyEqual(MT_Vector3(m_localxyz), MT_Vector3(other->m_localxyz))*/) ; + /* dont bother comparing m_localxyz since we know there from the same vert */ } short RAS_TexVert::getFlag() const diff --git a/source/gameengine/Rasterizer/RAS_TexVert.h b/source/gameengine/Rasterizer/RAS_TexVert.h index 54da109cbf1..b93078f4712 100644 --- a/source/gameengine/Rasterizer/RAS_TexVert.h +++ b/source/gameengine/Rasterizer/RAS_TexVert.h @@ -34,6 +34,10 @@ #include "MT_Point2.h" #include "MT_Transform.h" +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + static MT_Point3 g_pt3; static MT_Point2 g_pt2; @@ -110,11 +114,12 @@ public: return (unsigned char *) &m_rgba; } - const unsigned int getOrigIndex() const { + unsigned int getOrigIndex() const { return m_origindex; } void SetXYZ(const MT_Point3& xyz); + void SetXYZ(const float *xyz); void SetUV(const MT_Point2& uv); void SetUV2(const MT_Point2& uv); @@ -133,6 +138,12 @@ public: // compare two vertices, to test if they can be shared, used for // splitting up based on uv's, colors, etc bool closeTo(const RAS_TexVert* other); + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_TexVert"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__RAS_TEXVERT diff --git a/source/gameengine/Rasterizer/SConscript b/source/gameengine/Rasterizer/SConscript index a024f7e0ee6..dbec2d92e31 100644 --- a/source/gameengine/Rasterizer/SConscript +++ b/source/gameengine/Rasterizer/SConscript @@ -4,12 +4,7 @@ Import ('env') sources = env.Glob('*.cpp') -incs = '. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/BlenderRoutines #extern/glew/include #source/gameengine/Expressions #source/blender/blenkernel #source/blender/makesdna' +incs = '. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/BlenderRoutines #extern/glew/include #source/gameengine/Expressions #source/gameengine/SceneGraph #source/blender/blenkernel #source/blender/makesdna' incs += ' ' + env['BF_PYTHON_INC'] -if env['OURPLATFORM']=='win32-vc': - cflags = [] - cflags.append('/Ox') - env.BlenderLib ( 'bf_rasterizer', sources, Split(incs), [], libtype=['game','player'], priority=[35,115], compileflags = cflags ) -else: - env.BlenderLib ( 'bf_rasterizer', sources, Split(incs), [], libtype=['game','player'], priority=[35,115] ) +env.BlenderLib ( 'bf_rasterizer', sources, Split(incs), [], libtype=['core','player'], priority=[350,70], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/SConscript b/source/gameengine/SConscript index c2750d19706..592b138583f 100644 --- a/source/gameengine/SConscript +++ b/source/gameengine/SConscript @@ -3,7 +3,7 @@ Import ('env') SConscript(['BlenderRoutines/SConscript', 'Converter/SConscript', - 'Expressions/SConscript', + 'Expressions/SConscript', #310 'GameLogic/SConscript', 'Ketsji/SConscript', 'Ketsji/KXNetwork/SConscript', @@ -15,13 +15,8 @@ SConscript(['BlenderRoutines/SConscript', 'Rasterizer/RAS_OpenGLRasterizer/SConscript', 'SceneGraph/SConscript', 'Physics/Bullet/SConscript', - 'Physics/Sumo/SConscript' + 'VideoTexture/SConscript' ]) if env['WITH_BF_PLAYER']: SConscript(['GamePlayer/SConscript']) - -#if user_options_dict['USE_PHYSICS'] == 'solid': -# SConscript(['Physics/Sumo/SConscript']) -#elif user_options_dict['USE_PHYSICS'] == 'ode': -# SConscript(['Physics/BlOde/SConscript']) diff --git a/source/gameengine/SceneGraph/CMakeLists.txt b/source/gameengine/SceneGraph/CMakeLists.txt index 0409b8c0ac4..2ac52be938e 100644 --- a/source/gameengine/SceneGraph/CMakeLists.txt +++ b/source/gameengine/SceneGraph/CMakeLists.txt @@ -27,8 +27,8 @@ FILE(GLOB SRC *.cpp) SET(INC - . - ../../../intern/moto/include + . + ../../../intern/moto/include ) BLENDERLIB(bf_scenegraph "${SRC}" "${INC}") diff --git a/source/gameengine/SceneGraph/SConscript b/source/gameengine/SceneGraph/SConscript index 23c1c24c297..2a33cd67b5e 100644 --- a/source/gameengine/SceneGraph/SConscript +++ b/source/gameengine/SceneGraph/SConscript @@ -2,8 +2,8 @@ Import ('env') -sources = env.Glob('*.cpp') #'SG_BBox.cpp SG_Controller.cpp SG_IObject.cpp SG_Node.cpp SG_Spatial.cpp SG_Tree.cpp' +sources = env.Glob('*.cpp') incs = '. #intern/moto/include' -env.BlenderLib ( 'bf_scenegraph', sources, Split(incs), [], libtype=['game','player'], priority=[50,130] ) +env.BlenderLib ( 'bf_scenegraph', sources, Split(incs), [], libtype=['core','player'], priority=[325,85], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/SceneGraph/SG_BBox.cpp b/source/gameengine/SceneGraph/SG_BBox.cpp index 4bd2805978e..66fcc5c7408 100644 --- a/source/gameengine/SceneGraph/SG_BBox.cpp +++ b/source/gameengine/SceneGraph/SG_BBox.cpp @@ -34,8 +34,8 @@ #include "SG_Node.h" SG_BBox::SG_BBox() : - m_min(MT_Point3(0., 0., 0.)), - m_max(MT_Point3(0., 0., 0.)) + m_min(0., 0., 0.), + m_max(0., 0., 0.) { } @@ -188,6 +188,13 @@ void SG_BBox::getaa(MT_Point3 *box, const MT_Transform &world) const *box++ = max; } +void SG_BBox::getmm(MT_Point3 *box, const MT_Transform &world) const +{ + const MT_Point3 min(world(m_min)), max(world(m_max)); + *box++ = min; + *box++ = max; +} + void SG_BBox::split(SG_BBox &left, SG_BBox &right) const { MT_Scalar sizex = m_max[0] - m_min[0]; diff --git a/source/gameengine/SceneGraph/SG_BBox.h b/source/gameengine/SceneGraph/SG_BBox.h index b7e8ff65865..8dbb9869dae 100644 --- a/source/gameengine/SceneGraph/SG_BBox.h +++ b/source/gameengine/SceneGraph/SG_BBox.h @@ -38,6 +38,10 @@ #include <vector> +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + class SG_Node; /** @@ -122,10 +126,18 @@ public: */ void getaa(MT_Point3 *box, const MT_Transform &world) const; + void getmm(MT_Point3 *box, const MT_Transform &world) const; + void split(SG_BBox &left, SG_BBox &right) const; friend class SG_Tree; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SG_BBox"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif /* __SG_BBOX_H__ */ diff --git a/source/gameengine/SceneGraph/SG_Controller.h b/source/gameengine/SceneGraph/SG_Controller.h index c32885b915f..db9d7bdb464 100644 --- a/source/gameengine/SceneGraph/SG_Controller.h +++ b/source/gameengine/SceneGraph/SG_Controller.h @@ -40,6 +40,12 @@ class SG_Controller { public: + +#ifdef WITH_CXX_GUARDEDALLOC + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "SG_Controller"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif + SG_Controller( ) : m_pObject(NULL) { diff --git a/source/gameengine/SceneGraph/SG_DList.h b/source/gameengine/SceneGraph/SG_DList.h new file mode 100644 index 00000000000..3e17fb55dc0 --- /dev/null +++ b/source/gameengine/SceneGraph/SG_DList.h @@ -0,0 +1,172 @@ +/** + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** + */ +#ifndef __SG_DLIST +#define __SG_DLIST + +#include <stdlib.h> + +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + +/** + * Double circular linked list + */ +class SG_DList +{ +protected : + SG_DList* m_flink; + SG_DList* m_blink; + +public: + template<typename T> class iterator + { + private: + SG_DList& m_head; + T* m_current; + public: + typedef iterator<T> _myT; + iterator(SG_DList& head) : m_head(head), m_current(NULL) {} + ~iterator() {} + + void begin() + { + m_current = (T*)m_head.Peek(); + } + void back() + { + m_current = (T*)m_head.Back(); + } + bool end() + { + return (m_current == (T*)m_head.Self()); + } + bool add_back(T* item) + { + return m_current->AddBack(item); + } + T* operator*() + { + return m_current; + } + _myT& operator++() + { + // no check of NULL! make sure you don't try to increment beyond end + m_current = (T*)m_current->Peek(); + return *this; + } + _myT& operator--() + { + // no check of NULL! make sure you don't try to increment beyond end + m_current = (T*)m_current->Back(); + return *this; + } + }; + + SG_DList() + { + m_flink = m_blink = this; + } + SG_DList(const SG_DList& other) + { + m_flink = m_blink = this; + } + virtual ~SG_DList() + { + Delink(); + } + + inline bool Empty() // Check for empty queue + { + return ( m_flink == this ); + } + bool AddBack( SG_DList *item ) // Add to the back + { + if (!item->Empty()) + return false; + item->m_blink = m_blink; + item->m_flink = this; + m_blink->m_flink = item; + m_blink = item; + return true; + } + bool AddFront( SG_DList *item ) // Add to the back + { + if (!item->Empty()) + return false; + item->m_flink = m_flink; + item->m_blink = this; + m_flink->m_blink = item; + m_flink = item; + return true; + } + SG_DList *Remove() // Remove from the front + { + if (Empty()) + { + return NULL; + } + SG_DList* item = m_flink; + m_flink = item->m_flink; + m_flink->m_blink = this; + item->m_flink = item->m_blink = item; + return item; + } + bool Delink() // Remove from the middle + { + if (Empty()) + return false; + m_blink->m_flink = m_flink; + m_flink->m_blink = m_blink; + m_flink = m_blink = this; + return true; + } + inline SG_DList *Peek() // Look at front without removing + { + return m_flink; + } + inline SG_DList *Back() // Look at front without removing + { + return m_blink; + } + inline SG_DList *Self() + { + return this; + } + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SG_DList"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif //__SG_DLIST + diff --git a/source/gameengine/SceneGraph/SG_IObject.cpp b/source/gameengine/SceneGraph/SG_IObject.cpp index d0bdac5c8f0..5795ca57113 100644 --- a/source/gameengine/SceneGraph/SG_IObject.cpp +++ b/source/gameengine/SceneGraph/SG_IObject.cpp @@ -33,23 +33,26 @@ #include <config.h> #endif +SG_Stage gSG_Stage = SG_STAGE_UNKNOWN; + SG_IObject:: SG_IObject( void* clientobj, void* clientinfo, - SG_Callbacks callbacks + SG_Callbacks& callbacks ): + SG_QList(), m_SGclientObject(clientobj), - m_SGclientInfo(clientinfo), - m_callbacks(callbacks) + m_SGclientInfo(clientinfo) { - //nothing to do + m_callbacks = callbacks; } SG_IObject:: SG_IObject( const SG_IObject &other ) : + SG_QList(), m_SGclientObject(other.m_SGclientObject), m_SGclientInfo(other.m_SGclientInfo), m_callbacks(other.m_callbacks) @@ -72,92 +75,17 @@ RemoveAllControllers( m_SGcontrollers.clear(); } -/// Needed for replication - SGControllerList& -SG_IObject:: -GetSGControllerList( -){ - return m_SGcontrollers; -} - - void* -SG_IObject:: -GetSGClientObject( -){ - return m_SGclientObject; -} - -const - void* -SG_IObject:: -GetSGClientObject( -) const { - return m_SGclientObject; -} - - void -SG_IObject:: -SetSGClientObject( - void* clientObject -){ - m_SGclientObject = clientObject; -} - - - bool -SG_IObject:: -ActivateReplicationCallback( - SG_IObject *replica -){ - if (m_callbacks.m_replicafunc) - { - // Call client provided replication func - if (m_callbacks.m_replicafunc(replica,m_SGclientObject,m_SGclientInfo) == NULL) - return false; - } - return true; -}; - - void -SG_IObject:: -ActivateDestructionCallback( -){ - if (m_callbacks.m_destructionfunc) - { - // Call client provided destruction function on this! - m_callbacks.m_destructionfunc(this,m_SGclientObject,m_SGclientInfo); - } - else - { - // no callback but must still destroy the node to avoid memory leak - delete this; - } -} - - void -SG_IObject:: -ActivateUpdateTransformCallback( -){ - if (m_callbacks.m_updatefunc) - { - // Call client provided update func. - m_callbacks.m_updatefunc(this, m_SGclientObject, m_SGclientInfo); - } -} - - void -SG_IObject:: -SetControllerTime( - double time -){ +void SG_IObject::SetControllerTime(double time) +{ SGControllerList::iterator contit; - for (contit = m_SGcontrollers.begin();contit!=m_SGcontrollers.end();++contit) { (*contit)->SetSimulatedTime(time); } } +/// Needed for replication + SG_IObject:: ~SG_IObject() diff --git a/source/gameengine/SceneGraph/SG_IObject.h b/source/gameengine/SceneGraph/SG_IObject.h index 7f6bdfbbb1c..23e6c1e9c99 100644 --- a/source/gameengine/SceneGraph/SG_IObject.h +++ b/source/gameengine/SceneGraph/SG_IObject.h @@ -29,8 +29,39 @@ #ifndef __SG_IOBJECT #define __SG_IOBJECT +#include "SG_QList.h" #include <vector> +// used for debugging: stage of the game engine main loop at which a Scenegraph modification is done +enum SG_Stage +{ + SG_STAGE_UNKNOWN = 0, + SG_STAGE_NETWORK, + SG_STAGE_NETWORK_UPDATE, + SG_STAGE_PHYSICS1, + SG_STAGE_PHYSICS1_UPDATE, + SG_STAGE_CONTROLLER, + SG_STAGE_CONTROLLER_UPDATE, + SG_STAGE_ACTUATOR, + SG_STAGE_ACTUATOR_UPDATE, + SG_STAGE_PHYSICS2, + SG_STAGE_PHYSICS2_UPDATE, + SG_STAGE_SCENE, + SG_STAGE_RENDER, + SG_STAGE_CONVERTER, + SG_STAGE_CULLING, + SG_STAGE_MAX +}; + +extern SG_Stage gSG_Stage; + +inline void SG_SetActiveStage(SG_Stage stage) +{ + gSG_Stage = stage; +} + + + class SG_Controller; class SG_IObject; @@ -54,6 +85,18 @@ typedef void (*SG_UpdateTransformCallback)( void* clientinfo ); +typedef bool (*SG_ScheduleUpdateCallback)( + SG_IObject* sgobject, + void* clientobj, + void* clientinfo +); + +typedef bool (*SG_RescheduleUpdateCallback)( + SG_IObject* sgobject, + void* clientobj, + void* clientinfo +); + /** * SG_Callbacks hold 2 call backs to the outside world. @@ -76,30 +119,38 @@ struct SG_Callbacks ): m_replicafunc(NULL), m_destructionfunc(NULL), - m_updatefunc(NULL) + m_updatefunc(NULL), + m_schedulefunc(NULL), + m_reschedulefunc(NULL) { }; SG_Callbacks( SG_ReplicationNewCallback repfunc, SG_DestructionNewCallback destructfunc, - SG_UpdateTransformCallback updatefunc + SG_UpdateTransformCallback updatefunc, + SG_ScheduleUpdateCallback schedulefunc, + SG_RescheduleUpdateCallback reschedulefunc ): m_replicafunc(repfunc), m_destructionfunc(destructfunc), - m_updatefunc(updatefunc) + m_updatefunc(updatefunc), + m_schedulefunc(schedulefunc), + m_reschedulefunc(reschedulefunc) { }; SG_ReplicationNewCallback m_replicafunc; SG_DestructionNewCallback m_destructionfunc; SG_UpdateTransformCallback m_updatefunc; + SG_ScheduleUpdateCallback m_schedulefunc; + SG_RescheduleUpdateCallback m_reschedulefunc; }; /** base object that can be part of the scenegraph. */ -class SG_IObject +class SG_IObject : public SG_QList { private : @@ -109,8 +160,6 @@ private : SGControllerList m_SGcontrollers; public: - - virtual ~SG_IObject(); @@ -147,10 +196,18 @@ public: * using STL? */ - SGControllerList& - GetSGControllerList( - ); + SGControllerList& GetSGControllerList() + { + return m_SGcontrollers; + } + /** + * + */ + SG_Callbacks& GetCallBackFunctions() + { + return m_callbacks; + } /** * Get the client object associated with this @@ -162,16 +219,16 @@ public: * This may be NULL. */ - void* - GetSGClientObject( - ); + inline const void* GetSGClientObject() const + { + return m_SGclientObject; + } - const - void* - GetSGClientObject( - ) const ; + inline void* GetSGClientObject() + { + return m_SGclientObject; + } - /** * Set the client object for this node. This is just a * pointer to an object allocated that should exist for @@ -179,10 +236,10 @@ public: * this function is called again. */ - void - SetSGClientObject( - void* clientObject - ); + void SetSGClientObject(void* clientObject) + { + m_SGclientObject = clientObject; + } /** * Set the current simulation time for this node. @@ -190,10 +247,7 @@ public: * the nodes list of controllers and calls their SetSimulatedTime methods */ - void - SetControllerTime( - double time - ); + void SetControllerTime(double time); virtual void @@ -205,20 +259,76 @@ protected : bool ActivateReplicationCallback( SG_IObject *replica - ); + ) + { + if (m_callbacks.m_replicafunc) + { + // Call client provided replication func + if (m_callbacks.m_replicafunc(replica,m_SGclientObject,m_SGclientInfo) == NULL) + return false; + } + return true; + } + void ActivateDestructionCallback( - ); + ) + { + if (m_callbacks.m_destructionfunc) + { + // Call client provided destruction function on this! + m_callbacks.m_destructionfunc(this,m_SGclientObject,m_SGclientInfo); + } + else + { + // no callback but must still destroy the node to avoid memory leak + delete this; + } + } void ActivateUpdateTransformCallback( - ); + ) + { + if (m_callbacks.m_updatefunc) + { + // Call client provided update func. + m_callbacks.m_updatefunc(this, m_SGclientObject, m_SGclientInfo); + } + } + + bool + ActivateScheduleUpdateCallback( + ) + { + // HACK, this check assumes that the scheduled nodes are put on a DList (see SG_Node.h) + // The early check on Empty() allows up to avoid calling the callback function + // when the node is already scheduled for update. + if (Empty() && m_callbacks.m_schedulefunc) + { + // Call client provided update func. + return m_callbacks.m_schedulefunc(this, m_SGclientObject, m_SGclientInfo); + } + return false; + } + + void + ActivateRecheduleUpdateCallback( + ) + { + if (m_callbacks.m_reschedulefunc) + { + // Call client provided update func. + m_callbacks.m_reschedulefunc(this, m_SGclientObject, m_SGclientInfo); + } + } + SG_IObject( void* clientobj, void* clientinfo, - SG_Callbacks callbacks + SG_Callbacks& callbacks ); SG_IObject( @@ -226,6 +336,11 @@ protected : ); +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SG_IObject"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__SG_IOBJECT diff --git a/source/gameengine/SceneGraph/SG_Node.cpp b/source/gameengine/SceneGraph/SG_Node.cpp index 8de7ac83477..4cd43e852b8 100644 --- a/source/gameengine/SceneGraph/SG_Node.cpp +++ b/source/gameengine/SceneGraph/SG_Node.cpp @@ -40,12 +40,13 @@ using namespace std; SG_Node::SG_Node( void* clientobj, void* clientinfo, - SG_Callbacks callbacks + SG_Callbacks& callbacks ) : SG_Spatial(clientobj,clientinfo,callbacks), m_SGparent(NULL) { + m_modified = true; } SG_Node::SG_Node( @@ -55,7 +56,7 @@ SG_Node::SG_Node( m_children(other.m_children), m_SGparent(other.m_SGparent) { - // nothing to do + m_modified = true; } SG_Node::~SG_Node() @@ -141,22 +142,6 @@ Destruct() ActivateDestructionCallback(); } - - SG_Node* -SG_Node:: -GetSGParent( -) const { - return m_SGparent; -} - - void -SG_Node:: -SetSGParent( - SG_Node* parent -){ - m_SGparent = parent; -} - const SG_Node* SG_Node:: @@ -165,28 +150,6 @@ GetRootSGParent( return (m_SGparent ? (const SG_Node*) m_SGparent->GetRootSGParent() : (const SG_Node*) this); } - bool -SG_Node:: -IsVertexParent() -{ - if (m_parent_relation) - { - return m_parent_relation->IsVertexRelation(); - } - return false; -} - - bool -SG_Node:: -IsSlowParent() -{ - if (m_parent_relation) - { - return m_parent_relation->IsSlowRelation(); - } - return false; -} - void SG_Node:: DisconnectFromParent( @@ -199,8 +162,6 @@ DisconnectFromParent( } - - void SG_Node::AddChild(SG_Node* child) { m_children.push_back(child); @@ -219,40 +180,26 @@ void SG_Node::RemoveChild(SG_Node* child) -void SG_Node::UpdateWorldData(double time) +void SG_Node::UpdateWorldData(double time, bool parentUpdated) { //if (!GetSGParent()) // return; - if (UpdateSpatialData(GetSGParent(),time)) + if (UpdateSpatialData(GetSGParent(),time,parentUpdated)) + // to update the ActivateUpdateTransformCallback(); + // The node is updated, remove it from the update list + Delink(); + // update children's worlddata for (NodeList::iterator it = m_children.begin();it!=m_children.end();++it) { - (*it)->UpdateWorldData(time); + (*it)->UpdateWorldData(time, parentUpdated); } } -NodeList& SG_Node::GetSGChildren() -{ - return this->m_children; -} - - -const NodeList& SG_Node::GetSGChildren() const -{ - return this->m_children; -} - - -void SG_Node::ClearSGChildren() -{ - m_children.clear(); -} - - void SG_Node::SetSimulatedTime(double time,bool recurse) { diff --git a/source/gameengine/SceneGraph/SG_Node.h b/source/gameengine/SceneGraph/SG_Node.h index ffaaad861e2..4281bcd11f6 100644 --- a/source/gameengine/SceneGraph/SG_Node.h +++ b/source/gameengine/SceneGraph/SG_Node.h @@ -40,11 +40,10 @@ typedef std::vector<SG_Node*> NodeList; class SG_Node : public SG_Spatial { public: - SG_Node( void* clientobj, void* clientinfo, - SG_Callbacks callbacks + SG_Callbacks& callbacks ); SG_Node( @@ -85,45 +84,47 @@ public: * @return a reference to the list of children of this node. */ - NodeList& - GetSGChildren( - ); + NodeList& GetSGChildren() + { + return this->m_children; + } /** * Get the current list of children. * @return a const reference to the current list of children of this node. */ - const - NodeList& - GetSGChildren( - ) const; + const NodeList& GetSGChildren() const + { + return this->m_children; + } /** * Clear the list of children associated with this node */ - void - ClearSGChildren( - ); + void ClearSGChildren() + { + m_children.clear(); + } /** * return the parent of this node if it exists. */ - SG_Node* - GetSGParent( - ) const ; - + SG_Node* GetSGParent() const + { + return m_SGparent; + } /** * Set the parent of this node. */ - void - SetSGParent( - SG_Node* parent - ); + void SetSGParent(SG_Node* parent) + { + m_SGparent = parent; + } /** * Return the top node in this node's Scene graph hierarchy @@ -143,30 +144,33 @@ public: ); /** - * Tell this node to treat it's parent as a vertex parent. - */ - - void - SetVertexParent( - bool isvertexparent - ) ; - - - /** * Return vertex parent status. */ + bool IsVertexParent() + { + if (m_parent_relation) + { + return m_parent_relation->IsVertexRelation(); + } + return false; + } + - bool - IsVertexParent( - ) ; - /** * Return slow parent status. */ - bool - IsSlowParent( - ) ; + bool IsSlowParent() + { + if (m_parent_relation) + { + return m_parent_relation->IsSlowRelation(); + } + return false; + } + + + /** * Update the spatial data of this node. Iterate through @@ -175,7 +179,8 @@ public: void UpdateWorldData( - double time + double time, + bool parentUpdated=false ); /** @@ -190,6 +195,42 @@ public: ); /** + * Schedule this node for update by placing it in head queue + */ + bool Schedule(SG_QList& head) + { + // Put top parent in front of list to make sure they are updated before their + // children => the children will be udpated and removed from the list before + // we get to them, should they be in the list too. + return (m_SGparent)?head.AddBack(this):head.AddFront(this); + } + + /** + * Used during Scenegraph update + */ + static SG_Node* GetNextScheduled(SG_QList& head) + { + return static_cast<SG_Node*>(head.Remove()); + } + + /** + * Make this node ready for schedule on next update. This is needed for nodes + * that must always be updated (slow parent, bone parent) + */ + bool Reschedule(SG_QList& head) + { + return head.QAddBack(this); + } + + /** + * Used during Scenegraph update + */ + static SG_Node* GetNextRescheduled(SG_QList& head) + { + return static_cast<SG_Node*>(head.QRemove()); + } + + /** * Node replication functions. */ @@ -218,6 +259,12 @@ private: */ SG_Node* m_SGparent; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SG_Node"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__SG_NODE_H diff --git a/source/gameengine/SceneGraph/SG_ParentRelation.h b/source/gameengine/SceneGraph/SG_ParentRelation.h index 6507cb98519..a6a43c19115 100644 --- a/source/gameengine/SceneGraph/SG_ParentRelation.h +++ b/source/gameengine/SceneGraph/SG_ParentRelation.h @@ -55,7 +55,6 @@ class SG_Spatial; class SG_ParentRelation { public : - /** * Update the childs local and global coordinates * based upon the parents global coordinates. @@ -69,7 +68,8 @@ public : bool UpdateChildCoordinates( SG_Spatial * child, - const SG_Spatial * parent + const SG_Spatial * parent, + bool& parentUpdated ) = 0; virtual @@ -127,6 +127,13 @@ protected : SG_ParentRelation( const SG_ParentRelation & ); + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SG_ParentRelation"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif diff --git a/source/gameengine/SceneGraph/SG_QList.h b/source/gameengine/SceneGraph/SG_QList.h new file mode 100644 index 00000000000..6399111d80b --- /dev/null +++ b/source/gameengine/SceneGraph/SG_QList.h @@ -0,0 +1,164 @@ +/** + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 ***** + */ +#ifndef __SG_QLIST +#define __SG_QLIST + +#include "SG_DList.h" + +/** + * Double-Double circular linked list + * For storing an object is two lists simultaneously + */ +class SG_QList : public SG_DList +{ +protected : + SG_QList* m_fqlink; + SG_QList* m_bqlink; + +public: + template<typename T> class iterator + { + private: + SG_QList& m_head; + T* m_current; + public: + typedef iterator<T> _myT; + iterator(SG_QList& head, SG_QList* current=NULL) : m_head(head) { m_current = (T*)current; } + ~iterator() {} + + void begin() + { + m_current = (T*)m_head.QPeek(); + } + void back() + { + m_current = (T*)m_head.QBack(); + } + bool end() + { + return (m_current == (T*)m_head.Self()); + } + bool add_back(T* item) + { + return m_current->QAddBack(item); + } + T* operator*() + { + return m_current; + } + _myT& operator++() + { + m_current = (T*)m_current->QPeek(); + return *this; + } + _myT& operator--() + { + // no check on NULL! make sure you don't try to increment beyond end + m_current = (T*)m_current->QBack(); + return *this; + } + }; + + SG_QList() : SG_DList() + { + m_fqlink = m_bqlink = this; + } + SG_QList(const SG_QList& other) : SG_DList() + { + m_fqlink = m_bqlink = this; + } + virtual ~SG_QList() + { + QDelink(); + } + + inline bool QEmpty() // Check for empty queue + { + return ( m_fqlink == this ); + } + bool QAddBack( SG_QList *item ) // Add to the back + { + if (!item->QEmpty()) + return false; + item->m_bqlink = m_bqlink; + item->m_fqlink = this; + m_bqlink->m_fqlink = item; + m_bqlink = item; + return true; + } + bool QAddFront( SG_QList *item ) // Add to the back + { + if (!item->Empty()) + return false; + item->m_fqlink = m_fqlink; + item->m_bqlink = this; + m_fqlink->m_bqlink = item; + m_fqlink = item; + return true; + } + SG_QList *QRemove() // Remove from the front + { + if (QEmpty()) + { + return NULL; + } + SG_QList* item = m_fqlink; + m_fqlink = item->m_fqlink; + m_fqlink->m_bqlink = this; + item->m_fqlink = item->m_bqlink = item; + return item; + } + bool QDelink() // Remove from the middle + { + if (QEmpty()) + return false; + m_bqlink->m_fqlink = m_fqlink; + m_fqlink->m_bqlink = m_bqlink; + m_fqlink = m_bqlink = this; + return true; + } + inline SG_QList *QPeek() // Look at front without removing + { + return m_fqlink; + } + inline SG_QList *QBack() // Look at front without removing + { + return m_bqlink; + } + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SG_QList"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif //__SG_QLIST + diff --git a/source/gameengine/SceneGraph/SG_Spatial.cpp b/source/gameengine/SceneGraph/SG_Spatial.cpp index 5ba116e59db..5a47f07f573 100644 --- a/source/gameengine/SceneGraph/SG_Spatial.cpp +++ b/source/gameengine/SceneGraph/SG_Spatial.cpp @@ -40,22 +40,24 @@ SG_Spatial:: SG_Spatial( void* clientobj, void* clientinfo, - SG_Callbacks callbacks + SG_Callbacks& callbacks ): SG_IObject(clientobj,clientinfo,callbacks), - m_localPosition(MT_Point3(0.0,0.0,0.0)), - m_localRotation(MT_Matrix3x3(1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0)), - m_localScaling(MT_Vector3(1.f,1.f,1.f)), + m_localPosition(0.0,0.0,0.0), + m_localRotation(1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0), + m_localScaling(1.f,1.f,1.f), - m_worldPosition(MT_Point3(0.0,0.0,0.0)), - m_worldRotation(MT_Matrix3x3(1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0)), - m_worldScaling(MT_Vector3(1.f,1.f,1.f)), + m_worldPosition(0.0,0.0,0.0), + m_worldRotation(1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0), + m_worldScaling(1.f,1.f,1.f), m_parent_relation (NULL), m_bbox(MT_Point3(-1.0, -1.0, -1.0), MT_Point3(1.0, 1.0, 1.0)), - m_radius(1.0) + m_radius(1.0), + m_modified(false), + m_ogldirty(false) { } @@ -75,7 +77,9 @@ SG_Spatial( m_parent_relation(NULL), m_bbox(other.m_bbox), - m_radius(other.m_radius) + m_radius(other.m_radius), + m_modified(false), + m_ogldirty(false) { // duplicate the parent relation for this object m_parent_relation = other.m_parent_relation->NewCopy(); @@ -87,13 +91,6 @@ SG_Spatial:: delete (m_parent_relation); } - SG_ParentRelation * -SG_Spatial:: -GetParentRelation( -){ - return m_parent_relation; -} - void SG_Spatial:: SetParentRelation( @@ -101,6 +98,7 @@ SetParentRelation( ){ delete (m_parent_relation); m_parent_relation = relation; + SetModified(); } @@ -114,7 +112,8 @@ SetParentRelation( SG_Spatial:: UpdateSpatialData( const SG_Spatial *parent, - double time + double time, + bool& parentUpdated ){ bool bComputesWorldTransform = false; @@ -135,16 +134,11 @@ UpdateSpatialData( // our world coordinates. if (!bComputesWorldTransform) - bComputesWorldTransform = ComputeWorldTransforms(parent); + bComputesWorldTransform = ComputeWorldTransforms(parent, parentUpdated); return bComputesWorldTransform; } -bool SG_Spatial::ComputeWorldTransforms(const SG_Spatial *parent) -{ - return m_parent_relation->UpdateChildCoordinates(this,parent); -} - /** * Position and translation methods */ @@ -166,52 +160,14 @@ RelativeTranslate( m_localPosition += trans; } } + SetModified(); } - void -SG_Spatial:: -SetLocalPosition( - const MT_Point3& trans -){ - m_localPosition = trans; -} - - void -SG_Spatial:: -SetWorldPosition( - const MT_Point3& trans -) { - m_worldPosition = trans; -} /** * Scaling methods. */ - void -SG_Spatial:: -RelativeScale( - const MT_Vector3& scale -){ - m_localScaling = m_localScaling * scale; -} - - void -SG_Spatial:: -SetLocalScale( - const MT_Vector3& scale -){ - m_localScaling = scale; -} - - - void -SG_Spatial:: -SetWorldScale( - const MT_Vector3& scale -){ - m_worldScaling = scale; -} /** * Orientation and rotation methods. @@ -229,83 +185,10 @@ RelativeRotate( rot : (GetWorldOrientation().inverse() * rot * GetWorldOrientation())); + SetModified(); } - void -SG_Spatial:: -SetLocalOrientation(const MT_Matrix3x3& rot) -{ - m_localRotation = rot; -} - - - - void -SG_Spatial:: -SetWorldOrientation( - const MT_Matrix3x3& rot -) { - m_worldRotation = rot; -} - -const - MT_Point3& -SG_Spatial:: -GetLocalPosition( -) const { - return m_localPosition; -} - -const - MT_Matrix3x3& -SG_Spatial:: -GetLocalOrientation( -) const { - return m_localRotation; -} - -const - MT_Vector3& -SG_Spatial:: -GetLocalScale( -) const{ - return m_localScaling; -} - - -const - MT_Point3& -SG_Spatial:: -GetWorldPosition( -) const { - return m_worldPosition; -} - -const - MT_Matrix3x3& -SG_Spatial:: -GetWorldOrientation( -) const { - return m_worldRotation; -} -const - MT_Vector3& -SG_Spatial:: -GetWorldScaling( -) const { - return m_worldScaling; -} - -SG_BBox& SG_Spatial::BBox() -{ - return m_bbox; -} - -void SG_Spatial::SetBBox(SG_BBox& bbox) -{ - m_bbox = bbox; -} MT_Transform SG_Spatial::GetWorldTransform() const { diff --git a/source/gameengine/SceneGraph/SG_Spatial.h b/source/gameengine/SceneGraph/SG_Spatial.h index 28848b0f933..a818c8c81f7 100644 --- a/source/gameengine/SceneGraph/SG_Spatial.h +++ b/source/gameengine/SceneGraph/SG_Spatial.h @@ -35,6 +35,7 @@ #include <MT_Matrix3x3.h> // or Quaternion later ? #include "SG_IObject.h" #include "SG_BBox.h" +#include "SG_ParentRelation.h" class SG_Node; @@ -61,10 +62,24 @@ protected: SG_BBox m_bbox; MT_Scalar m_radius; - + bool m_modified; + bool m_ogldirty; // true if the openGL matrix for this object must be recomputed public: - + inline void ClearModified() + { + m_modified = false; + m_ogldirty = true; + } + inline void SetModified() + { + m_modified = true; + ActivateScheduleUpdateCallback(); + } + inline void ClearDirty() + { + m_ogldirty = false; + } /** * Define the realtionship this node has with it's parent * node. You should pass an unshared instance of an SG_ParentRelation @@ -84,9 +99,12 @@ public: SG_ParentRelation *relation ); - SG_ParentRelation * - GetParentRelation( - ); + SG_ParentRelation * GetParentRelation() + { + return m_parent_relation; + } + + /** @@ -105,15 +123,17 @@ public: bool local ); - void - SetLocalPosition( - const MT_Point3& trans - ); + void SetLocalPosition(const MT_Point3& trans) + { + m_localPosition = trans; + SetModified(); + } + + void SetWorldPosition(const MT_Point3& trans) + { + m_worldPosition = trans; + } - void - SetWorldPosition( - const MT_Point3& trans - ); void RelativeRotate( @@ -121,79 +141,117 @@ public: bool local ); - void - SetLocalOrientation( - const MT_Matrix3x3& rot - ); - - void - SetWorldOrientation( - const MT_Matrix3x3& rot - ); - - void - RelativeScale( - const MT_Vector3& scale - ); - - void - SetLocalScale( - const MT_Vector3& scale - ); - - void - SetWorldScale( - const MT_Vector3& scale - ); - - const - MT_Point3& - GetLocalPosition( - ) const ; - - const - MT_Matrix3x3& - GetLocalOrientation( - ) const ; + void SetLocalOrientation(const MT_Matrix3x3& rot) + { + m_localRotation = rot; + SetModified(); + } + + // rot is arrange like openGL matrix + void SetLocalOrientation(const float* rot) + { + m_localRotation.setValue(rot); + SetModified(); + } + + void SetWorldOrientation(const MT_Matrix3x3& rot) + { + m_worldRotation = rot; + } + + void RelativeScale(const MT_Vector3& scale) + { + m_localScaling = m_localScaling * scale; + SetModified(); + } + + void SetLocalScale(const MT_Vector3& scale) + { + m_localScaling = scale; + SetModified(); + } + + void SetWorldScale(const MT_Vector3& scale) + { + m_worldScaling = scale; + } + + const MT_Point3& GetLocalPosition() const + { + return m_localPosition; + } + + const MT_Matrix3x3& GetLocalOrientation() const + { + return m_localRotation; + } + + const MT_Vector3& GetLocalScale() const + { + return m_localScaling; + } + + const MT_Point3& GetWorldPosition() const + { + return m_worldPosition; + } + + const MT_Matrix3x3& GetWorldOrientation() const + { + return m_worldRotation; + } + + const MT_Vector3& GetWorldScaling() const + { + return m_worldScaling; + } + + void SetWorldFromLocalTransform() + { + m_worldPosition= m_localPosition; + m_worldScaling= m_localScaling; + m_worldRotation= m_localRotation; + } - const - MT_Vector3& - GetLocalScale( - ) const; - const - MT_Point3& - GetWorldPosition( - ) const ; - - const - MT_Matrix3x3& - GetWorldOrientation( - ) const ; - - const - MT_Vector3& - GetWorldScaling( - ) const ; MT_Transform GetWorldTransform() const; - bool ComputeWorldTransforms( const SG_Spatial *parent); + bool ComputeWorldTransforms(const SG_Spatial *parent, bool& parentUpdated) + { + return m_parent_relation->UpdateChildCoordinates(this,parent,parentUpdated); + } + /** * Bounding box functions. */ - SG_BBox& BBox(); - void SetBBox(SG_BBox & bbox); + SG_BBox& BBox() + { + return m_bbox; + } + + void SetBBox(SG_BBox& bbox) + { + m_bbox = bbox; + } + + bool inside(const MT_Point3 &point) const; void getBBox(MT_Point3 *box) const; void getAABBox(MT_Point3 *box) const; MT_Scalar Radius() const { return m_radius; } void SetRadius(MT_Scalar radius) { m_radius = radius; } + bool IsModified() { return m_modified; } + bool IsDirty() { return m_ogldirty; } protected: friend class SG_Controller; + friend class KX_BoneParentRelation; + friend class KX_VertexParentRelation; + friend class KX_SlowParentRelation; + friend class KX_NormalParentRelation; /** * Protected constructor this class is not @@ -203,7 +261,7 @@ protected: SG_Spatial( void* clientobj, void* clientinfo, - SG_Callbacks callbacks + SG_Callbacks& callbacks ); SG_Spatial( @@ -221,9 +279,16 @@ protected: bool UpdateSpatialData( const SG_Spatial *parent, - double time + double time, + bool& parentUpdated ); + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SG_Spatial"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif //__SG_SPATIAL_H diff --git a/source/gameengine/SceneGraph/SG_Tree.h b/source/gameengine/SceneGraph/SG_Tree.h index 4741af83aae..6ca3307920e 100644 --- a/source/gameengine/SceneGraph/SG_Tree.h +++ b/source/gameengine/SceneGraph/SG_Tree.h @@ -111,6 +111,13 @@ public: } }; + + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SG_Tree"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; @@ -148,6 +155,12 @@ public: SG_Tree* MakeTree(); + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:SG_TreeFactory"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif }; #endif /* __SG_BBOX_H__ */ diff --git a/source/gameengine/VideoTexture/BlendType.h b/source/gameengine/VideoTexture/BlendType.h new file mode 100644 index 00000000000..8b243c43912 --- /dev/null +++ b/source/gameengine/VideoTexture/BlendType.h @@ -0,0 +1,77 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2006 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined BLENDTYPE_H +#define BLENDTYPE_H + + +/// class allows check type of blender python object and access its contained object +/// MUST ONLY BE USED FOR KX classes that are descendent of PyObjectPlus +template <class PyObj> class BlendType +{ +public: + /// constructor + BlendType (char * name) : m_name(name) {} + + /// check blender type and return pointer to contained object or NULL (if type is not valid) + PyObj * checkType (PyObject * obj) + { + // if pointer to type isn't set + if (m_objType == NULL) + { + // compare names of type + if (strcmp(obj->ob_type->tp_name, m_name) == 0) + // if name of type match, save pointer to type + m_objType = obj->ob_type; + else + // if names of type don't match, return NULL + return NULL; + } + // if pointer to type is set and don't match to type of provided object, return NULL + else if (obj->ob_type != m_objType) + return NULL; + // return pointer to object, this class can only be used for KX object => + // the Py object is actually a proxy + return (PyObj*)BGE_PROXY_REF(obj); + } + + /// parse arguments to get object + PyObj * parseArg (PyObject * args) + { + // parse arguments + PyObject * obj; + if (PyArg_ParseTuple(args, "O", &obj)) + // if successfully parsed, return pointer to object + return checkType(obj); + // otherwise return NULL + return NULL; + } + +protected: + /// name of Python type + char * m_name; + /// pointer to Python type + PyTypeObject * m_objType; +}; + + +#endif diff --git a/source/gameengine/VideoTexture/CMakeLists.txt b/source/gameengine/VideoTexture/CMakeLists.txt new file mode 100644 index 00000000000..935c5a2c292 --- /dev/null +++ b/source/gameengine/VideoTexture/CMakeLists.txt @@ -0,0 +1,61 @@ +# $Id$ +# ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL LICENSE BLOCK ***** + +FILE(GLOB SRC *.cpp) + +SET(INC + . + ../../../source/gameengine/Ketsji + ../../../source/gameengine/Expressions + ../../../source/gameengine/GameLogic + ../../../source/gameengine/SceneGraph + ../../../source/gameengine/Rasterizer + ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer + ../../../source/gameengine/BlenderRoutines + ../../../source/blender/include + ../../../source/blender/blenlib + ../../../source/blender/blenkernel + ../../../source/blender/makesdna + ../../../source/blender/editors/include + ../../../source/blender/imbuf + ../../../source/blender/python + ../../../source/blender/gpu + ../../../source/kernel/gen_system + ../../../intern/string + ../../../intern/moto/include + ../../../intern/guardedalloc + ../../../extern/glew/include + ${PYTHON_INC} +) + +IF(WITH_FFMPEG) + SET(INC ${INC} ${FFMPEG_INC} ${PTHREADS_INC}) + ADD_DEFINITIONS(-DWITH_FFMPEG) + ADD_DEFINITIONS(-D__STDC_CONSTANT_MACROS) +ENDIF(WITH_FFMPEG) + +BLENDERLIB(bf_videotex "${SRC}" "${INC}") +#env.BlenderLib ( 'bf_videotex', sources, Split(incs), [], libtype=['game','player'], priority=[25, 72], compileflags = cflags ) diff --git a/source/gameengine/VideoTexture/Common.h b/source/gameengine/VideoTexture/Common.h new file mode 100644 index 00000000000..f771077bbba --- /dev/null +++ b/source/gameengine/VideoTexture/Common.h @@ -0,0 +1,55 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2006 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if defined WIN32 +#define WINDOWS_LEAN_AND_MEAN +#endif + +#if !defined NULL +#define NULL 0 +#endif + +#if !defined HRESULT +#define HRESULT long +#endif + +#if !defined DWORD +#define DWORD unsigned long +#endif + +#if !defined S_OK +#define S_OK ((HRESULT)0L) +#endif + +#if !defined BYTE +#define BYTE unsigned char +#endif + +#if !defined WIN32 +#define Sleep(time) sleep(time) +#endif + +#if !defined FAILED +#define FAILED(Status) ((HRESULT)(Status)<0) +#endif + +#include <iostream> diff --git a/source/gameengine/VideoTexture/Exception.cpp b/source/gameengine/VideoTexture/Exception.cpp new file mode 100644 index 00000000000..35d335b5981 --- /dev/null +++ b/source/gameengine/VideoTexture/Exception.cpp @@ -0,0 +1,215 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2006 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + + +#include <sstream> +#include <fstream> + +#include <PyObjectPlus.h> + +#include "Exception.h" + + +// exception identificators +ExceptionID ErrGeneral, ErrNotFound; + +// exception descriptions +ExpDesc errGenerDesc (ErrGeneral, "General Error"); +ExpDesc errNFoundDesc (ErrNotFound, "Error description not found"); + + + +// implementation of ExpDesc + +// constructor +ExpDesc::ExpDesc (ExceptionID & exp, char * desc, RESULT hres) +: m_expID(exp), m_hRslt(hres), m_description(desc) +{ +} + +// destructor +ExpDesc::~ExpDesc (void) {} + +// list of descriptions +std::vector<ExpDesc*> ExpDesc::m_expDescs; + + +// class Exception + + +// last exception description +std::string Exception::m_lastError; + +// log file name +char * Exception::m_logFile = NULL; + + +// basic constructor +Exception::Exception () +{ + // default values + m_expID = &ErrNotFound; + m_hRslt = S_OK; + m_line = 0; +} + + +// destructor +Exception::~Exception () throw() { } + + +// copy constructor +Exception::Exception (const Exception & xpt) +{ copy (xpt); } + + +// assignment operator +Exception & Exception::operator= (const Exception & xpt) +{ copy (xpt); return *this; } + + +// get exception description +const char * Exception::what() +{ + // set exception description + setXptDesc(); + // return c string + return m_desc.c_str(); +} + + +// debug version - with file and line of exception +Exception::Exception (ExceptionID & expID, RESULT rslt, char * fil, int lin) +: m_expID (&expID), m_hRslt (rslt) +{ + // set file and line + if (strlen(fil) > 0 || lin > 0) + setFileLine (fil, lin); +} + + +// set file and line +void Exception::setFileLine (char * fil, int lin) +{ + if (fil != NULL) m_fileName = fil; + m_line = lin; +} + + +// report exception +void Exception::report(void) +{ + // set exception description + setXptDesc(); + // set python error + PyErr_SetString(PyExc_RuntimeError, what()); + // if log file is set + if (m_logFile != NULL) + { + // write description to log + std::ofstream logf (m_logFile, std::ios_base::app); + logf << m_fileName << ':' << m_line << ':' << m_desc << std::endl; + logf.flush(); + logf.close(); + } +} + + +// set exception description +void Exception::setXptDesc (void) +{ + // if description is not set + if (m_desc.size() == 0) + { + // start of search -1 + // found description "NotFound" 0 + // found description without matching result 1 + // found description with matching result 2 + int best = -1; + // find exception description + for (std::vector<ExpDesc*>::iterator it = ExpDesc::m_expDescs.begin(); it != ExpDesc::m_expDescs.end(); ++it) + { + // use "NotFound", if there is not better + if (best < 0 && (*it)->isExp(&ErrNotFound) > 0) + { + (*it)->loadDesc(m_desc); + best = 0; + } + // match exception + int nBest = (*it)->isExp(m_expID, m_hRslt); + // if exception is matching better + if (nBest > 0 && best < nBest) + { + // set description + (*it)->loadDesc(m_desc); + best = nBest; + // if matching exactly, finish search + if (best == 2) break; + } + } + // add result code + // length of result code + const size_t rsltSize = 11; + // delimit description + //const char delimRslt[] = ": "; + // set text of description + char rsltTxt[rsltSize]; + std::ostringstream os; + os << std::hex << m_hRslt << ": " << '\0'; + // copy result to description + m_desc.insert(0, rsltTxt); + // copy exception description to last exception string + m_lastError = m_desc; + } +} + + +// copy exception data +void Exception::copy (const Exception & xpt) +{ + // standard data + m_expID = xpt.m_expID; + m_hRslt = xpt.m_hRslt; + m_desc = xpt.m_desc; + + // debug data + m_fileName = xpt.m_fileName; + m_line = xpt.m_line; +} + +void registerAllExceptions(void) +{ + errGenerDesc.registerDesc(); + errNFoundDesc.registerDesc(); + MaterialNotAvailDesc.registerDesc(); + ImageSizesNotMatchDesc.registerDesc(); + SceneInvalidDesc.registerDesc(); + CameraInvalidDesc.registerDesc(); + ObserverInvalidDesc.registerDesc(); + MirrorInvalidDesc.registerDesc(); + MirrorSizeInvalidDesc.registerDesc(); + MirrorNormalInvalidDesc.registerDesc(); + MirrorHorizontalDesc.registerDesc(); + MirrorTooSmallDesc.registerDesc(); + SourceVideoEmptyDesc.registerDesc(); + SourceVideoCreationDesc.registerDesc(); +} diff --git a/source/gameengine/VideoTexture/Exception.h b/source/gameengine/VideoTexture/Exception.h new file mode 100644 index 00000000000..1a3c25071b1 --- /dev/null +++ b/source/gameengine/VideoTexture/Exception.h @@ -0,0 +1,216 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2006 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + + +#if !defined EXCEPTION_H +#define EXCEPTION_H + +#include <exception> +#include <vector> +#include <string> +#include <algorithm> + +#include "Common.h" + + +#define CHCKHRSLTV(fnc,val,err) \ +{ \ + HRESULT macroHRslt = (fnc); \ + if (macroHRslt != val) \ + throw Exception (err, macroHRslt, __FILE__, __LINE__); \ +} + +#define THRWEXCP(err,hRslt) throw Exception (err, hRslt, __FILE__, __LINE__); + + +#if defined WIN32 + +#define CHCKHRSLT(fnc,err) \ +{ \ + HRESULT macroHRslt = (fnc); \ + if (FAILED(macroHRslt)) \ + throw Exception (err, macroHRslt, __FILE__, __LINE__); \ +} + +#else + +#define CHCKHRSLT(fnc,err) CHCKHRSLTV(fnc,S_OK,err) + +#endif + + +// forward declarations +class ExceptionID; +class Exception; + + +// exception identificators +extern ExceptionID ErrGeneral, ErrNotFound; + + +// result type +typedef long RESULT; + + +// class ExceptionID for exception identification +class ExceptionID +{ +public: + // constructor a destructor + ExceptionID (void) {} + ~ExceptionID (void) {} + +private: + // not allowed + ExceptionID (const ExceptionID & obj) throw() {} + ExceptionID & operator= (const ExceptionID & obj) throw() { return *this; } +}; + + +// class ExpDesc for exception description +class ExpDesc +{ +public: + // constructor a destructor + ExpDesc (ExceptionID & exp, char * desc, RESULT hres = S_OK); + ~ExpDesc (void); + + // comparision function + // returns 0, if exception identification don't match at all + // returns 1, if only exception identification is matching + // returns 2, if both exception identification and result are matching + int isExp (ExceptionID * exp, RESULT hres = S_OK) throw() + { + // check exception identification + if (&m_expID == exp) + { + // check result value + if (m_hRslt == hres) return 2; + // only identification match + if (m_hRslt == S_OK) return 1; + } + // no match + return 0; + } + + // get exception description + void loadDesc (std::string & desc) throw() + { + desc = m_description; + } + + void registerDesc(void) + { + if (std::find(m_expDescs.begin(), m_expDescs.end(), this) == m_expDescs.end()) + m_expDescs.push_back(this); + } + // list of exception descriptions + static std::vector<ExpDesc*> m_expDescs; + +private: + // exception ID + ExceptionID & m_expID; + // result + RESULT m_hRslt; + // description + char * m_description; + + // not allowed + ExpDesc (const ExpDesc & obj) : m_expID (ErrNotFound) {} + ExpDesc & operator= (const ExpDesc & obj) { return *this; } +}; + + + +// class Exception +class Exception : public std::exception +{ +public: + // constructor + Exception (); + // destructor + virtual ~Exception () throw(); + // copy constructor + Exception (const Exception & xpt); + // assignment operator + Exception & operator= (const Exception & xpt); + // get exception description + virtual const char * what(void); + + // debug version of constructor + Exception (ExceptionID & expID, RESULT rslt, char * fil, int lin); + // set source file and line of exception + void setFileLine (char * fil, int lin); + + // get description in string + std::string & getDesc (void) throw() { return m_desc; } + + // report exception + virtual void report (void); + + // get exception id + ExceptionID * getID (void) throw() { return m_expID; } + + /// last exception description + static std::string m_lastError; + + /// log file name + static char * m_logFile; + +protected: + // exception identification + ExceptionID * m_expID; + // RESULT code + RESULT m_hRslt; + + // exception description + std::string m_desc; + + // set exception description + virtual void setXptDesc (void); + + // copy exception + void copy (const Exception & xpt); + + // file name where exception was thrown + std::string m_fileName; + // line number in file + int m_line; + +}; + +extern ExpDesc MaterialNotAvailDesc; +extern ExpDesc ImageSizesNotMatchDesc; +extern ExpDesc SceneInvalidDesc; +extern ExpDesc CameraInvalidDesc; +extern ExpDesc ObserverInvalidDesc; +extern ExpDesc MirrorInvalidDesc; +extern ExpDesc MirrorSizeInvalidDesc; +extern ExpDesc MirrorNormalInvalidDesc; +extern ExpDesc MirrorHorizontalDesc; +extern ExpDesc MirrorTooSmallDesc; +extern ExpDesc SourceVideoEmptyDesc; +extern ExpDesc SourceVideoCreationDesc; + + +void registerAllExceptions(void); +#endif diff --git a/source/gameengine/VideoTexture/FilterBase.cpp b/source/gameengine/VideoTexture/FilterBase.cpp new file mode 100644 index 00000000000..b2abd4354fd --- /dev/null +++ b/source/gameengine/VideoTexture/FilterBase.cpp @@ -0,0 +1,150 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#include "FilterBase.h" + +#include <PyObjectPlus.h> +#include <structmember.h> + + +// FilterBase class implementation + +// constructor +FilterBase::FilterBase (void) : m_previous(NULL) {} + + +// destructor +FilterBase::~FilterBase (void) +{ + // release Python objects, if not released yet + release(); +} + + +// release python objects +void FilterBase::release (void) +{ + // release previous filter object + setPrevious(NULL); +} + + +// set new previous filter +void FilterBase::setPrevious (PyFilter * filt, bool useRefCnt) +{ + // if reference counting has to be used + if (useRefCnt) + { + // reference new filter + if (filt != NULL) Py_INCREF(filt); + // release old filter + Py_XDECREF(m_previous); + } + // set new previous filter + m_previous = filt; +} + + +// find first filter +FilterBase * FilterBase::findFirst (void) +{ + // find first filter in chain + FilterBase * frst; + for (frst = this; frst->m_previous != NULL; frst = frst->m_previous->m_filter) {}; + // set first filter + return frst; +} + + + +// list offilter types +PyTypeList pyFilterTypes; + + + +// functions for python interface + + +// object allocation +PyObject * Filter_allocNew (PyTypeObject * type, PyObject * args, PyObject * kwds) +{ + // allocate object + PyFilter * self = reinterpret_cast<PyFilter*>(type->tp_alloc(type, 0)); + // initialize object structure + self->m_filter = NULL; + // return allocated object + return reinterpret_cast<PyObject*>(self); +} + +// object deallocation +void Filter_dealloc (PyFilter * self) +{ + // release object attributes + if (self->m_filter != NULL) + { + self->m_filter->release(); + delete self->m_filter; + self->m_filter = NULL; + } +} + + +// get previous pixel filter object +PyObject * Filter_getPrevious (PyFilter * self, void * closure) +{ + // if filter object is available + if (self->m_filter != NULL) + { + // pixel filter object + PyObject * filt = reinterpret_cast<PyObject*>(self->m_filter->getPrevious()); + // if filter is present + if (filt != NULL) + { + // return it + Py_INCREF(filt); + return filt; + } + } + // otherwise return none + Py_RETURN_NONE; +} + + +// set previous pixel filter object +int Filter_setPrevious (PyFilter * self, PyObject * value, void * closure) +{ + // if filter object is available + if (self->m_filter != NULL) + { + // check new value + if (value == NULL || !pyFilterTypes.in(value->ob_type)) + { + // report value error + PyErr_SetString(PyExc_TypeError, "Invalid type of value"); + return -1; + } + // set new value + self->m_filter->setPrevious(reinterpret_cast<PyFilter*>(value)); + } + // return success + return 0; +} diff --git a/source/gameengine/VideoTexture/FilterBase.h b/source/gameengine/VideoTexture/FilterBase.h new file mode 100644 index 00000000000..b6080f018d5 --- /dev/null +++ b/source/gameengine/VideoTexture/FilterBase.h @@ -0,0 +1,138 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined FILTERBASE_H +#define FILTERBASE_H + +#include "Common.h" + +#include <PyObjectPlus.h> + +#include "PyTypeList.h" + +#define VT_C(v,idx) ((unsigned char*)&v)[idx] +#define VT_R(v) ((unsigned char*)&v)[0] +#define VT_G(v) ((unsigned char*)&v)[1] +#define VT_B(v) ((unsigned char*)&v)[2] +#define VT_A(v) ((unsigned char*)&v)[3] +#define VT_RGBA(v,r,g,b,a) VT_R(v)=(unsigned char)r, VT_G(v)=(unsigned char)g, VT_B(v)=(unsigned char)b, VT_A(v)=(unsigned char)a + +// forward declaration +class FilterBase; + + +// python structure for filter +struct PyFilter +{ + PyObject_HEAD + // source object + FilterBase * m_filter; +}; + + +/// base class for pixel filters +class FilterBase +{ +public: + /// constructor + FilterBase (void); + /// destructor + virtual ~FilterBase (void); + // release python objects + virtual void release (void); + + /// convert pixel + template <class SRC> unsigned int convert (SRC src, short x, short y, + short * size, unsigned int pixSize) + { + return filter(src, x, y, size, pixSize, + convertPrevious(src, x, y, size, pixSize)); + } + + /// get previous filter + PyFilter * getPrevious (void) { return m_previous; } + /// set previous filter + void setPrevious (PyFilter * filt, bool useRefCnt = true); + + /// find first filter in chain + FilterBase * findFirst (void); + + /// get first filter's source pixel size + unsigned int firstPixelSize (void) { return findFirst()->getPixelSize(); } + +protected: + /// previous pixel filter + PyFilter * m_previous; + + /// filter pixel, source byte buffer + virtual unsigned int filter (unsigned char * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { return val; } + /// filter pixel, source int buffer + virtual unsigned int filter (unsigned int * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { return val; } + + /// get source pixel size + virtual unsigned int getPixelSize (void) { return 1; } + + /// get converted pixel from previous filters + template <class SRC> unsigned int convertPrevious (SRC src, short x, short y, + short * size, unsigned int pixSize) + { + // if previous filter doesn't exists, return source pixel + if (m_previous == NULL) return *src; + // otherwise return converted pixel + return m_previous->m_filter->convert(src, x, y, size, pixSize); + } +}; + + +// list of python filter types +extern PyTypeList pyFilterTypes; + + +// functions for python interface + +// object initialization +template <class T> static int Filter_init (PyObject * pySelf, PyObject * args, PyObject * kwds) +{ + PyFilter * self = reinterpret_cast<PyFilter*>(pySelf); + // create filter object + if (self->m_filter != NULL) delete self->m_filter; + self->m_filter = new T(); + // initialization succeded + return 0; +} + +// object allocation +PyObject * Filter_allocNew (PyTypeObject * type, PyObject * args, PyObject * kwds); +// object deallocation +void Filter_dealloc (PyFilter * self); + +// get previous pixel filter object +PyObject * Filter_getPrevious (PyFilter * self, void * closure); +// set previous pixel filter object +int Filter_setPrevious (PyFilter * self, PyObject * value, void * closure); + + +#endif diff --git a/source/gameengine/VideoTexture/FilterBlueScreen.cpp b/source/gameengine/VideoTexture/FilterBlueScreen.cpp new file mode 100644 index 00000000000..2a624b2ccaa --- /dev/null +++ b/source/gameengine/VideoTexture/FilterBlueScreen.cpp @@ -0,0 +1,177 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + + +#include <PyObjectPlus.h> +#include <structmember.h> + +#include "FilterBlueScreen.h" + +#include "FilterBase.h" +#include "PyTypeList.h" + +// implementation FilterBlueScreen + +// constructor +FilterBlueScreen::FilterBlueScreen (void) +{ + // set color to blue + setColor(0, 0, 255); + // set limits + setLimits(64, 64); +} + +// set color +void FilterBlueScreen::setColor (unsigned char red, unsigned char green, unsigned char blue) +{ + m_color[0] = red; + m_color[1] = green; + m_color[2] = blue; +} + +// set limits for color variation +void FilterBlueScreen::setLimits (unsigned short minLimit, unsigned short maxLimit) +{ + m_limits[0] = minLimit; + m_limits[1] = maxLimit > minLimit ? maxLimit : minLimit; + // calculate square values + for (short idx = 0; idx < 2; ++idx) + m_squareLimits[idx] = m_limits[idx] * m_limits[idx]; + // limits distance + m_limitDist = m_squareLimits[1] - m_squareLimits[0]; +} + + + +// cast Filter pointer to FilterBlueScreen +inline FilterBlueScreen * getFilter (PyFilter * self) +{ return static_cast<FilterBlueScreen*>(self->m_filter); } + + +// python methods and get/sets + +// get color +static PyObject * getColor (PyFilter * self, void * closure) +{ + return Py_BuildValue("[BBB]", getFilter(self)->getColor()[0], + getFilter(self)->getColor()[1], getFilter(self)->getColor()[2]); +} + +// set color +static int setColor (PyFilter * self, PyObject * value, void * closure) +{ + // check validity of parameter + if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 3 + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0)) + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1)) + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 2))) + { + PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 3 ints"); + return -1; + } + // set color + getFilter(self)->setColor((unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 0))), + (unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 1))), + (unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 2)))); + // success + return 0; +} + +// get limits +static PyObject * getLimits (PyFilter * self, void * closure) +{ + return Py_BuildValue("[II]", getFilter(self)->getLimits()[0], + getFilter(self)->getLimits()[1]); +} + +// set limit +static int setLimits (PyFilter * self, PyObject * value, void * closure) +{ + // check validity of parameter + if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 2 + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0)) + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1))) + { + PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 ints"); + return -1; + } + // set limits + getFilter(self)->setLimits((unsigned short)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 0))), + (unsigned short)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 1)))); + // success + return 0; +} + + +// attributes structure +static PyGetSetDef filterBSGetSets[] = +{ + {(char*)"color", (getter)getColor, (setter)setColor, (char*)"blue screen color", NULL}, + {(char*)"limits", (getter)getLimits, (setter)setLimits, (char*)"blue screen color limits", NULL}, + // attributes from FilterBase class + {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL}, + {NULL} +}; + +// define python type +PyTypeObject FilterBlueScreenType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.FilterBlueScreen", /*tp_name*/ + sizeof(PyFilter), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Filter_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Filter for Blue Screen objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + NULL, /* tp_methods */ + 0, /* tp_members */ + filterBSGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Filter_init<FilterBlueScreen>, /* tp_init */ + 0, /* tp_alloc */ + Filter_allocNew, /* tp_new */ +}; + diff --git a/source/gameengine/VideoTexture/FilterBlueScreen.h b/source/gameengine/VideoTexture/FilterBlueScreen.h new file mode 100644 index 00000000000..820e4a44501 --- /dev/null +++ b/source/gameengine/VideoTexture/FilterBlueScreen.h @@ -0,0 +1,97 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of blendTex library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined FILTERBLUESCREEN_H +#define FILTERBLUESCREEN_H + +#include "Common.h" + +#include "FilterBase.h" + + +/// pixel filter for blue screen +class FilterBlueScreen : public FilterBase +{ +public: + /// constructor + FilterBlueScreen (void); + /// destructor + virtual ~FilterBlueScreen (void) {} + + /// get color + unsigned char * getColor (void) { return m_color; } + /// set color + void setColor (unsigned char red, unsigned char green, unsigned char blue); + + /// get limits for color variation + unsigned short * getLimits (void) { return m_limits; } + /// set limits for color variation + void setLimits (unsigned short minLimit, unsigned short maxLimit); + +protected: + /// blue screen color (red component first) + unsigned char m_color[3]; + /// limits for color variation - first defines, where ends fully transparent + /// color, second defines, where begins fully opaque color + unsigned short m_limits[2]; + /// squared limits for color variation + unsigned int m_squareLimits[2]; + /// distance between squared limits + unsigned int m_limitDist; + + /// filter pixel template, source int buffer + template <class SRC> unsigned int tFilter (SRC src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { + // calculate differences + int difRed = int(VT_R(val)) - int(m_color[0]); + int difGreen = int(VT_G(val)) - int(m_color[1]); + int difBlue = int(VT_B(val)) - int(m_color[2]); + // calc distance from "blue screen" color + unsigned int dist = (unsigned int)(difRed * difRed + difGreen * difGreen + + difBlue * difBlue); + // condition for fully transparent color + if (m_squareLimits[0] >= dist) + // return color with zero alpha + VT_A(val) = 0; + // condition for fully opaque color + else if (m_squareLimits[1] <= dist) + // return normal colour + VT_A(val) = 0xFF; + // otherwise calc alpha + else + VT_A(val) = (((dist - m_squareLimits[0]) << 8) / m_limitDist); + return val; + } + + /// virtual filtering function for byte source + virtual unsigned int filter (unsigned char * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { return tFilter(src, x, y, size, pixSize, val); } + /// virtual filtering function for unsigned int source + virtual unsigned int filter (unsigned int * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { return tFilter(src, x, y, size, pixSize, val); } +}; + + +#endif diff --git a/source/gameengine/VideoTexture/FilterColor.cpp b/source/gameengine/VideoTexture/FilterColor.cpp new file mode 100644 index 00000000000..e5d479747c4 --- /dev/null +++ b/source/gameengine/VideoTexture/FilterColor.cpp @@ -0,0 +1,347 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + + +#include <PyObjectPlus.h> +#include <structmember.h> + +#include "FilterColor.h" + +#include "FilterBase.h" +#include "PyTypeList.h" + +// implementation FilterGray + +// attributes structure +static PyGetSetDef filterGrayGetSets[] = +{ // attributes from FilterBase class + {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL}, + {NULL} +}; + +// define python type +PyTypeObject FilterGrayType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.FilterGray", /*tp_name*/ + sizeof(PyFilter), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Filter_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Filter for gray scale effect", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + NULL, /* tp_methods */ + 0, /* tp_members */ + filterGrayGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Filter_init<FilterGray>, /* tp_init */ + 0, /* tp_alloc */ + Filter_allocNew, /* tp_new */ +}; + + +// implementation FilterColor + +// constructor +FilterColor::FilterColor (void) +{ + // reset color matrix to identity + for (int r = 0; r < 4; ++r) + for (int c = 0; c < 5; ++c) + m_matrix[r][c] = (r == c) ? 256 : 0; +} + +// set color matrix +void FilterColor::setMatrix (ColorMatrix & mat) +{ + // copy matrix + for (int r = 0; r < 4; ++r) + for (int c = 0; c < 5; ++c) + m_matrix[r][c] = mat[r][c]; +} + + + +// cast Filter pointer to FilterColor +inline FilterColor * getFilterColor (PyFilter * self) +{ return static_cast<FilterColor*>(self->m_filter); } + + +// python methods and get/sets + +// get color matrix +static PyObject * getMatrix (PyFilter * self, void * closure) +{ + ColorMatrix & mat = getFilterColor(self)->getMatrix(); + return Py_BuildValue("((hhhhh)(hhhhh)(hhhhh)(hhhhh))", + mat[0][0], mat[0][1], mat[0][2], mat[0][3], mat[0][4], + mat[1][0], mat[1][1], mat[1][2], mat[1][3], mat[1][4], + mat[2][0], mat[2][1], mat[2][2], mat[2][3], mat[2][4], + mat[3][0], mat[3][1], mat[3][2], mat[3][3], mat[3][4]); +} + +// set color matrix +static int setMatrix (PyFilter * self, PyObject * value, void * closure) +{ + // matrix to store items + ColorMatrix mat; + // check validity of parameter + bool valid = value != NULL && PySequence_Check(value) + && PySequence_Length(value) == 4; + // check rows + for (int r = 0; valid && r < 4; ++r) + { + // get row object + PyObject * row = PySequence_Fast_GET_ITEM(value, r); + // check sequence + valid = PySequence_Check(row) && PySequence_Length(row) == 5; + // check items + for (int c = 0; valid && c < 5; ++c) + { + // item must be int + valid = PyLong_Check(PySequence_Fast_GET_ITEM(row, c)); + // if it is valid, save it in matrix + if (valid) + mat[r][c] = short(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(row, c))); + } + } + // if parameter is not valid, report error + if (!valid) + { + PyErr_SetString(PyExc_TypeError, "The value must be a matrix [4][5] of ints"); + return -1; + } + // set color matrix + getFilterColor(self)->setMatrix(mat); + // success + return 0; +} + + +// attributes structure +static PyGetSetDef filterColorGetSets[] = +{ + {(char*)"matrix", (getter)getMatrix, (setter)setMatrix, (char*)"matrix [4][5] for color calculation", NULL}, + // attributes from FilterBase class + {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL}, + {NULL} +}; + +// define python type +PyTypeObject FilterColorType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.FilterColor", /*tp_name*/ + sizeof(PyFilter), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Filter_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Filter for color calculations", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + NULL, /* tp_methods */ + 0, /* tp_members */ + filterColorGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Filter_init<FilterColor>, /* tp_init */ + 0, /* tp_alloc */ + Filter_allocNew, /* tp_new */ +}; + +// implementation FilterLevel + +// constructor +FilterLevel::FilterLevel (void) +{ + // reset color levels + for (int r = 0; r < 4; ++r) + { + levels[r][0] = 0; + levels[r][1] = 0xFF; + levels[r][2] = 0xFF; + } +} + +// set color levels +void FilterLevel::setLevels (ColorLevel & lev) +{ + // copy levels + for (int r = 0; r < 4; ++r) + { + for (int c = 0; c < 2; ++c) + levels[r][c] = lev[r][c]; + levels[r][2] = lev[r][0] < lev[r][1] ? lev[r][1] - lev[r][0] : 1; + } +} + + +// cast Filter pointer to FilterLevel +inline FilterLevel * getFilterLevel (PyFilter * self) +{ return static_cast<FilterLevel*>(self->m_filter); } + + +// python methods and get/sets + +// get color levels +static PyObject * getLevels (PyFilter * self, void * closure) +{ + ColorLevel & lev = getFilterLevel(self)->getLevels(); + return Py_BuildValue("((HH)(HH)(HH)(HH))", + lev[0][0], lev[0][1], lev[1][0], lev[1][1], + lev[2][0], lev[2][1], lev[3][0], lev[3][1]); +} + +// set color levels +static int setLevels (PyFilter * self, PyObject * value, void * closure) +{ + // matrix to store items + ColorLevel lev; + // check validity of parameter + bool valid = value != NULL && PySequence_Check(value) + && PySequence_Length(value) == 4; + // check rows + for (int r = 0; valid && r < 4; ++r) + { + // get row object + PyObject * row = PySequence_Fast_GET_ITEM(value, r); + // check sequence + valid = PySequence_Check(row) && PySequence_Length(row) == 2; + // check items + for (int c = 0; valid && c < 2; ++c) + { + // item must be int + valid = PyLong_Check(PySequence_Fast_GET_ITEM(row, c)); + // if it is valid, save it in matrix + if (valid) + lev[r][c] = (unsigned short)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(row, c))); + } + } + // if parameter is not valid, report error + if (!valid) + { + PyErr_SetString(PyExc_TypeError, "The value must be a matrix [4][2] of ints"); + return -1; + } + // set color matrix + getFilterLevel(self)->setLevels(lev); + // success + return 0; +} + + +// attributes structure +static PyGetSetDef filterLevelGetSets[] = +{ + {(char*)"levels", (getter)getLevels, (setter)setLevels, (char*)"levels matrix [4] (min, max)", NULL}, + // attributes from FilterBase class + {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL}, + {NULL} +}; + +// define python type +PyTypeObject FilterLevelType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.FilterLevel", /*tp_name*/ + sizeof(PyFilter), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Filter_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Filter for levels calculations", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + NULL, /* tp_methods */ + 0, /* tp_members */ + filterLevelGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Filter_init<FilterLevel>, /* tp_init */ + 0, /* tp_alloc */ + Filter_allocNew, /* tp_new */ +}; + diff --git a/source/gameengine/VideoTexture/FilterColor.h b/source/gameengine/VideoTexture/FilterColor.h new file mode 100644 index 00000000000..b7e52c4521c --- /dev/null +++ b/source/gameengine/VideoTexture/FilterColor.h @@ -0,0 +1,168 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of blendTex library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined FILTERCOLOR_H +#define FILTERCOLOR_H + +#include "Common.h" + +#include "FilterBase.h" + + +/// pixel filter for gray scale +class FilterGray : public FilterBase +{ +public: + /// constructor + FilterGray (void) {} + /// destructor + virtual ~FilterGray (void) {} + +protected: + /// filter pixel template, source int buffer + template <class SRC> unsigned int tFilter (SRC src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { + // calculate gray value + unsigned int gray = (28 * (VT_B(val)) + 151 * (VT_G(val)) + + 77 * (VT_R(val))) >> 8; + // return gray scale value + VT_R(val) = gray; + VT_G(val) = gray; + VT_B(val) = gray; + return val; + } + + /// virtual filtering function for byte source + virtual unsigned int filter (unsigned char * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { return tFilter(src, x, y, size, pixSize, val); } + /// virtual filtering function for unsigned int source + virtual unsigned int filter (unsigned int * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { return tFilter(src, x, y, size, pixSize, val); } +}; + + +/// type for color matrix +typedef short ColorMatrix[4][5]; + +/// pixel filter for color calculation +class FilterColor : public FilterBase +{ +public: + /// constructor + FilterColor (void); + /// destructor + virtual ~FilterColor (void) {} + + /// get color matrix + ColorMatrix & getMatrix (void) { return m_matrix; } + /// set color matrix + void setMatrix (ColorMatrix & mat); + +protected: + /// color calculation matrix + ColorMatrix m_matrix; + + /// calculate one color component + unsigned char calcColor (unsigned int val, short idx) + { + return (((m_matrix[idx][0] * (VT_R(val)) + m_matrix[idx][1] * (VT_G(val)) + + m_matrix[idx][2] * (VT_B(val)) + m_matrix[idx][3] * (VT_A(val)) + + m_matrix[idx][4]) >> 8) & 0xFF); + } + + /// filter pixel template, source int buffer + template <class SRC> unsigned int tFilter (SRC src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { + // return calculated color + int color; + VT_RGBA(color, calcColor(val, 0), calcColor(val, 1), calcColor(val, 2), calcColor(val, 3)); + return color; + } + + /// virtual filtering function for byte source + virtual unsigned int filter (unsigned char * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { return tFilter(src, x, y, size, pixSize, val); } + /// virtual filtering function for unsigned int source + virtual unsigned int filter (unsigned int * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { return tFilter(src, x, y, size, pixSize, val); } +}; + + +/// type for color levels +typedef unsigned short ColorLevel[4][3]; + +/// pixel filter for color calculation +class FilterLevel : public FilterBase +{ +public: + /// constructor + FilterLevel (void); + /// destructor + virtual ~FilterLevel (void) {} + + /// get color matrix + ColorLevel & getLevels (void) { return levels; } + /// set color matrix + void setLevels (ColorLevel & lev); + +protected: + /// color calculation matrix + ColorLevel levels; + + /// calculate one color component + unsigned int calcColor (unsigned int val, short idx) + { + unsigned int col = VT_C(val,idx);; + if (col <= levels[idx][0]) col = 0; + else if (col >= levels[idx][1]) col = 0xFF; + else col = (((col - levels[idx][0]) << 8) / levels[idx][2]) & 0xFF; + return col; + } + + /// filter pixel template, source int buffer + template <class SRC> unsigned int tFilter (SRC src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { + // return calculated color + int color; + VT_RGBA(color, calcColor(val, 0), calcColor(val, 1), calcColor(val, 2), calcColor(val, 3)); + return color; + } + + /// virtual filtering function for byte source + virtual unsigned int filter (unsigned char * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { return tFilter(src, x, y, size, pixSize, val); } + /// virtual filtering function for unsigned int source + virtual unsigned int filter (unsigned int * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { return tFilter(src, x, y, size, pixSize, val); } +}; + + +#endif diff --git a/source/gameengine/VideoTexture/FilterNormal.cpp b/source/gameengine/VideoTexture/FilterNormal.cpp new file mode 100644 index 00000000000..d755e6294c9 --- /dev/null +++ b/source/gameengine/VideoTexture/FilterNormal.cpp @@ -0,0 +1,166 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + + +#include <PyObjectPlus.h> +#include <structmember.h> + +#include "FilterNormal.h" + +#include "FilterBase.h" +#include "PyTypeList.h" + +// implementation FilterNormal + +// constructor +FilterNormal::FilterNormal (void) : m_colIdx(0) +{ + // set default depth + setDepth(4); +} + +// set color shift +void FilterNormal::setColor (unsigned short colIdx) +{ + // check validity of index + if (colIdx < 3) + // set color shift + m_colIdx = colIdx; +} + +// set depth +void FilterNormal::setDepth (float depth) +{ + m_depth = depth; + m_depthScale = depth / depthScaleKoef; +} + + +// cast Filter pointer to FilterNormal +inline FilterNormal * getFilter (PyFilter * self) +{ return static_cast<FilterNormal*>(self->m_filter); } + + +// python methods and get/sets + +// get index of color used to calculate normal +static PyObject * getColor (PyFilter * self, void * closure) +{ + return Py_BuildValue("H", getFilter(self)->getColor()); +} + +// set index of color used to calculate normal +static int setColor (PyFilter * self, PyObject * value, void * closure) +{ + // check validity of parameter + if (value == NULL || !PyLong_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "filt.colorIdx = int: VideoTexture.FilterNormal, expected the value must be a int"); + return -1; + } + // set color index + getFilter(self)->setColor((unsigned short)(PyLong_AsSsize_t(value))); + // success + return 0; +} + + +// get depth +static PyObject * getDepth (PyFilter * self, void * closure) +{ + return Py_BuildValue("f", getFilter(self)->getDepth()); +} + +// set depth +static int setDepth (PyFilter * self, PyObject * value, void * closure) +{ + // check validity of parameter + if (value) + { + float depth= (float)PyFloat_AsDouble(value); + if ((depth==-1 && PyErr_Occurred()) == 0) /* no error converting to a float? */ + { + // set depth + getFilter(self)->setDepth(depth); + // success + return 0; + } + } + + PyErr_SetString(PyExc_TypeError, "filt.depth = float: VideoTexture.FilterNormal, expected the value must be a float"); + return -1; +} + + +// attributes structure +static PyGetSetDef filterNormalGetSets[] = +{ + {(char*)"colorIdx", (getter)getColor, (setter)setColor, (char*)"index of color used to calculate normal (0 - red, 1 - green, 2 - blue)", NULL}, + {(char*)"depth", (getter)getDepth, (setter)setDepth, (char*)"depth of relief", NULL}, + // attributes from FilterBase class + {(char*)"previous", (getter)Filter_getPrevious, (setter)Filter_setPrevious, (char*)"previous pixel filter", NULL}, + {NULL} +}; + +// define python type +PyTypeObject FilterNormalType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.FilterNormal", /*tp_name*/ + sizeof(PyFilter), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Filter_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Filter for Blue Screen objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + NULL, /* tp_methods */ + 0, /* tp_members */ + filterNormalGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Filter_init<FilterNormal>, /* tp_init */ + 0, /* tp_alloc */ + Filter_allocNew, /* tp_new */ +}; + diff --git a/source/gameengine/VideoTexture/FilterNormal.h b/source/gameengine/VideoTexture/FilterNormal.h new file mode 100644 index 00000000000..840043be9a1 --- /dev/null +++ b/source/gameengine/VideoTexture/FilterNormal.h @@ -0,0 +1,107 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of blendTex library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined FILTERNORMAL_H +#define FILTERNORMAL_H + +#include "Common.h" + +#include "FilterBase.h" + + +// scale constants for normals +const float depthScaleKoef = 255.0; +const float normScaleKoef = float(depthScaleKoef / 2.0); + + +/// pixel filter for normal mapping +class FilterNormal : public FilterBase +{ +public: + /// constructor + FilterNormal (void); + /// destructor + virtual ~FilterNormal (void) {} + + /// get index of color used to calculate normals + unsigned short getColor (void) { return m_colIdx; } + /// set index of color used to calculate normals + void setColor (unsigned short colIdx); + + /// get depth + float getDepth (void) { return m_depth; } + /// set depth + void setDepth (float depth); + +protected: + /// depth of normal relief + float m_depth; + /// scale to calculate normals + float m_depthScale; + + /// color index, 0=red, 1=green, 2=blue, 3=alpha + unsigned short m_colIdx; + + /// filter pixel, source int buffer + template <class SRC> unsigned int tFilter (SRC * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { + // get value of required color + int actPix = int(VT_C(val,m_colIdx)); + int upPix = actPix; + int leftPix = actPix; + // get upper and left pixel from actual pixel + if (y > 0) + { + val = convertPrevious(src - pixSize * size[0], x, y - 1, size, pixSize); + upPix = VT_C(val,m_colIdx); + } + if (x > 0) + { + val = convertPrevious(src - pixSize, x - 1, y, size, pixSize); + leftPix = VT_C(val,m_colIdx); + } + // height differences (from blue color) + float dx = (actPix - leftPix) * m_depthScale; + float dy = (actPix - upPix) * m_depthScale; + // normalize vector + float dz = float(normScaleKoef / sqrt(dx * dx + dy * dy + 1.0)); + dx = dx * dz + normScaleKoef; + dy = dy * dz + normScaleKoef; + dz += normScaleKoef; + // return normal vector converted to color + VT_RGBA(val, dx, dy, dz, 0xFF); + return val; + } + + /// filter pixel, source byte buffer + virtual unsigned int filter (unsigned char * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { return tFilter(src, x, y, size, pixSize, val); } + /// filter pixel, source int buffer + virtual unsigned int filter (unsigned int * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { return tFilter(src, x, y, size, pixSize, val); } +}; + + +#endif diff --git a/source/gameengine/VideoTexture/FilterSource.cpp b/source/gameengine/VideoTexture/FilterSource.cpp new file mode 100644 index 00000000000..4b67785edb3 --- /dev/null +++ b/source/gameengine/VideoTexture/FilterSource.cpp @@ -0,0 +1,168 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +// implementation + +#include <PyObjectPlus.h> +#include <structmember.h> + +#include "FilterSource.h" + +#include "FilterBase.h" +#include "PyTypeList.h" + + +// FilterRGB24 + +// define python type +PyTypeObject FilterRGB24Type = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.FilterRGB24", /*tp_name*/ + sizeof(PyFilter), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Filter_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Source filter RGB24 objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + NULL, /* tp_methods */ + 0, /* tp_members */ + NULL, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Filter_init<FilterRGB24>, /* tp_init */ + 0, /* tp_alloc */ + Filter_allocNew, /* tp_new */ +}; + +// FilterRGBA32 + +// define python type +PyTypeObject FilterRGBA32Type = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.FilterRGBA32", /*tp_name*/ + sizeof(PyFilter), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Filter_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Source filter RGBA32 objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + NULL, /* tp_methods */ + 0, /* tp_members */ + NULL, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Filter_init<FilterRGBA32>, /* tp_init */ + 0, /* tp_alloc */ + Filter_allocNew, /* tp_new */ +}; + +// FilterBGR24 + +// define python type +PyTypeObject FilterBGR24Type = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.FilterBGR24", /*tp_name*/ + sizeof(PyFilter), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Filter_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Source filter BGR24 objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + NULL, /* tp_methods */ + 0, /* tp_members */ + NULL, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Filter_init<FilterBGR24>, /* tp_init */ + 0, /* tp_alloc */ + Filter_allocNew, /* tp_new */ +}; + diff --git a/source/gameengine/VideoTexture/FilterSource.h b/source/gameengine/VideoTexture/FilterSource.h new file mode 100644 index 00000000000..254e0a02679 --- /dev/null +++ b/source/gameengine/VideoTexture/FilterSource.h @@ -0,0 +1,263 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of blendTex library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined FILTERSOURCE_H +#define FILTERSOURCE_H + +#include "Common.h" + +#include "FilterBase.h" + + +/// class for RGB24 conversion +class FilterRGB24 : public FilterBase +{ +public: + /// constructor + FilterRGB24 (void) {} + /// destructor + virtual ~FilterRGB24 (void) {} + + /// get source pixel size + virtual unsigned int getPixelSize (void) { return 3; } + +protected: + /// filter pixel, source byte buffer + virtual unsigned int filter (unsigned char * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { VT_RGBA(val,src[0],src[1],src[2],0xFF); return val; } +}; + +/// class for RGBA32 conversion +class FilterRGBA32 : public FilterBase +{ +public: + /// constructor + FilterRGBA32 (void) {} + /// destructor + virtual ~FilterRGBA32 (void) {} + + /// get source pixel size + virtual unsigned int getPixelSize (void) { return 4; } + +protected: + /// filter pixel, source byte buffer + virtual unsigned int filter (unsigned char * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { + if ((intptr_t(src)&0x3) == 0) + return *(unsigned int*)src; + else + { + VT_RGBA(val,src[0],src[1],src[2],src[3]); + return val; + } + } +}; + +/// class for BGR24 conversion +class FilterBGR24 : public FilterBase +{ +public: + /// constructor + FilterBGR24 (void) {} + /// destructor + virtual ~FilterBGR24 (void) {} + + /// get source pixel size + virtual unsigned int getPixelSize (void) { return 3; } + +protected: + /// filter pixel, source byte buffer + virtual unsigned int filter (unsigned char * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { VT_RGBA(val,src[2],src[1],src[0],0xFF); return val; } +}; + +/// class for YV12 conversion +class FilterYV12 : public FilterBase +{ +public: + /// constructor + FilterYV12 (void) {} + /// destructor + virtual ~FilterYV12 (void) {} + + /// get source pixel size + virtual unsigned int getPixelSize (void) { return 1; } + + /// set pointers to color buffers + void setBuffs (unsigned char * buff, short * size) + { + unsigned int buffSize = size[0] * size[1]; + m_buffV = buff + buffSize; + m_buffU = m_buffV + (buffSize >> 2); + m_pitchUV = size[0] >> 1; + } + +protected: + /// begin of V buffer + unsigned char * m_buffV; + /// begin of U buffer + unsigned char * m_buffU; + /// pitch for V & U buffers + short m_pitchUV; + + /// interpolation function + int interpol (int a, int b, int c, int d) + { return (9 * (b + c) - a - d + 8) >> 4; } + + /// common horizontal interpolation + int interpolH (unsigned char * src) + { return interpol(*(src-1), *src, *(src+1), *(src+2)); } + + /// common vertical interpolation + int interpolV (unsigned char * src) + { return interpol(*(src-m_pitchUV), *src, *(src+m_pitchUV), *(src+2*m_pitchUV)); } + + /// common joined vertical and horizontal interpolation + int interpolVH (unsigned char * src) + { + return interpol(interpolV(src-1), interpolV(src), interpolV(src+1), + interpolV(src+2)); + } + + /// is pixel on edge + bool isEdge (short x, short y, short * size) + { return x <= 1 || x >= size[0] - 4 || y <= 1 || y >= size[1] - 4; } + + /// get the first parameter on the low edge + unsigned char * interParA (unsigned char * src, short x, short size, short shift) + { return x > 1 ? src - shift : src; } + /// get the third parameter on the high edge + unsigned char * interParC (unsigned char * src, short x, short size, short shift) + { return x < size - 2 ? src + shift : src; } + /// get the fourth parameter on the high edge + unsigned char * interParD (unsigned char * src, short x, short size, short shift) + { return x < size - 4 ? src + 2 * shift : x < size - 2 ? src + shift : src; } + + /// horizontal interpolation on edges + int interpolEH (unsigned char * src, short x, short size) + { + return interpol(*interParA(src, x, size, 1), *src, + *interParC(src, x, size, 1), *interParD(src, x, size, 1)); + } + + /// vertical interpolation on edges + int interpolEV (unsigned char * src, short y, short size) + { + return interpol(*interParA(src, y, size, m_pitchUV), *src, + *interParC(src, y, size, m_pitchUV), *interParD(src, y, size, m_pitchUV)); + } + + /// joined vertical and horizontal interpolation on edges + int interpolEVH (unsigned char * src, short x, short y, short * size) + { + return interpol(interpolEV(interParA(src, x, size[0], 1), y, size[1]), + interpolEV(src, y, size[1]), interpolEV(interParC(src, x, size[0], 1), y, size[1]), + interpolEV(interParD(src, x, size[0], 1), y, size[1])); + } + + + /// filter pixel, source byte buffer + virtual unsigned int filter (unsigned char * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val) + { + // V & U offset + long offset = (x >> 1) + m_pitchUV * (y >> 1); + // get modified YUV -> CDE: C = Y - 16; D = U - 128; E = V - 128 + int c = *src - 16; + int d = m_buffU[offset] - 128; + int e = m_buffV[offset] - 128; + // if horizontal interpolation is needed + if ((x & 1) == 1) { + // if vertical interpolation is needed too + if ((y & 1) == 1) + { + // if this pixel is on the edge + if (isEdge(x, y, size)) + { + // get U & V from edge + d = interpolEVH(m_buffU + offset, x, y, size) - 128; + e = interpolEVH(m_buffV + offset, x, y, size) - 128; + } + // otherwise get U & V from inner range + else + { + d = interpolVH(m_buffU + offset) - 128; + e = interpolVH(m_buffV + offset) - 128; + } + // otherwise use horizontal interpolation only + } + else { + // if this pixel is on the edge + if (isEdge(x, y, size)) + { + // get U & V from edge + d = interpolEH(m_buffU + offset, x, size[0]) - 128; + e = interpolEH(m_buffV + offset, x, size[0]) - 128; + } + // otherwise get U & V from inner range + else + { + d = interpolH(m_buffU + offset) - 128; + e = interpolH(m_buffV + offset) - 128; + } + // otherwise if only vertical interpolation is needed + } + } + else if ((y & 1) == 1) { + // if this pixel is on the edge + if (isEdge(x, y, size)) + { + // get U & V from edge + d = interpolEV(m_buffU + offset, y, size[1]) - 128; + e = interpolEV(m_buffV + offset, y, size[1]) - 128; + } + // otherwise get U & V from inner range + else + { + d = interpolV(m_buffU + offset) - 128; + e = interpolV(m_buffV + offset) - 128; + } + } + // convert to RGB + // R = clip(( 298 * C + 409 * E + 128) >> 8) + // G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8) + // B = clip(( 298 * C + 516 * D + 128) >> 8) + int red = (298 * c + 409 * e + 128) >> 8; + if (red >= 0x100) red = 0xFF; + else if (red < 0) red = 0; + int green = (298 * c - 100 * d - 208 * e) >> 8; + if (green >= 0x100) green = 0xFF; + else if (green < 0) green = 0; + int blue = (298 * c + 516 * d + 128) >> 8; + if (blue >= 0x100) blue = 0xFF; + else if (blue < 0) blue = 0; + // return result + VT_RGBA(val, red, green, blue, 0xFF); + return val; + } +}; + + +#endif diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp new file mode 100644 index 00000000000..0740afed2c6 --- /dev/null +++ b/source/gameengine/VideoTexture/ImageBase.cpp @@ -0,0 +1,535 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#include "ImageBase.h" + +#include <vector> +#include <string.h> + +#include <PyObjectPlus.h> +#include <structmember.h> + +#include "FilterBase.h" + +#include "Exception.h" + + + +// ImageBase class implementation + +// constructor +ImageBase::ImageBase (bool staticSrc) : m_image(NULL), m_imgSize(0), +m_avail(false), m_scale(false), m_scaleChange(false), m_flip(false), +m_staticSources(staticSrc), m_pyfilter(NULL) +{ + m_size[0] = m_size[1] = 0; +} + + +// destructor +ImageBase::~ImageBase (void) +{ + // release image + delete [] m_image; +} + + +// release python objects +bool ImageBase::release (void) +{ + // iterate sources + for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it) + { + // release source object + delete *it; + *it = NULL; + } + // release filter object + Py_XDECREF(m_pyfilter); + m_pyfilter = NULL; + return true; +} + + +// get image +unsigned int * ImageBase::getImage (unsigned int texId) +{ + // if image is not available + if (!m_avail) + { + // if there are any sources + if (!m_sources.empty()) + { + // get images from sources + for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it) + // get source image + (*it)->getImage(); + // init image + init(m_sources[0]->getSize()[0], m_sources[0]->getSize()[1]); + } + // calculate new image + calcImage(texId); + } + // if image is available, return it, otherwise NULL + return m_avail ? m_image : NULL; +} + + +// refresh image source +void ImageBase::refresh (void) +{ + // invalidate this image + m_avail = false; + // refresh all sources + for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it) + (*it)->refresh(); +} + + +// get source object +PyImage * ImageBase::getSource (const char * id) +{ + // find source + ImageSourceList::iterator src = findSource(id); + // return it, if found + return src != m_sources.end() ? (*src)->getSource() : NULL; +} + + +// set source object +bool ImageBase::setSource (const char * id, PyImage * source) +{ + // find source + ImageSourceList::iterator src = findSource(id); + // check source loop + if (source != NULL && source->m_image->loopDetect(this)) + return false; + // if found, set new object + if (src != m_sources.end()) + // if new object is not empty or sources are static + if (source != NULL || m_staticSources) + // replace previous source + (*src)->setSource(source); + // otherwise delete source + else + m_sources.erase(src); + // if source is not found and adding is allowed + else + if (!m_staticSources) + { + // create new source + ImageSource * newSrc = newSource(id); + newSrc->setSource(source); + // if source was created, add it to source list + if (newSrc != NULL) m_sources.push_back(newSrc); + } + // otherwise source wasn't set + else + return false; + // source was set + return true; +} + + +// set pixel filter +void ImageBase::setFilter (PyFilter * filt) +{ + // reference new filter + if (filt != NULL) Py_INCREF(filt); + // release previous filter + Py_XDECREF(m_pyfilter); + // set new filter + m_pyfilter = filt; +} + + +// initialize image data +void ImageBase::init (short width, short height) +{ + // if image has to be scaled + if (m_scale) + { + // recalc sizes of image + width = calcSize(width); + height = calcSize(height); + } + // if sizes differ + if (width != m_size[0] || height != m_size[1]) + { + // new buffer size + unsigned int newSize = width * height; + // if new buffer is larger than previous + if (newSize > m_imgSize) + { + // set new buffer size + m_imgSize = newSize; + // release previous and create new buffer + delete [] m_image; + m_image = new unsigned int[m_imgSize]; + } + // new image size + m_size[0] = width; + m_size[1] = height; + // scale was processed + m_scaleChange = false; + } +} + + +// find source +ImageSourceList::iterator ImageBase::findSource (const char * id) +{ + // iterate sources + ImageSourceList::iterator it; + for (it = m_sources.begin(); it != m_sources.end(); ++it) + // if id matches, return iterator + if ((*it)->is(id)) return it; + // source not found + return it; +} + + +// check sources sizes +bool ImageBase::checkSourceSizes (void) +{ + // reference size + short * refSize = NULL; + // iterate sources + for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it) + { + // get size of current source + short * curSize = (*it)->getSize(); + // if size is available and is not empty + if (curSize[0] != 0 && curSize[1] != 0) { + // if reference size is not set + if (refSize == NULL) { + // set current size as reference + refSize = curSize; + // otherwise check with current size + } else if (curSize[0] != refSize[0] || curSize[1] != refSize[1]) { + // if they don't match, report it + return false; + } + } + } + // all sizes match + return true; +} + + +// compute nearest power of 2 value +short ImageBase::calcSize (short size) +{ + // while there is more than 1 bit in size value + while ((size & (size - 1)) != 0) + // clear last bit + size = size & (size - 1); + // return result + return size; +} + + +// perform loop detection +bool ImageBase::loopDetect (ImageBase * img) +{ + // if this object is the same as parameter, loop is detected + if (this == img) return true; + // check all sources + for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it) + // if source detected loop, return this result + if ((*it)->getSource() != NULL && (*it)->getSource()->m_image->loopDetect(img)) + return true; + // no loop detected + return false; +} + + +// ImageSource class implementation + +// constructor +ImageSource::ImageSource (const char * id) : m_source(NULL), m_image(NULL) +{ + // copy id + int idx; + for (idx = 0; id[idx] != '\0' && idx < SourceIdSize - 1; ++idx) + m_id[idx] = id[idx]; + m_id[idx] = '\0'; +} + +// destructor +ImageSource::~ImageSource (void) +{ + // release source + setSource(NULL); +} + + +// compare id +bool ImageSource::is (const char * id) +{ + for (char * myId = m_id; *myId != '\0'; ++myId, ++id) + if (*myId != *id) return false; + return *id == '\0'; +} + + +// set source object +void ImageSource::setSource (PyImage * source) +{ + // reference new source + if (source != NULL) Py_INCREF(source); + // release previous source + Py_XDECREF(m_source); + // set new source + m_source = source; +} + + +// get image from source +unsigned int * ImageSource::getImage (void) +{ + // if source is available + if (m_source != NULL) + // get image from source + m_image = m_source->m_image->getImage(); + // otherwise reset buffer + else + m_image = NULL; + // return image + return m_image; +} + + +// refresh source +void ImageSource::refresh (void) +{ + // if source is available, refresh it + if (m_source != NULL) m_source->m_image->refresh(); +} + + + +// list of image types +PyTypeList pyImageTypes; + + + +// functions for python interface + +// object allocation +PyObject * Image_allocNew (PyTypeObject * type, PyObject * args, PyObject * kwds) +{ + // allocate object + PyImage * self = reinterpret_cast<PyImage*>(type->tp_alloc(type, 0)); + // initialize object structure + self->m_image = NULL; + // return allocated object + return reinterpret_cast<PyObject*>(self); +} + +// object deallocation +void Image_dealloc (PyImage * self) +{ + // release object attributes + if (self->m_image != NULL) + { + // if release requires deleting of object, do it + if (self->m_image->release()) + delete self->m_image; + self->m_image = NULL; + } +} + +// get image data +PyObject * Image_getImage (PyImage * self, void * closure) +{ + try + { + // get image + unsigned int * image = self->m_image->getImage(); + return Py_BuildValue("s#", image, self->m_image->getBuffSize()); + } + catch (Exception & exp) + { + exp.report(); + } + Py_RETURN_NONE; +} + +// get image size +PyObject * Image_getSize (PyImage * self, void * closure) +{ + return Py_BuildValue("(hh)", self->m_image->getSize()[0], + self->m_image->getSize()[1]); +} + +// refresh image +PyObject * Image_refresh (PyImage * self) +{ + self->m_image->refresh(); + Py_RETURN_NONE; +} + +// get scale +PyObject * Image_getScale (PyImage * self, void * closure) +{ + if (self->m_image != NULL && self->m_image->getScale()) Py_RETURN_TRUE; + else Py_RETURN_FALSE; +} + +// set scale +int Image_setScale (PyImage * self, PyObject * value, void * closure) +{ + // check parameter, report failure + if (value == NULL || !PyBool_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "The value must be a bool"); + return -1; + } + // set scale + if (self->m_image != NULL) self->m_image->setScale(value == Py_True); + // success + return 0; +} + +// get flip +PyObject * Image_getFlip (PyImage * self, void * closure) +{ + if (self->m_image != NULL && self->m_image->getFlip()) Py_RETURN_TRUE; + else Py_RETURN_FALSE; +} + +// set flip +int Image_setFlip (PyImage * self, PyObject * value, void * closure) +{ + // check parameter, report failure + if (value == NULL || !PyBool_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "The value must be a bool"); + return -1; + } + // set scale + if (self->m_image != NULL) self->m_image->setFlip(value == Py_True); + // success + return 0; +} + + +// get filter source object +PyObject * Image_getSource (PyImage * self, PyObject * args) +{ + // get arguments + char * id; + if (!PyArg_ParseTuple(args, "s:getSource", &id)) + return NULL; + if (self->m_image != NULL) + { + // get source object + PyObject * src = reinterpret_cast<PyObject*>(self->m_image->getSource(id)); + // if source is available + if (src != NULL) + { + // return source + Py_INCREF(src); + return src; + } + } + // source was not found + Py_RETURN_NONE; +} + + +// set filter source object +PyObject * Image_setSource (PyImage * self, PyObject * args) +{ + // get arguments + char * id; + PyObject * obj; + if (!PyArg_ParseTuple(args, "sO:setSource", &id, &obj)) + return NULL; + if (self->m_image != NULL) + { + // check type of object + if (pyImageTypes.in(obj->ob_type)) + { + // convert to image struct + PyImage * img = reinterpret_cast<PyImage*>(obj); + // set source + if (!self->m_image->setSource(id, img)) + { + // if not set, retport error + PyErr_SetString(PyExc_RuntimeError, "Invalid source or id"); + return NULL; + } + } + // else report error + else + { + PyErr_SetString(PyExc_RuntimeError, "Invalid type of object"); + return NULL; + } + } + // return none + Py_RETURN_NONE; +} + + +// get pixel filter object +PyObject * Image_getFilter (PyImage * self, void * closure) +{ + // if image object is available + if (self->m_image != NULL) + { + // pixel filter object + PyObject * filt = reinterpret_cast<PyObject*>(self->m_image->getFilter()); + // if filter is present + if (filt != NULL) + { + // return it + Py_INCREF(filt); + return filt; + } + } + // otherwise return none + Py_RETURN_NONE; +} + + +// set pixel filter object +int Image_setFilter (PyImage * self, PyObject * value, void * closure) +{ + // if image object is available + if (self->m_image != NULL) + { + // check new value + if (value == NULL || !pyFilterTypes.in(value->ob_type)) + { + // report value error + PyErr_SetString(PyExc_TypeError, "Invalid type of value"); + return -1; + } + // set new value + self->m_image->setFilter(reinterpret_cast<PyFilter*>(value)); + } + // return success + return 0; +} diff --git a/source/gameengine/VideoTexture/ImageBase.h b/source/gameengine/VideoTexture/ImageBase.h new file mode 100644 index 00000000000..138580ce701 --- /dev/null +++ b/source/gameengine/VideoTexture/ImageBase.h @@ -0,0 +1,349 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of blendTex library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined IMAGEBASE_H +#define IMAGEBASE_H + +#include "Common.h" + +#include <vector> +#include <PyObjectPlus.h> + +#include "PyTypeList.h" + +#include "FilterBase.h" + + +// forward declarations +struct PyImage; +class ImageSource; + + +/// type for list of image sources +typedef std::vector<ImageSource*> ImageSourceList; + + +/// base class for image filters +class ImageBase +{ +public: + /// constructor + ImageBase (bool staticSrc = false); + /// destructor + virtual ~ImageBase (void); + /// release contained objects, if returns true, object should be deleted + virtual bool release (void); + + /// get image + unsigned int * getImage (unsigned int texId = 0); + /// get image size + short * getSize (void) { return m_size; } + /// get image buffer size + unsigned long getBuffSize (void) + { return m_size[0] * m_size[1] * sizeof(unsigned int); } + /// refresh image - invalidate its current content + virtual void refresh (void); + + /// get scale + bool getScale (void) { return m_scale; } + /// set scale + void setScale (bool scale) { m_scale = scale; m_scaleChange = true; } + /// get vertical flip + bool getFlip (void) { return m_flip; } + /// set vertical flip + void setFlip (bool flip) { m_flip = flip; } + + /// get source object + PyImage * getSource (const char * id); + /// set source object, return true, if source was set + bool setSource (const char * id, PyImage * source); + + /// get pixel filter + PyFilter * getFilter (void) { return m_pyfilter; } + /// set pixel filter + void setFilter (PyFilter * filt); + + /// calculate size (nearest power of 2) + static short calcSize (short size); + +protected: + /// image buffer + unsigned int * m_image; + /// image buffer size + unsigned int m_imgSize; + /// image size + short m_size[2]; + /// image is available + bool m_avail; + + /// scale image to power 2 sizes + bool m_scale; + /// scale was changed + bool m_scaleChange; + /// flip image vertically + bool m_flip; + + /// source image list + ImageSourceList m_sources; + /// flag for disabling addition and deletion of sources + bool m_staticSources; + + /// pixel filter + PyFilter * m_pyfilter; + + /// initialize image data + void init (short width, short height); + + /// find source + ImageSourceList::iterator findSource (const char * id); + + /// create new source + virtual ImageSource * newSource (const char * id) { return NULL; } + + /// check source sizes + bool checkSourceSizes (void); + + /// calculate image from sources and set its availability + virtual void calcImage (unsigned int texId) {} + + /// perform loop detection + bool loopDetect (ImageBase * img); + + /// template for image conversion + template<class FLT, class SRC> void convImage (FLT & filter, SRC srcBuff, + short * srcSize) + { + // destination buffer + unsigned int * dstBuff = m_image; + // pixel size from filter + unsigned int pixSize = filter.firstPixelSize(); + // if no scaling is needed + if (srcSize[0] == m_size[0] && srcSize[1] == m_size[1]) + // if flipping isn't required + if (!m_flip) + // copy bitmap + for (short y = 0; y < m_size[1]; ++y) + for (short x = 0; x < m_size[0]; ++x, ++dstBuff, srcBuff += pixSize) + // copy pixel + *dstBuff = filter.convert(srcBuff, x, y, srcSize, pixSize); + // otherwise flip image top to bottom + else + { + // go to last row of image + srcBuff += srcSize[0] * (srcSize[1] - 1) * pixSize; + // copy bitmap + for (short y = m_size[1] - 1; y >= 0; --y, srcBuff -= 2 * srcSize[0] * pixSize) + for (short x = 0; x < m_size[0]; ++x, ++dstBuff, srcBuff += pixSize) + // copy pixel + *dstBuff = filter.convert(srcBuff, x, y, srcSize, pixSize); + } + // else scale picture (nearest neighbour) + else + { + // interpolation accumulator + int accHeight = srcSize[1] >> 1; + // if flipping is required + if (m_flip) + // go to last row of image + srcBuff += srcSize[0] * (srcSize[1] - 1) * pixSize; + // process image rows + for (int y = 0; y < srcSize[1]; ++y) + { + // increase height accum + accHeight += m_size[1]; + // if pixel row has to be drawn + if (accHeight >= srcSize[1]) + { + // decrease accum + accHeight -= srcSize[1]; + // width accum + int accWidth = srcSize[0] >> 1; + // process row + for (int x = 0; x < srcSize[0]; ++x) + { + // increase width accum + accWidth += m_size[0]; + // if pixel has to be drawn + if (accWidth >= srcSize[0]) + { + // decrease accum + accWidth -= srcSize[0]; + // convert pixel + *dstBuff = filter.convert(srcBuff, x, m_flip ? srcSize[1] - y - 1 : y, + srcSize, pixSize); + // next pixel + ++dstBuff; + } + // shift source pointer + srcBuff += pixSize; + } + } + // if pixel row will not be drawn + else + // move source pointer to next row + srcBuff += pixSize * srcSize[0]; + // if y flipping is required + if (m_flip) + // go to previous row of image + srcBuff -= 2 * pixSize * srcSize[0]; + } + } + } + + // template for specific filter preprocessing + template <class F, class SRC> void filterImage (F & filt, SRC srcBuff, short * srcSize) + { + // find first filter in chain + FilterBase * firstFilter = NULL; + if (m_pyfilter != NULL) firstFilter = m_pyfilter->m_filter->findFirst(); + // if first filter is available + if (firstFilter != NULL) + { + // python wrapper for filter + PyFilter pyFilt; + pyFilt.m_filter = &filt; + // set specified filter as first in chain + firstFilter->setPrevious(&pyFilt, false); + // convert video image + convImage(*(m_pyfilter->m_filter), srcBuff, srcSize); + // delete added filter + firstFilter->setPrevious(NULL, false); + } + // otherwise use given filter for conversion + else convImage(filt, srcBuff, srcSize); + // source was processed + m_avail = true; + } +}; + + +// python structure for image filter +struct PyImage +{ + PyObject_HEAD + // source object + ImageBase * m_image; +}; + + +// size of id +const int SourceIdSize = 32; + + +/// class for source of image +class ImageSource +{ +public: + /// constructor + ImageSource (const char * id); + /// destructor + virtual ~ImageSource (void); + + /// get id + const char * getId (void) { return m_id; } + /// compare id to argument + bool is (const char * id); + + /// get source object + PyImage * getSource (void) { return m_source; } + /// set source object + void setSource (PyImage * source); + + /// get image from source + unsigned int * getImage (void); + /// get buffered image + unsigned int * getImageBuf (void) { return m_image; } + /// refresh source + void refresh (void); + + /// get image size + short * getSize (void) + { + static short defSize [] = {0, 0}; + return m_source != NULL ? m_source->m_image->getSize() : defSize; + } + +protected: + /// id of source + char m_id [SourceIdSize]; + /// pointer to source structure + PyImage * m_source; + /// buffered image from source + unsigned int * m_image; + +private: + /// default constructor is forbidden + ImageSource (void) {} +}; + + + +// list of python image types +extern PyTypeList pyImageTypes; + + +// functions for python interface + +// object initialization +template <class T> static int Image_init (PyObject * pySelf, PyObject * args, PyObject * kwds) +{ + PyImage * self = reinterpret_cast<PyImage*>(pySelf); + // create source object + if (self->m_image != NULL) delete self->m_image; + self->m_image = new T(); + // initialization succeded + return 0; +} + +// object allocation +PyObject * Image_allocNew (PyTypeObject * type, PyObject * args, PyObject * kwds); +// object deallocation +void Image_dealloc (PyImage * self); + +// get image data +PyObject * Image_getImage (PyImage * self, void * closure); +// get image size +PyObject * Image_getSize (PyImage * self, void * closure); +// refresh image - invalidate current content +PyObject * Image_refresh (PyImage * self); + +// get scale +PyObject * Image_getScale (PyImage * self, void * closure); +// set scale +int Image_setScale (PyImage * self, PyObject * value, void * closure); +// get flip +PyObject * Image_getFlip (PyImage * self, void * closure); +// set flip +int Image_setFlip (PyImage * self, PyObject * value, void * closure); + +// get filter source object +PyObject * Image_getSource (PyImage * self, PyObject * args); +// set filter source object +PyObject * Image_setSource (PyImage * self, PyObject * args); + +// get pixel filter object +PyObject * Image_getFilter (PyImage * self, void * closure); +// set pixel filter object +int Image_setFilter (PyImage * self, PyObject * value, void * closure); + + +#endif diff --git a/source/gameengine/VideoTexture/ImageBuff.cpp b/source/gameengine/VideoTexture/ImageBuff.cpp new file mode 100644 index 00000000000..9cd661a2422 --- /dev/null +++ b/source/gameengine/VideoTexture/ImageBuff.cpp @@ -0,0 +1,164 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +// implementation + +#include <PyObjectPlus.h> +#include <structmember.h> + +#include "ImageBuff.h" + +#include "ImageBase.h" +#include "FilterSource.h" + + +// default filter +FilterRGB24 defFilter; + + +// load image from buffer +void ImageBuff::load (unsigned char * img, short width, short height) +{ + // initialize image buffer + init(width, height); + // original size + short orgSize[2] = {width, height}; + // is filter available + if (m_pyfilter != NULL) + // use it to process image + convImage(*(m_pyfilter->m_filter), img, orgSize); + else + // otherwise use default filter + convImage(defFilter, img, orgSize); + // image is available + m_avail = true; +} + + + +// cast Image pointer to ImageBuff +inline ImageBuff * getImageBuff (PyImage * self) +{ return static_cast<ImageBuff*>(self->m_image); } + + +// python methods + +// load image +static PyObject * load (PyImage * self, PyObject * args) +{ + // parameters: string image buffer, its size, width, height + unsigned char * buff; + unsigned int buffSize; + short width; + short height; + // parse parameters + if (!PyArg_ParseTuple(args, "s#hh:load", &buff, &buffSize, &width, &height)) + { + // report error + return NULL; + } + // else check buffer size + else + { + // calc proper buffer size + unsigned int propSize = width * height; + // use pixel size from filter + if (self->m_image->getFilter() != NULL) + propSize *= self->m_image->getFilter()->m_filter->firstPixelSize(); + else + propSize *= defFilter.firstPixelSize(); + // check if buffer size is correct + if (propSize != buffSize) + { + // if not, report error + PyErr_SetString(PyExc_TypeError, "Buffer hasn't correct size"); + return NULL; + } + else + // if correct, load image + getImageBuff(self)->load(buff, width, height); + } + Py_RETURN_NONE; +} + + +// methods structure +static PyMethodDef imageBuffMethods[] = +{ + {"load", (PyCFunction)load, METH_VARARGS, "Load image from buffer"}, + {NULL} +}; +// attributes structure +static PyGetSetDef imageBuffGetSets[] = +{ // attributes from ImageBase class + {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, + {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, + {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL}, + {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, + {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, + {NULL} +}; + + +// define python type +PyTypeObject ImageBuffType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.ImageBuff", /*tp_name*/ + sizeof(PyImage), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Image_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Image source from image buffer", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + imageBuffMethods, /* tp_methods */ + 0, /* tp_members */ + imageBuffGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Image_init<ImageBuff>, /* tp_init */ + 0, /* tp_alloc */ + Image_allocNew, /* tp_new */ +}; + diff --git a/source/gameengine/VideoTexture/ImageBuff.h b/source/gameengine/VideoTexture/ImageBuff.h new file mode 100644 index 00000000000..fa2025fa8c4 --- /dev/null +++ b/source/gameengine/VideoTexture/ImageBuff.h @@ -0,0 +1,51 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined IMAGEBUFF_H +#define IMAGEBUFF_H + + +#include "Common.h" + +#include "ImageBase.h" + + +/// class for image buffer +class ImageBuff : public ImageBase +{ +public: + /// constructor + ImageBuff (void) : ImageBase(true) {} + + /// destructor + virtual ~ImageBuff (void) {} + + /// load image from buffer + void load (unsigned char * img, short width, short height); + + /// refresh image - do nothing + virtual void refresh (void) {} +}; + + +#endif + diff --git a/source/gameengine/VideoTexture/ImageMix.cpp b/source/gameengine/VideoTexture/ImageMix.cpp new file mode 100644 index 00000000000..2560467c3db --- /dev/null +++ b/source/gameengine/VideoTexture/ImageMix.cpp @@ -0,0 +1,208 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +// implementation + +#include <PyObjectPlus.h> +#include <structmember.h> + +#include "ImageMix.h" + +#include "ImageBase.h" + +#include "Exception.h" + + +// cast ImageSource pointer to ImageSourceMix +inline ImageSourceMix * getImageSourceMix (ImageSource * src) +{ return static_cast<ImageSourceMix*>(src); } + + +// get weight +short ImageMix::getWeight (const char * id) +{ + // find source + ImageSourceList::iterator src = findSource(id); + // if found, return its weight + return src != m_sources.end() ? getImageSourceMix(*src)->getWeight() : 0; +} + +// set weight +bool ImageMix::setWeight (const char * id, short weight) +{ + // find source + ImageSourceList::iterator src = findSource(id); + // if source isn't found, report it + if (src == m_sources.end()) return false; + // set its weight + getImageSourceMix(*src)->setWeight(weight); + return true; +} + +ExceptionID ImageSizesNotMatch; + +ExpDesc ImageSizesNotMatchDesc (ImageSizesNotMatch, "Image sizes of sources are different"); + +// calculate image from sources and set its availability +void ImageMix::calcImage (unsigned int texId) +{ + // check source sizes + if (!checkSourceSizes()) THRWEXCP(ImageSizesNotMatch, S_OK); + // set offsets to image buffers + for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it) + // if image buffer is available + if ((*it)->getImageBuf() != NULL) + // set its offset + getImageSourceMix(*it)->setOffset(m_sources[0]->getImageBuf()); + // otherwise don't calculate image + else + return; + // if there is only single source + if (m_sources.size() == 1) + { + // use single filter + FilterBase mixFilt; + // fiter and convert image + filterImage(mixFilt, m_sources[0]->getImageBuf(), m_sources[0]->getSize()); + } + // otherwise use mix filter to merge source images + else + { + FilterImageMix mixFilt (m_sources); + // fiter and convert image + filterImage(mixFilt, m_sources[0]->getImageBuf(), m_sources[0]->getSize()); + } +} + + + +// cast Image pointer to ImageMix +inline ImageMix * getImageMix (PyImage * self) +{ return static_cast<ImageMix*>(self->m_image); } + + +// python methods + +// get source weight +PyObject * getWeight (PyImage * self, PyObject * args) +{ + // weight + short weight = 0; + // get arguments + char * id; + if (!PyArg_ParseTuple(args, "s:getWeight", &id)) + return NULL; + if (self->m_image != NULL) + // get weight + weight = getImageMix(self)->getWeight(id); + // return weight + return Py_BuildValue("h", weight); +} + + +// set source weight +PyObject * setWeight (PyImage * self, PyObject * args) +{ + // get arguments + char * id; + short weight = 0; + if (!PyArg_ParseTuple(args, "sh:setWeight", &id, &weight)) + return NULL; + if (self->m_image != NULL) + // set weight + if (!getImageMix(self)->setWeight(id, weight)) + { + // if not set, report error + PyErr_SetString(PyExc_RuntimeError, "Invalid id of source");; + return NULL; + } + // return none + Py_RETURN_NONE; +} + + +// methods structure +static PyMethodDef imageMixMethods[] = +{ + {"getSource", (PyCFunction)Image_getSource, METH_VARARGS, "get image source"}, + {"setSource", (PyCFunction)Image_setSource, METH_VARARGS, "set image source"}, + {"getWeight", (PyCFunction)getWeight, METH_VARARGS, "get image source weight"}, + {"setWeight", (PyCFunction)setWeight, METH_VARARGS, "set image source weight"}, + // methods from ImageBase class + {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"}, + {NULL} +}; +// attributes structure +static PyGetSetDef imageMixGetSets[] = +{ // attributes from ImageBase class + {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, + {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, + {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL}, + {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, + {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, + {NULL} +}; + + +// define python type +PyTypeObject ImageMixType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.ImageMix", /*tp_name*/ + sizeof(PyImage), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Image_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Image mixer", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + imageMixMethods, /* tp_methods */ + 0, /* tp_members */ + imageMixGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Image_init<ImageMix>, /* tp_init */ + 0, /* tp_alloc */ + Image_allocNew, /* tp_new */ +}; + diff --git a/source/gameengine/VideoTexture/ImageMix.h b/source/gameengine/VideoTexture/ImageMix.h new file mode 100644 index 00000000000..b4842bd6b40 --- /dev/null +++ b/source/gameengine/VideoTexture/ImageMix.h @@ -0,0 +1,123 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined IMAGEMIX_H +#define IMAGEMIX_H + + +#include "Common.h" + +#include "ImageBase.h" +#include "FilterBase.h" + + +/// class for source mixing +class ImageSourceMix : public ImageSource +{ +public: + /// constructor + ImageSourceMix (const char * id) : ImageSource(id), m_weight(0x100) {} + /// destructor + virtual ~ImageSourceMix (void) {} + + /// get offset + long long getOffset (void) { return m_offset; } + /// set offset + void setOffset (unsigned int * firstImg) { m_offset = m_image - firstImg; } + + /// get weight + short getWeight (void) { return m_weight; } + /// set weight + void setWeight (short weight) { m_weight = weight; } + +protected: + /// buffer offset to the first source buffer + long long m_offset; + /// source weight + short m_weight; +}; + + +/// class for image mixer +class ImageMix : public ImageBase +{ +public: + /// constructor + ImageMix (void) : ImageBase(false) {} + + /// destructor + virtual ~ImageMix (void) {} + + /// get weight + short getWeight (const char * id); + /// set weight + bool setWeight (const char * id, short weight); + +protected: + + /// create new source + virtual ImageSource * newSource (const char * id) { return new ImageSourceMix(id); } + + /// calculate image from sources and set its availability + virtual void calcImage (unsigned int texId); +}; + + +/// pixel filter for image mixer +class FilterImageMix : public FilterBase +{ +public: + /// constructor + FilterImageMix (ImageSourceList & sources) : m_sources(sources) {} + /// destructor + virtual ~FilterImageMix (void) {} + +protected: + /// source list + ImageSourceList & m_sources; + + /// filter pixel, source int buffer + virtual unsigned int filter (unsigned int * src, short x, short y, + short * size, unsigned int pixSize, unsigned int val = 0) + { + // resulting pixel color + int color[] = {0, 0, 0, 0}; + // iterate sources + for (ImageSourceList::iterator it = m_sources.begin(); it != m_sources.end(); ++it) + { + // get pointer to mixer source + ImageSourceMix * mixSrc = static_cast<ImageSourceMix*>(*it); + // add weighted source pixel to result + color[0] += mixSrc->getWeight() * (src[mixSrc->getOffset()] & 0xFF); + color[1] += mixSrc->getWeight() * ((src[mixSrc->getOffset()] >> 8) & 0xFF); + color[2] += mixSrc->getWeight() * ((src[mixSrc->getOffset()] >> 16) & 0xFF); + color[3] += mixSrc->getWeight() * ((src[mixSrc->getOffset()] >> 24) & 0xFF); + } + // return resulting color + return ((color[0] >> 8) & 0xFF) | (color[1] & 0xFF00) + | ((color[2] << 8) & 0xFF0000) | ((color[3] << 16) & 0xFF000000); + } +}; + + +#endif + diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp new file mode 100644 index 00000000000..6e70bfb14a0 --- /dev/null +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -0,0 +1,752 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +// implementation + +#include <PyObjectPlus.h> +#include <structmember.h> +#include <float.h> +#include <math.h> + + +#include "GL/glew.h" + +#include "KX_PythonInit.h" +#include "DNA_scene_types.h" +#include "RAS_CameraData.h" +#include "RAS_MeshObject.h" +#include "BLI_arithb.h" + +#include "ImageRender.h" +#include "ImageBase.h" +#include "BlendType.h" +#include "Exception.h" +#include "Texture.h" + +ExceptionID SceneInvalid, CameraInvalid, ObserverInvalid; +ExceptionID MirrorInvalid, MirrorSizeInvalid, MirrorNormalInvalid, MirrorHorizontal, MirrorTooSmall; +ExpDesc SceneInvalidDesc (SceneInvalid, "Scene object is invalid"); +ExpDesc CameraInvalidDesc (CameraInvalid, "Camera object is invalid"); +ExpDesc ObserverInvalidDesc (ObserverInvalid, "Observer object is invalid"); +ExpDesc MirrorInvalidDesc (MirrorInvalid, "Mirror object is invalid"); +ExpDesc MirrorSizeInvalidDesc (MirrorSizeInvalid, "Mirror has no vertex or no size"); +ExpDesc MirrorNormalInvalidDesc (MirrorNormalInvalid, "Cannot determine mirror plane"); +ExpDesc MirrorHorizontalDesc (MirrorHorizontal, "Mirror is horizontal in local space"); +ExpDesc MirrorTooSmallDesc (MirrorTooSmall, "Mirror is too small"); + +// constructor +ImageRender::ImageRender (KX_Scene * scene, KX_Camera * camera) : + ImageViewport(), + m_render(true), + m_scene(scene), + m_camera(camera), + m_owncamera(false), + m_observer(NULL), + m_mirror(NULL), + m_clip(100.f) +{ + // initialize background colour + setBackground(0, 0, 255, 255); + // retrieve rendering objects + m_engine = KX_GetActiveEngine(); + m_rasterizer = m_engine->GetRasterizer(); + m_canvas = m_engine->GetCanvas(); + m_rendertools = m_engine->GetRenderTools(); +} + +// destructor +ImageRender::~ImageRender (void) +{ + if (m_owncamera) + m_camera->Release(); +} + + +// set background color +void ImageRender::setBackground (int red, int green, int blue, int alpha) +{ + m_background[0] = (red < 0) ? 0.f : (red > 255) ? 1.f : float(red)/255.f; + m_background[1] = (green < 0) ? 0.f : (green > 255) ? 1.f : float(green)/255.f; + m_background[2] = (blue < 0) ? 0.f : (blue > 255) ? 1.f : float(blue)/255.f; + m_background[3] = (alpha < 0) ? 0.f : (alpha > 255) ? 1.f : float(alpha)/255.f; +} + + +// capture image from viewport +void ImageRender::calcImage (unsigned int texId) +{ + if (m_rasterizer->GetDrawingMode() != RAS_IRasterizer::KX_TEXTURED || // no need for texture + m_camera->GetViewport() || // camera must be inactive + m_camera == m_scene->GetActiveCamera()) + { + // no need to compute texture in non texture rendering + m_avail = false; + return; + } + // render the scene from the camera + Render(); + // get image from viewport + ImageViewport::calcImage(texId); + // restore OpenGL state + m_canvas->EndFrame(); +} + +void ImageRender::Render() +{ + RAS_FrameFrustum frustrum; + + if (!m_render) + return; + + if (m_mirror) + { + // mirror mode, compute camera frustrum, position and orientation + // convert mirror position and normal in world space + const MT_Matrix3x3 & mirrorObjWorldOri = m_mirror->GetSGNode()->GetWorldOrientation(); + const MT_Point3 & mirrorObjWorldPos = m_mirror->GetSGNode()->GetWorldPosition(); + const MT_Vector3 & mirrorObjWorldScale = m_mirror->GetSGNode()->GetWorldScaling(); + MT_Point3 mirrorWorldPos = + mirrorObjWorldPos + mirrorObjWorldScale * (mirrorObjWorldOri * m_mirrorPos); + MT_Vector3 mirrorWorldZ = mirrorObjWorldOri * m_mirrorZ; + // get observer world position + const MT_Point3 & observerWorldPos = m_observer->GetSGNode()->GetWorldPosition(); + // get plane D term = mirrorPos . normal + MT_Scalar mirrorPlaneDTerm = mirrorWorldPos.dot(mirrorWorldZ); + // compute distance of observer to mirror = D - observerPos . normal + MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ); + // if distance < 0.01 => observer is on wrong side of mirror, don't render + if (observerDistance < 0.01f) + return; + // set camera world position = observerPos + normal * 2 * distance + MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ; + m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos); + // set camera orientation: z=normal, y=mirror_up in world space, x= y x z + MT_Vector3 mirrorWorldY = mirrorObjWorldOri * m_mirrorY; + MT_Vector3 mirrorWorldX = mirrorObjWorldOri * m_mirrorX; + MT_Matrix3x3 cameraWorldOri( + mirrorWorldX[0], mirrorWorldY[0], mirrorWorldZ[0], + mirrorWorldX[1], mirrorWorldY[1], mirrorWorldZ[1], + mirrorWorldX[2], mirrorWorldY[2], mirrorWorldZ[2]); + m_camera->GetSGNode()->SetLocalOrientation(cameraWorldOri); + m_camera->GetSGNode()->UpdateWorldData(0.0); + // compute camera frustrum: + // get position of mirror relative to camera: offset = mirrorPos-cameraPos + MT_Vector3 mirrorOffset = mirrorWorldPos - cameraWorldPos; + // convert to camera orientation + mirrorOffset = mirrorOffset * cameraWorldOri; + // scale mirror size to world scale: + // get closest local axis for mirror Y and X axis and scale height and width by local axis scale + MT_Scalar x, y; + x = fabs(m_mirrorY[0]); + y = fabs(m_mirrorY[1]); + float height = (x > y) ? + ((x > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]): + ((y > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]); + x = fabs(m_mirrorX[0]); + y = fabs(m_mirrorX[1]); + float width = (x > y) ? + ((x > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]): + ((y > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]); + width *= m_mirrorHalfWidth; + height *= m_mirrorHalfHeight; + // left = offsetx-width + // right = offsetx+width + // top = offsety+height + // bottom = offsety-height + // near = -offsetz + // far = near+100 + frustrum.x1 = mirrorOffset[0]-width; + frustrum.x2 = mirrorOffset[0]+width; + frustrum.y1 = mirrorOffset[1]-height; + frustrum.y2 = mirrorOffset[1]+height; + frustrum.camnear = -mirrorOffset[2]; + frustrum.camfar = -mirrorOffset[2]+m_clip; + } + const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode(); + + // The screen area that ImageViewport will copy is also the rendering zone + m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1); + m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]); + m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER); + m_rasterizer->BeginFrame(RAS_IRasterizer::KX_TEXTURED,m_engine->GetClockTime()); + m_rendertools->BeginFrame(m_rasterizer); + m_engine->SetWorldSettings(m_scene->GetWorldInfo()); + m_rendertools->SetAuxilaryClientInfo(m_scene); + m_rasterizer->DisplayFog(); + // matrix calculation, don't apply any of the stereo mode + m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO); + if (m_mirror) + { + // frustrum was computed above + // get frustrum matrix and set projection matrix + MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix( + frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); + + m_camera->SetProjectionMatrix(projmat); + } else if (m_camera->hasValidProjectionMatrix()) + { + m_rasterizer->SetProjectionMatrix(m_camera->GetProjectionMatrix()); + } else + { + float lens = m_camera->GetLens(); + bool orthographic = !m_camera->GetCameraData()->m_perspective; + float nearfrust = m_camera->GetCameraNear(); + float farfrust = m_camera->GetCameraFar(); + float aspect_ratio = 1.0f; + Scene *blenderScene = m_scene->GetBlenderScene(); + MT_Matrix4x4 projmat; + + // compute the aspect ratio from frame blender scene settings so that render to texture + // works the same in Blender and in Blender player + if (blenderScene->r.ysch != 0) + aspect_ratio = float(blenderScene->r.xsch*blenderScene->r.xasp) / float(blenderScene->r.ysch*blenderScene->r.yasp); + + if (orthographic) { + + RAS_FramingManager::ComputeDefaultOrtho( + nearfrust, + farfrust, + m_camera->GetScale(), + aspect_ratio, + frustrum + ); + + projmat = m_rasterizer->GetOrthoMatrix( + frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); + } else + { + RAS_FramingManager::ComputeDefaultFrustum( + nearfrust, + farfrust, + lens, + aspect_ratio, + frustrum); + + projmat = m_rasterizer->GetFrustumMatrix( + frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); + } + m_camera->SetProjectionMatrix(projmat); + } + + MT_Transform camtrans(m_camera->GetWorldToCamera()); + MT_Matrix4x4 viewmat(camtrans); + + m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->GetCameraData()->m_perspective); + m_camera->SetModelviewMatrix(viewmat); + // restore the stereo mode now that the matrix is computed + m_rasterizer->SetStereoMode(stereomode); + + m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera); + + m_scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools); +} + + +// cast Image pointer to ImageRender +inline ImageRender * getImageRender (PyImage * self) +{ return static_cast<ImageRender*>(self->m_image); } + + +// python methods + +// Blender Scene type +BlendType<KX_Scene> sceneType ("KX_Scene"); +// Blender Camera type +BlendType<KX_Camera> cameraType ("KX_Camera"); + + +// object initialization +static int ImageRender_init (PyObject * pySelf, PyObject * args, PyObject * kwds) +{ + // parameters - scene object + PyObject * scene; + // camera object + PyObject * camera; + // parameter keywords + static char *kwlist[] = {"sceneObj", "cameraObj", NULL}; + // get parameters + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &scene, &camera)) + return -1; + try + { + // get scene pointer + KX_Scene * scenePtr (NULL); + if (scene != NULL) scenePtr = sceneType.checkType(scene); + // throw exception if scene is not available + if (scenePtr == NULL) THRWEXCP(SceneInvalid, S_OK); + + // get camera pointer + KX_Camera * cameraPtr (NULL); + if (camera != NULL) cameraPtr = cameraType.checkType(camera); + // throw exception if camera is not available + if (cameraPtr == NULL) THRWEXCP(CameraInvalid, S_OK); + + // get pointer to image structure + PyImage * self = reinterpret_cast<PyImage*>(pySelf); + // create source object + if (self->m_image != NULL) delete self->m_image; + self->m_image = new ImageRender(scenePtr, cameraPtr); + } + catch (Exception & exp) + { + exp.report(); + return -1; + } + // initialization succeded + return 0; +} + + +// get background color +PyObject * getBackground (PyImage * self, void * closure) +{ + return Py_BuildValue("[BBBB]", + getImageRender(self)->getBackground(0), + getImageRender(self)->getBackground(1), + getImageRender(self)->getBackground(2), + getImageRender(self)->getBackground(3)); +} + +// set color +static int setBackground (PyImage * self, PyObject * value, void * closure) +{ + // check validity of parameter + if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 4 + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0)) + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1)) + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 2)) + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 3))) + { + PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 4 integer between 0 and 255"); + return -1; + } + // set background color + getImageRender(self)->setBackground((unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 0))), + (unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 1))), + (unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 2))), + (unsigned char)(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 3)))); + // success + return 0; +} + + +// methods structure +static PyMethodDef imageRenderMethods[] = +{ // methods from ImageBase class + {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"}, + {NULL} +}; +// attributes structure +static PyGetSetDef imageRenderGetSets[] = +{ + {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL}, + // attribute from ImageViewport + {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL}, + {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, + {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL}, + // attributes from ImageBase class + {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, + {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, + {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL}, + {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, + {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, + {NULL} +}; + + +// define python type +PyTypeObject ImageRenderType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.ImageRender", /*tp_name*/ + sizeof(PyImage), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Image_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Image source from render", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + imageRenderMethods, /* tp_methods */ + 0, /* tp_members */ + imageRenderGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)ImageRender_init, /* tp_init */ + 0, /* tp_alloc */ + Image_allocNew, /* tp_new */ +}; + +// object initialization +static int ImageMirror_init (PyObject * pySelf, PyObject * args, PyObject * kwds) +{ + // parameters - scene object + PyObject * scene; + // reference object for mirror + PyObject * observer; + // object holding the mirror + PyObject * mirror; + // material of the mirror + short materialID = 0; + // parameter keywords + static char *kwlist[] = {"scene", "observer", "mirror", "material", NULL}; + // get parameters + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|h", kwlist, &scene, &observer, &mirror, &materialID)) + return -1; + try + { + // get scene pointer + KX_Scene * scenePtr (NULL); + if (scene != NULL && PyObject_TypeCheck(scene, &KX_Scene::Type)) + scenePtr = static_cast<KX_Scene*>BGE_PROXY_REF(scene); + else + THRWEXCP(SceneInvalid, S_OK); + + if(scenePtr==NULL) /* incase the python proxy reference is invalid */ + THRWEXCP(SceneInvalid, S_OK); + + // get observer pointer + KX_GameObject * observerPtr (NULL); + if (observer != NULL && PyObject_TypeCheck(observer, &KX_GameObject::Type)) + observerPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(observer); + else if (observer != NULL && PyObject_TypeCheck(observer, &KX_Camera::Type)) + observerPtr = static_cast<KX_Camera*>BGE_PROXY_REF(observer); + else + THRWEXCP(ObserverInvalid, S_OK); + + if(observerPtr==NULL) /* incase the python proxy reference is invalid */ + THRWEXCP(ObserverInvalid, S_OK); + + // get mirror pointer + KX_GameObject * mirrorPtr (NULL); + if (mirror != NULL && PyObject_TypeCheck(mirror, &KX_GameObject::Type)) + mirrorPtr = static_cast<KX_GameObject*>BGE_PROXY_REF(mirror); + else + THRWEXCP(MirrorInvalid, S_OK); + + if(mirrorPtr==NULL) /* incase the python proxy reference is invalid */ + THRWEXCP(MirrorInvalid, S_OK); + + // locate the material in the mirror + RAS_IPolyMaterial * material = getMaterial(mirror, materialID); + if (material == NULL) + THRWEXCP(MaterialNotAvail, S_OK); + + // get pointer to image structure + PyImage * self = reinterpret_cast<PyImage*>(pySelf); + + // create source object + if (self->m_image != NULL) + { + delete self->m_image; + self->m_image = NULL; + } + self->m_image = new ImageRender(scenePtr, observerPtr, mirrorPtr, material); + } + catch (Exception & exp) + { + exp.report(); + return -1; + } + // initialization succeded + return 0; +} + +// get background color +PyObject * getClip (PyImage * self, void * closure) +{ + return PyFloat_FromDouble(getImageRender(self)->getClip()); +} + +// set clip +static int setClip (PyImage * self, PyObject * value, void * closure) +{ + // check validity of parameter + double clip; + if (value == NULL || !PyFloat_Check(value) || (clip = PyFloat_AsDouble(value)) < 0.01 || clip > 5000.0) + { + PyErr_SetString(PyExc_TypeError, "The value must be an float between 0.01 and 5000"); + return -1; + } + // set background color + getImageRender(self)->setClip(float(clip)); + // success + return 0; +} + +// attributes structure +static PyGetSetDef imageMirrorGetSets[] = +{ + {(char*)"clip", (getter)getClip, (setter)setClip, (char*)"clipping distance", NULL}, + // attribute from ImageRender + {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL}, + // attribute from ImageViewport + {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL}, + {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, + {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL}, + // attributes from ImageBase class + {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, + {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, + {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL}, + {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, + {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, + {NULL} +}; + + +// constructor +ImageRender::ImageRender (KX_Scene * scene, KX_GameObject * observer, KX_GameObject * mirror, RAS_IPolyMaterial * mat) : + ImageViewport(), + m_render(false), + m_scene(scene), + m_observer(observer), + m_mirror(mirror), + m_clip(100.f) +{ + // this constructor is used for automatic planar mirror + // create a camera, take all data by default, in any case we will recompute the frustrum on each frame + RAS_CameraData camdata; + vector<RAS_TexVert*> mirrorVerts; + vector<RAS_TexVert*>::iterator it; + float mirrorArea = 0.f; + float mirrorNormal[3] = {0.f, 0.f, 0.f}; + float mirrorUp[3]; + float dist, vec[3], axis[3]; + float zaxis[3] = {0.f, 0.f, 1.f}; + float yaxis[3] = {0.f, 1.f, 0.f}; + float mirrorMat[3][3]; + float left, right, top, bottom, back; + // make sure this camera will delete its node + m_camera= new KX_Camera(scene, KX_Scene::m_callbacks, camdata, true, true); + m_camera->SetName("__mirror__cam__"); + // don't add the camera to the scene object list, it doesn't need to be accessible + m_owncamera = true; + // retrieve rendering objects + m_engine = KX_GetActiveEngine(); + m_rasterizer = m_engine->GetRasterizer(); + m_canvas = m_engine->GetCanvas(); + m_rendertools = m_engine->GetRenderTools(); + // locate the vertex assigned to mat and do following calculation in mesh coordinates + for (int meshIndex = 0; meshIndex < mirror->GetMeshCount(); meshIndex++) + { + RAS_MeshObject* mesh = mirror->GetMesh(meshIndex); + int numPolygons = mesh->NumPolygons(); + for (int polygonIndex=0; polygonIndex < numPolygons; polygonIndex++) + { + RAS_Polygon* polygon = mesh->GetPolygon(polygonIndex); + if (polygon->GetMaterial()->GetPolyMaterial() == mat) + { + RAS_TexVert *v1, *v2, *v3, *v4; + float normal[3]; + float area; + // this polygon is part of the mirror, + v1 = polygon->GetVertex(0); + v2 = polygon->GetVertex(1); + v3 = polygon->GetVertex(2); + mirrorVerts.push_back(v1); + mirrorVerts.push_back(v2); + mirrorVerts.push_back(v3); + if (polygon->VertexCount() == 4) + { + v4 = polygon->GetVertex(3); + mirrorVerts.push_back(v4); + area = CalcNormFloat4((float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ(), (float*)v4->getXYZ(), normal); + } else + { + area = CalcNormFloat((float*)v1->getXYZ(), (float*)v2->getXYZ(), (float*)v3->getXYZ(), normal); + } + area = fabs(area); + mirrorArea += area; + VecMulf(normal, area); + VecAddf(mirrorNormal, mirrorNormal, normal); + } + } + } + if (mirrorVerts.size() == 0 || mirrorArea < FLT_EPSILON) + { + // no vertex or zero size mirror + THRWEXCP(MirrorSizeInvalid, S_OK); + } + // compute average normal of mirror faces + VecMulf(mirrorNormal, 1.0f/mirrorArea); + if (Normalize(mirrorNormal) == 0.f) + { + // no normal + THRWEXCP(MirrorNormalInvalid, S_OK); + } + // the mirror plane has an equation of the type ax+by+cz = d where (a,b,c) is the normal vector + // if the mirror is more vertical then horizontal, the Z axis is the up direction. + // otherwise the Y axis is the up direction. + // If the mirror is not perfectly vertical(horizontal), the Z(Y) axis projection on the mirror + // plan by the normal will be the up direction. + if (fabs(mirrorNormal[2]) > fabs(mirrorNormal[1]) && + fabs(mirrorNormal[2]) > fabs(mirrorNormal[0])) + { + // the mirror is more horizontal than vertical + VecCopyf(axis, yaxis); + } + else + { + // the mirror is more vertical than horizontal + VecCopyf(axis, zaxis); + } + dist = Inpf(mirrorNormal, axis); + if (fabs(dist) < FLT_EPSILON) + { + // the mirror is already fully aligned with up axis + VecCopyf(mirrorUp, axis); + } + else + { + // projection of axis to mirror plane through normal + VecCopyf(vec, mirrorNormal); + VecMulf(vec, dist); + VecSubf(mirrorUp, axis, vec); + if (Normalize(mirrorUp) == 0.f) + { + // should not happen + THRWEXCP(MirrorHorizontal, S_OK); + return; + } + } + // compute rotation matrix between local coord and mirror coord + // to match camera orientation, we select mirror z = -normal, y = up, x = y x z + VecCopyf(mirrorMat[2], mirrorNormal); + VecMulf(mirrorMat[2], -1.0f); + VecCopyf(mirrorMat[1], mirrorUp); + Crossf(mirrorMat[0], mirrorMat[1], mirrorMat[2]); + // transpose to make it a orientation matrix from local space to mirror space + Mat3Transp(mirrorMat); + // transform all vertex to plane coordinates and determine mirror position + left = FLT_MAX; + right = -FLT_MAX; + bottom = FLT_MAX; + top = -FLT_MAX; + back = -FLT_MAX; // most backward vertex (=highest Z coord in mirror space) + for (it = mirrorVerts.begin(); it != mirrorVerts.end(); it++) + { + VecCopyf(vec, (float*)(*it)->getXYZ()); + Mat3MulVecfl(mirrorMat, vec); + if (vec[0] < left) + left = vec[0]; + if (vec[0] > right) + right = vec[0]; + if (vec[1] < bottom) + bottom = vec[1]; + if (vec[1] > top) + top = vec[1]; + if (vec[2] > back) + back = vec[2]; + } + // now store this information in the object for later rendering + m_mirrorHalfWidth = (right-left)*0.5f; + m_mirrorHalfHeight = (top-bottom)*0.5f; + if (m_mirrorHalfWidth < 0.01f || m_mirrorHalfHeight < 0.01f) + { + // mirror too small + THRWEXCP(MirrorTooSmall, S_OK); + } + // mirror position in mirror coord + vec[0] = (left+right)*0.5f; + vec[1] = (top+bottom)*0.5f; + vec[2] = back; + // convert it in local space: transpose again the matrix to get back to mirror to local transform + Mat3Transp(mirrorMat); + Mat3MulVecfl(mirrorMat, vec); + // mirror position in local space + m_mirrorPos.setValue(vec[0], vec[1], vec[2]); + // mirror normal vector (pointed towards the back of the mirror) in local space + m_mirrorZ.setValue(-mirrorNormal[0], -mirrorNormal[1], -mirrorNormal[2]); + m_mirrorY.setValue(mirrorUp[0], mirrorUp[1], mirrorUp[2]); + m_mirrorX = m_mirrorY.cross(m_mirrorZ); + m_render = true; + + setBackground(0, 0, 255, 255); +} + + + + +// define python type +PyTypeObject ImageMirrorType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.ImageMirror", /*tp_name*/ + sizeof(PyImage), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Image_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Image source from mirror", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + imageRenderMethods, /* tp_methods */ + 0, /* tp_members */ + imageMirrorGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)ImageMirror_init, /* tp_init */ + 0, /* tp_alloc */ + Image_allocNew, /* tp_new */ +}; + + diff --git a/source/gameengine/VideoTexture/ImageRender.h b/source/gameengine/VideoTexture/ImageRender.h new file mode 100644 index 00000000000..c94e2f1e718 --- /dev/null +++ b/source/gameengine/VideoTexture/ImageRender.h @@ -0,0 +1,104 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined IMAGERENDER_H +#define IMAGERENDER_H + + +#include "Common.h" + +#include <KX_Scene.h> +#include <KX_Camera.h> +#include <DNA_screen_types.h> +#include <RAS_ICanvas.h> +#include <RAS_IRasterizer.h> +#include <RAS_IRenderTools.h> + +#include "ImageViewport.h" + + +/// class for render 3d scene +class ImageRender : public ImageViewport +{ +public: + /// constructor + ImageRender (KX_Scene * scene, KX_Camera * camera); + ImageRender (KX_Scene * scene, KX_GameObject * observer, KX_GameObject * mirror, RAS_IPolyMaterial * mat); + + /// destructor + virtual ~ImageRender (void); + + /// get background color + int getBackground (int idx) { return (idx < 0 || idx > 3) ? 0 : int(m_background[idx]*255.f); } + /// set background color + void setBackground (int red, int green, int blue, int alpha); + + /// clipping distance + float getClip (void) { return m_clip; } + /// set whole buffer use + void setClip (float clip) { m_clip = clip; } + +protected: + /// true if ready to render + bool m_render; + /// rendered scene + KX_Scene * m_scene; + /// camera for render + KX_Camera * m_camera; + /// do we own the camera? + bool m_owncamera; + /// for mirror operation + KX_GameObject * m_observer; + KX_GameObject * m_mirror; + float m_clip; // clipping distance + float m_mirrorHalfWidth; // mirror width in mirror space + float m_mirrorHalfHeight; // mirror height in mirror space + MT_Point3 m_mirrorPos; // mirror center position in local space + MT_Vector3 m_mirrorZ; // mirror Z axis in local space + MT_Vector3 m_mirrorY; // mirror Y axis in local space + MT_Vector3 m_mirrorX; // mirror X axis in local space + /// canvas + RAS_ICanvas* m_canvas; + /// rasterizer + RAS_IRasterizer* m_rasterizer; + /// render tools + RAS_IRenderTools* m_rendertools; + /// engine + KX_KetsjiEngine* m_engine; + + /// background colour + float m_background[4]; + + + /// render 3d scene to image + virtual void calcImage (unsigned int texId); + + void Render(); + void SetupRenderFrame(KX_Scene *scene, KX_Camera* cam); + void RenderFrame(KX_Scene* scene, KX_Camera* cam); + void SetBackGround(KX_WorldInfo* wi); + void SetWorldSettings(KX_WorldInfo* wi); +}; + + +#endif + diff --git a/source/gameengine/VideoTexture/ImageViewport.cpp b/source/gameengine/VideoTexture/ImageViewport.cpp new file mode 100644 index 00000000000..691a983970a --- /dev/null +++ b/source/gameengine/VideoTexture/ImageViewport.cpp @@ -0,0 +1,330 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +// implementation + +#include <PyObjectPlus.h> +#include <structmember.h> + +#include "GL/glew.h" + +#include "Texture.h" +#include "ImageBase.h" +#include "FilterSource.h" +#include "ImageViewport.h" + + +// constructor +ImageViewport::ImageViewport (void) : m_alpha(false), m_texInit(false) +{ + // get viewport rectangle + glGetIntegerv(GL_VIEWPORT, m_viewport); + // create buffer for viewport image + m_viewportImage = new BYTE [4 * getViewportSize()[0] * getViewportSize()[1]]; + // set attributes + setWhole(false); +} + +// destructor +ImageViewport::~ImageViewport (void) +{ delete m_viewportImage; } + + +// use whole viewport to capture image +void ImageViewport::setWhole (bool whole) +{ + // set whole + m_whole = whole; + // set capture size to viewport size, if whole, + // otherwise place area in the middle of viewport + for (int idx = 0; idx < 2; ++idx) + { + // capture size + m_capSize[idx] = whole ? short(getViewportSize()[idx]) + : calcSize(short(getViewportSize()[idx])); + // position + m_position[idx] = whole ? 0 : ((getViewportSize()[idx] - m_capSize[idx]) >> 1); + } + // init image + init(m_capSize[0], m_capSize[1]); + // set capture position + setPosition(); +} + +void ImageViewport::setCaptureSize (short * size) +{ + m_whole = false; + if (size == NULL) + size = m_capSize; + for (int idx = 0; idx < 2; ++idx) + { + if (size[idx] < 1) + m_capSize[idx] = 1; + else if (size[idx] > getViewportSize()[idx]) + m_capSize[idx] = short(getViewportSize()[idx]); + else + m_capSize[idx] = size[idx]; + } + init(m_capSize[0], m_capSize[1]); + // set capture position + setPosition(); +} + +// set position of capture rectangle +void ImageViewport::setPosition (GLint * pos) +{ + // if new position is not provided, use existing position + if (pos == NULL) pos = m_position; + // save position + for (int idx = 0; idx < 2; ++idx) + m_position[idx] = pos[idx] < 0 ? 0 : pos[idx] >= getViewportSize()[idx] + - m_capSize[idx] ? getViewportSize()[idx] - m_capSize[idx] : pos[idx]; + // recalc up left corner + for (int idx = 0; idx < 2; ++idx) + m_upLeft[idx] = m_position[idx] + m_viewport[idx]; +} + + +// capture image from viewport +void ImageViewport::calcImage (unsigned int texId) +{ + // if scale was changed + if (m_scaleChange) + // reset image + init(m_capSize[0], m_capSize[1]); + // if texture wasn't initialized + if (!m_texInit) + { + // initialize it + loadTexture(texId, m_image, m_size); + m_texInit = true; + } + // if texture can be directly created + if (texId != 0 && m_pyfilter == NULL && m_capSize[0] == calcSize(m_capSize[0]) + && m_capSize[1] == calcSize(m_capSize[1]) && !m_flip) + { + // just copy current viewport to texture + glBindTexture(GL_TEXTURE_2D, texId); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1]); + // image is not available + m_avail = false; + } + // otherwise copy viewport to buffer, if image is not available + else if (!m_avail) + { + // get frame buffer data + if (m_alpha) + { + glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA, + GL_UNSIGNED_BYTE, m_viewportImage); + // filter loaded data + FilterRGBA32 filt; + filterImage(filt, m_viewportImage, m_capSize); + } + else + { + glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGB, + GL_UNSIGNED_BYTE, m_viewportImage); + // filter loaded data + FilterRGB24 filt; + filterImage(filt, m_viewportImage, m_capSize); + } + } +} + + + +// cast Image pointer to ImageViewport +inline ImageViewport * getImageViewport (PyImage * self) +{ return static_cast<ImageViewport*>(self->m_image); } + + +// python methods + + +// get whole +PyObject * ImageViewport_getWhole (PyImage * self, void * closure) +{ + if (self->m_image != NULL && getImageViewport(self)->getWhole()) Py_RETURN_TRUE; + else Py_RETURN_FALSE; +} + +// set whole +int ImageViewport_setWhole (PyImage * self, PyObject * value, void * closure) +{ + // check parameter, report failure + if (value == NULL || !PyBool_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "The value must be a bool"); + return -1; + } + // set whole + if (self->m_image != NULL) getImageViewport(self)->setWhole(value == Py_True); + // success + return 0; +} + +// get alpha +PyObject * ImageViewport_getAlpha (PyImage * self, void * closure) +{ + if (self->m_image != NULL && getImageViewport(self)->getAlpha()) Py_RETURN_TRUE; + else Py_RETURN_FALSE; +} + +// set whole +int ImageViewport_setAlpha (PyImage * self, PyObject * value, void * closure) +{ + // check parameter, report failure + if (value == NULL || !PyBool_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "The value must be a bool"); + return -1; + } + // set alpha + if (self->m_image != NULL) getImageViewport(self)->setAlpha(value == Py_True); + // success + return 0; +} + + +// get position +static PyObject * ImageViewport_getPosition (PyImage * self, void * closure) +{ + return Py_BuildValue("(ii)", getImageViewport(self)->getPosition()[0], + getImageViewport(self)->getPosition()[1]); +} + +// set position +static int ImageViewport_setPosition (PyImage * self, PyObject * value, void * closure) +{ + // check validity of parameter + if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 2 + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0)) + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1))) + { + PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 ints"); + return -1; + } + // set position + GLint pos [] = { + GLint(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 0))), + GLint(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 1))) + }; + getImageViewport(self)->setPosition(pos); + // success + return 0; +} + +// get capture size +PyObject * ImageViewport_getCaptureSize (PyImage * self, void * closure) +{ + return Py_BuildValue("(ii)", getImageViewport(self)->getCaptureSize()[0], + getImageViewport(self)->getCaptureSize()[1]); +} + +// set capture size +int ImageViewport_setCaptureSize (PyImage * self, PyObject * value, void * closure) +{ + // check validity of parameter + if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 2 + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 0)) + || !PyLong_Check(PySequence_Fast_GET_ITEM(value, 1))) + { + PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 ints"); + return -1; + } + // set capture size + short size [] = { + short(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 0))), + short(PyLong_AsSsize_t(PySequence_Fast_GET_ITEM(value, 1))) + }; + getImageViewport(self)->setCaptureSize(size); + // success + return 0; +} + + +// methods structure +static PyMethodDef imageViewportMethods[] = +{ // methods from ImageBase class + {"refresh", (PyCFunction)Image_refresh, METH_NOARGS, "Refresh image - invalidate its current content"}, + {NULL} +}; +// attributes structure +static PyGetSetDef imageViewportGetSets[] = +{ + {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to capture", NULL}, + {(char*)"position", (getter)ImageViewport_getPosition, (setter)ImageViewport_setPosition, (char*)"upper left corner of captured area", NULL}, + {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of viewport area being captured", NULL}, + {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, + // attributes from ImageBase class + {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, + {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, + {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL}, + {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, + {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, + {NULL} +}; + + +// define python type +PyTypeObject ImageViewportType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.ImageViewport", /*tp_name*/ + sizeof(PyImage), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Image_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Image source from viewport", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + imageViewportMethods, /* tp_methods */ + 0, /* tp_members */ + imageViewportGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Image_init<ImageViewport>, /* tp_init */ + 0, /* tp_alloc */ + Image_allocNew, /* tp_new */ +}; diff --git a/source/gameengine/VideoTexture/ImageViewport.h b/source/gameengine/VideoTexture/ImageViewport.h new file mode 100644 index 00000000000..0449249cf95 --- /dev/null +++ b/source/gameengine/VideoTexture/ImageViewport.h @@ -0,0 +1,98 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined IMAGEVIEWPORT_H +#define IMAGEVIEWPORT_H + + +#include "Common.h" + +#include "ImageBase.h" + + +/// class for viewport access +class ImageViewport : public ImageBase +{ +public: + /// constructor + ImageViewport (void); + + /// destructor + virtual ~ImageViewport (void); + + /// is whole buffer used + bool getWhole (void) { return m_whole; } + /// set whole buffer use + void setWhole (bool whole); + + /// is alpha channel used + bool getAlpha (void) { return m_alpha; } + /// set whole buffer use + void setAlpha (bool alpha) { m_alpha = alpha; } + + /// get capture size in viewport + short * getCaptureSize (void) { return m_capSize; } + /// set capture size in viewport + void setCaptureSize (short * size = NULL); + + /// get position in viewport + GLint * getPosition (void) { return m_position; } + /// set position in viewport + void setPosition (GLint * pos = NULL); + +protected: + /// frame buffer rectangle + GLint m_viewport[4]; + + /// size of captured area + short m_capSize[2]; + /// use whole viewport + bool m_whole; + /// use alpha channel + bool m_alpha; + + /// position of capture rectangle in viewport + GLint m_position[2]; + /// upper left point for capturing + GLint m_upLeft[2]; + + /// buffer to copy viewport + BYTE * m_viewportImage; + /// texture is initialized + bool m_texInit; + + /// capture image from viewport + virtual void calcImage (unsigned int texId); + + /// get viewport size + GLint * getViewportSize (void) { return m_viewport + 2; } +}; + +PyObject * ImageViewport_getCaptureSize (PyImage * self, void * closure); +int ImageViewport_setCaptureSize (PyImage * self, PyObject * value, void * closure); +PyObject * ImageViewport_getWhole (PyImage * self, void * closure); +int ImageViewport_setWhole (PyImage * self, PyObject * value, void * closure); +PyObject * ImageViewport_getAlpha (PyImage * self, void * closure); +int ImageViewport_setAlpha (PyImage * self, PyObject * value, void * closure); + +#endif + diff --git a/source/gameengine/Physics/Sumo/Makefile b/source/gameengine/VideoTexture/Makefile index 69efc4d84eb..90457df720f 100644 --- a/source/gameengine/Physics/Sumo/Makefile +++ b/source/gameengine/VideoTexture/Makefile @@ -28,23 +28,40 @@ # # -SOURCEDIR = source/gameengine/Physics/Sumo -LIBNAME = sumo -DIR = $(OCGDIR)/gameengine/blphys/$(LIBNAME) -DIRS = Fuzzics +LIBNAME = videotex +DIR = $(OCGDIR)/gameengine/$(LIBNAME) +SOURCEDIR = source/gameengine/VideoTexture include nan_compile.mk CCFLAGS += $(LEVEL_1_CPP_WARNINGS) +CPPFLAGS += $(OGL_CPPFLAGS) +CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) +CPPFLAGS += -I../../blender/python CPPFLAGS += -I$(NAN_STRING)/include -CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) - -CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO) -I$(NAN_MOTO)/include -CPPFLAGS += -I$(NAN_SOLID)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../Rasterizer/RAS_OpenGLRasterizer +CPPFLAGS += -I../Rasterizer -I../GameLogic -I../SceneGraph +CPPFLAGS += -I../BlenderRoutines -I../Expressions -I../Ketsji +CPPFLAGS += -I../../kernel/gen_system +CPPFLAGS += -I. +CPPFLAGS += -I../../blender/blenkernel +CPPFLAGS += -I../../blender/blenlib +CPPFLAGS += -I../../blender/editors/include +CPPFLAGS += -I../../blender/makesdna +CPPFLAGS += -I../../blender/imbuf +CPPFLAGS += -I../../blender/gpu CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include -CPPFLAGS += -I../../Physics/common -CPPFLAGS += -I../../Physics/Dummy -include nan_subdirs.mk +ifeq ($(WITH_FFMPEG),true) + CPPFLAGS += -DWITH_FFMPEG + CPPFLAGS += $(NAN_FFMPEGCFLAGS) + ifdef NAN_PTHREADS + CPPFLAGS += -I$(NAN_PTHREADS)/include + endif +endif + + diff --git a/source/gameengine/VideoTexture/PyTypeList.cpp b/source/gameengine/VideoTexture/PyTypeList.cpp new file mode 100644 index 00000000000..2d571675dbd --- /dev/null +++ b/source/gameengine/VideoTexture/PyTypeList.cpp @@ -0,0 +1,82 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of blendTex library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + + +#include "PyTypeList.h" + +#include <memory> +#include <vector> + +#include <PyObjectPlus.h> + + +/// check, if type is in list +bool PyTypeList::in (PyTypeObject * type) +{ + // if list exists + if (m_list.get() != NULL) + // iterate items in list + for (PyTypeListType::iterator it = m_list->begin(); it != m_list->end(); ++it) + // if item is found, return with success + if ((*it)->getType() == type) return true; + // otherwise return not found + return false; +} + +/// add type to list +void PyTypeList::add (PyTypeObject * type, const char * name) +{ + // if list doesn't exist, create it + if (m_list.get() == NULL) + m_list.reset(new PyTypeListType()); + if (!in(type)) + // add new item to list + m_list->push_back(new PyTypeListItem(type, name)); +} + +/// prepare types +bool PyTypeList::ready (void) +{ + // if list exists + if (m_list.get() != NULL) + // iterate items in list + for (PyTypeListType::iterator it = m_list->begin(); it != m_list->end(); ++it) + // if preparation failed, report it + if (PyType_Ready((*it)->getType()) < 0) return false; + // success + return true; +} + +/// register types to module +void PyTypeList::reg (PyObject * module) +{ + // if list exists + if (m_list.get() != NULL) + // iterate items in list + for (PyTypeListType::iterator it = m_list->begin(); it != m_list->end(); ++it) + { + // increase ref count + Py_INCREF((*it)->getType()); + // add type to module + PyModule_AddObject(module, (char*)(*it)->getName(), (PyObject*)(*it)->getType()); + } +} diff --git a/source/gameengine/VideoTexture/PyTypeList.h b/source/gameengine/VideoTexture/PyTypeList.h new file mode 100644 index 00000000000..4daf88bfa19 --- /dev/null +++ b/source/gameengine/VideoTexture/PyTypeList.h @@ -0,0 +1,85 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of blendTex library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined PYTYPELIST_H +#define PYTYPELIST_H + +#include "Common.h" + +#include <memory> +#include <vector> + +#include <PyObjectPlus.h> + +// forward declaration +class PyTypeListItem; + +// type for list of types +typedef std::vector<PyTypeListItem*> PyTypeListType; + + +/// class to store list of python types +class PyTypeList +{ +public: + /// check, if type is in list + bool in (PyTypeObject * type); + + /// add type to list + void add (PyTypeObject * type, const char * name); + + /// prepare types + bool ready (void); + + /// register types to module + void reg (PyObject * module); + +protected: + /// pointer to list of types + std::auto_ptr<PyTypeListType> m_list; +}; + + +/// class for item of python type list +class PyTypeListItem +{ +public: + /// constructor adds type into list + PyTypeListItem (PyTypeObject * type, const char * name) + : m_type(type), m_name(name) + { } + + /// does type match + PyTypeObject * getType (void) { return m_type; } + + /// get name of type + const char * getName (void) { return m_name; } + +protected: + /// pointer to type object + PyTypeObject * m_type; + /// name of type + const char * m_name; +}; + + +#endif diff --git a/source/gameengine/VideoTexture/SConscript b/source/gameengine/VideoTexture/SConscript new file mode 100644 index 00000000000..119bd1c9954 --- /dev/null +++ b/source/gameengine/VideoTexture/SConscript @@ -0,0 +1,29 @@ +#!/usr/bin/python +import sys + +Import ('env') + +sources = env.Glob('*.cpp') + +incs = '. #source/gameengine/Ketsji #source/gameengine/Expressions' +incs += ' #source/gameengine/GameLogic #source/gameengine/SceneGraph #source/gameengine/Rasterizer' +incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer' +incs += ' #source/gameengine/BlenderRoutines' +incs += ' #source/blender/editors/include #source/blender/blenlib #source/blender/blenkernel' +incs += ' #source/blender/makesdna #source/blender/imbuf #source/blender/python' +incs += ' #source/blender/gpu #source/kernel/gen_system #intern/string #intern/moto/include' +incs += ' #intern/guardedalloc #extern/glew/include' + +defs = [] +if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): + if env['BF_DEBUG']: + defs.append('_DEBUG') + +incs += ' ' + env['BF_PYTHON_INC'] +#incs += ' ' + env['BF_OPENGL_INC'] + +if env['WITH_BF_FFMPEG']: + defs.append('WITH_FFMPEG') + incs += ' ' + env['BF_FFMPEG_INC'] + ' ' + env['BF_PTHREADS_INC'] + +env.BlenderLib ( 'bf_videotex', sources, Split(incs), defs, libtype=['core','player'], priority=[300,205], cxx_compileflags=env['BGE_CXXFLAGS']) diff --git a/source/gameengine/VideoTexture/Texture.cpp b/source/gameengine/VideoTexture/Texture.cpp new file mode 100644 index 00000000000..04b39f0b05c --- /dev/null +++ b/source/gameengine/VideoTexture/Texture.cpp @@ -0,0 +1,475 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +// implementation + +#include <PyObjectPlus.h> +#include <structmember.h> + +#include <KX_GameObject.h> +#include <RAS_MeshObject.h> +#include <DNA_mesh_types.h> +#include <DNA_meshdata_types.h> +#include <DNA_image_types.h> +#include <IMB_imbuf_types.h> +#include <KX_PolygonMaterial.h> + +#include <MEM_guardedalloc.h> + +#include <KX_BlenderMaterial.h> +#include <BL_Texture.h> + +#include "KX_KetsjiEngine.h" +#include "KX_PythonInit.h" +#include "Texture.h" +#include "ImageBase.h" +#include "Exception.h" + +#include <memory.h> +#include "GL/glew.h" + + +// macro for exception handling and logging +#define CATCH_EXCP catch (Exception & exp) \ +{ exp.report(); return NULL; } + + +// Blender GameObject type +BlendType<KX_GameObject> gameObjectType ("KX_GameObject"); + + +// load texture +void loadTexture (unsigned int texId, unsigned int * texture, short * size, + bool mipmap) +{ + // load texture for rendering + glBindTexture(GL_TEXTURE_2D, texId); + if (mipmap) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, texture); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size[0], size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, texture); + } + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +} + + +// get pointer to material +RAS_IPolyMaterial * getMaterial (PyObject *obj, short matID) +{ + // if object is available + if (obj != NULL) + { + // get pointer to texture image + KX_GameObject * gameObj = gameObjectType.checkType(obj); + if (gameObj != NULL && gameObj->GetMeshCount() > 0) + { + // get material from mesh + RAS_MeshObject * mesh = gameObj->GetMesh(0); + RAS_MeshMaterial *meshMat = mesh->GetMeshMaterial(matID); + if (meshMat != NULL && meshMat->m_bucket != NULL) + // return pointer to polygon or blender material + return meshMat->m_bucket->GetPolyMaterial(); + } + } + // otherwise material was not found + return NULL; +} + + +// get material ID +short getMaterialID (PyObject * obj, char * name) +{ + // search for material + for (short matID = 0;; ++matID) + { + // get material + RAS_IPolyMaterial * mat = getMaterial(obj, matID); + // if material is not available, report that no material was found + if (mat == NULL) + break; + // name is a material name if it starts with MA and a UV texture name if it starts with IM + if (name[0] == 'I' && name[1] == 'M') + { + // if texture name matches + if (strcmp(mat->GetTextureName().ReadPtr(), name) == 0) + return matID; + } else + { + // if material name matches + if (strcmp(mat->GetMaterialName().ReadPtr(), name) == 0) + return matID; + } + } + // material was not found + return -1; +} + + +// Texture object allocation +PyObject * Texture_new (PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + // allocate object + Texture * self = reinterpret_cast<Texture*>(type->tp_alloc(type, 0)); + // initialize object structure + self->m_actTex = 0; + self->m_orgSaved = false; + self->m_imgTexture = NULL; + self->m_matTexture = NULL; + self->m_mipmap = false; + self->m_scaledImg = NULL; + self->m_scaledImgSize = 0; + self->m_source = NULL; + self->m_lastClock = 0.0; + // return allocated object + return reinterpret_cast<PyObject*>(self); +} + + +// forward declaration +PyObject * Texture_close(Texture * self); +int Texture_setSource (Texture * self, PyObject * value, void * closure); + + +// Texture object deallocation +void Texture_dealloc (Texture * self) +{ + // release renderer + Py_XDECREF(self->m_source); + // close texture + PyObject* ret = Texture_close(self); + Py_DECREF(ret); + // release scaled image buffer + delete [] self->m_scaledImg; + // release object + ((PyObject *)self)->ob_type->tp_free((PyObject*)self); +} + + +ExceptionID MaterialNotAvail; +ExpDesc MaterialNotAvailDesc (MaterialNotAvail, "Texture material is not available"); + +// Texture object initialization +int Texture_init (Texture *self, PyObject *args, PyObject *kwds) +{ + // parameters - game object with video texture + PyObject * obj = NULL; + // material ID + short matID = 0; + // texture ID + short texID = 0; + // texture object with shared texture ID + Texture * texObj = NULL; + + static char *kwlist[] = {"gameObj", "materialID", "textureID", "textureObj", NULL}; + + // get parameters + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|hhO!", kwlist, &obj, &matID, + &texID, &TextureType, &texObj)) + return -1; + + // if parameters are available + if (obj != NULL) + { + // process polygon material or blender material + try + { + // get pointer to texture image + RAS_IPolyMaterial * mat = getMaterial(obj, matID); + if (mat != NULL) + { + // is it blender material or polygon material + if (mat->GetFlag() & RAS_BLENDERGLSL) + { + self->m_imgTexture = static_cast<KX_BlenderMaterial*>(mat)->getImage(texID); + self->m_useMatTexture = false; + } else if (mat->GetFlag() & RAS_BLENDERMAT) + { + // get blender material texture + self->m_matTexture = static_cast<KX_BlenderMaterial*>(mat)->getTex(texID); + self->m_useMatTexture = true; + } + else + { + // get texture pointer from polygon material + MTFace * tface = static_cast<KX_PolygonMaterial*>(mat)->GetMTFace(); + self->m_imgTexture = (Image*)tface->tpage; + self->m_useMatTexture = false; + } + } + // check if texture is available, if not, initialization failed + if (self->m_imgTexture == NULL && self->m_matTexture == NULL) + // throw exception if initialization failed + THRWEXCP(MaterialNotAvail, S_OK); + + // if texture object is provided + if (texObj != NULL) + { + // copy texture code + self->m_actTex = texObj->m_actTex; + self->m_mipmap = texObj->m_mipmap; + if (texObj->m_source != NULL) + Texture_setSource(self, reinterpret_cast<PyObject*>(texObj->m_source), NULL); + } + else + // otherwise generate texture code + glGenTextures(1, (GLuint*)&self->m_actTex); + } + catch (Exception & exp) + { + exp.report(); + return -1; + } + } + // initialization succeded + return 0; +} + + +// close added texture +PyObject * Texture_close(Texture * self) +{ + // restore texture + if (self->m_orgSaved) + { + self->m_orgSaved = false; + // restore original texture code + if (self->m_useMatTexture) + self->m_matTexture->swapTexture(self->m_orgTex); + else + self->m_imgTexture->bindcode = self->m_orgTex; + // drop actual texture + if (self->m_actTex != 0) + { + glDeleteTextures(1, (GLuint *)&self->m_actTex); + self->m_actTex = 0; + } + } + Py_RETURN_NONE; +} + + +// refresh texture +PyObject * Texture_refresh (Texture * self, PyObject * args) +{ + // get parameter - refresh source + PyObject * param; + if (!PyArg_ParseTuple(args, "O:refresh", ¶m) || !PyBool_Check(param)) + { + // report error + PyErr_SetString(PyExc_TypeError, "The value must be a bool"); + return NULL; + } + // some trick here: we are in the business of loading a texture, + // no use to do it if we are still in the same rendering frame. + // We find this out by looking at the engine current clock time + KX_KetsjiEngine* engine = KX_GetActiveEngine(); + if (engine->GetClockTime() != self->m_lastClock) + { + self->m_lastClock = engine->GetClockTime(); + // set source refresh + bool refreshSource = (param == Py_True); + // try to proces texture from source + try + { + // if source is available + if (self->m_source != NULL) + { + // check texture code + if (!self->m_orgSaved) + { + self->m_orgSaved = true; + // save original image code + if (self->m_useMatTexture) + self->m_orgTex = self->m_matTexture->swapTexture(self->m_actTex); + else + { + self->m_orgTex = self->m_imgTexture->bindcode; + self->m_imgTexture->bindcode = self->m_actTex; + } + } + + // get texture + unsigned int * texture = self->m_source->m_image->getImage(self->m_actTex); + // if texture is available + if (texture != NULL) + { + // get texture size + short * orgSize = self->m_source->m_image->getSize(); + // calc scaled sizes + short size[] = {ImageBase::calcSize(orgSize[0]), ImageBase::calcSize(orgSize[1])}; + // scale texture if needed + if (size[0] != orgSize[0] || size[1] != orgSize[1]) + { + // if scaled image buffer is smaller than needed + if (self->m_scaledImgSize < (unsigned int)(size[0] * size[1])) + { + // new size + self->m_scaledImgSize = size[0] * size[1]; + // allocate scaling image + delete [] self->m_scaledImg; + self->m_scaledImg = new unsigned int[self->m_scaledImgSize]; + } + // scale texture + gluScaleImage(GL_RGBA, orgSize[0], orgSize[1], GL_UNSIGNED_BYTE, texture, + size[0], size[1], GL_UNSIGNED_BYTE, self->m_scaledImg); + // use scaled image instead original + texture = self->m_scaledImg; + } + // load texture for rendering + loadTexture (self->m_actTex, texture, size, self->m_mipmap); + + // refresh texture source, if required + if (refreshSource) self->m_source->m_image->refresh(); + } + } + } + CATCH_EXCP; + } + Py_RETURN_NONE; +} + + +// get mipmap value +PyObject * Texture_getMipmap (Texture * self, void * closure) +{ + // return true if flag is set, otherwise false + if (self->m_mipmap) Py_RETURN_TRUE; + else Py_RETURN_FALSE; +} + +// set mipmap value +int Texture_setMipmap (Texture * self, PyObject * value, void * closure) +{ + // check parameter, report failure + if (value == NULL || !PyBool_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "The value must be a bool"); + return -1; + } + // set mipmap + self->m_mipmap = value == Py_True; + // success + return 0; +} + + +// get source object +PyObject * Texture_getSource (Texture * self, PyObject * value, void * closure) +{ + // if source exists + if (self->m_source != NULL) + { + Py_INCREF(self->m_source); + return reinterpret_cast<PyObject*>(self->m_source); + } + // otherwise return None + Py_RETURN_NONE; +} + + +// set source object +int Texture_setSource (Texture * self, PyObject * value, void * closure) +{ + // check new value + if (value == NULL || !pyImageTypes.in(value->ob_type)) + { + // report value error + PyErr_SetString(PyExc_TypeError, "Invalid type of value"); + return -1; + } + // increase ref count for new value + Py_INCREF(value); + // release previous + Py_XDECREF(self->m_source); + // set new value + self->m_source = reinterpret_cast<PyImage*>(value); + // return success + return 0; +} + + +// class Texture methods +static PyMethodDef textureMethods[] = +{ + { "close", (PyCFunction)Texture_close, METH_NOARGS, "Close dynamic texture and restore original"}, + { "refresh", (PyCFunction)Texture_refresh, METH_VARARGS, "Refresh texture from source"}, + {NULL} /* Sentinel */ +}; + +// class Texture attributes +static PyGetSetDef textureGetSets[] = +{ + {(char*)"source", (getter)Texture_getSource, (setter)Texture_setSource, (char*)"source of texture", NULL}, + {(char*)"mipmap", (getter)Texture_getMipmap, (setter)Texture_setMipmap, (char*)"mipmap texture", NULL}, + {NULL} +}; + + +// class Texture declaration +PyTypeObject TextureType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.Texture", /*tp_name*/ + sizeof(Texture), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Texture_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Texture objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + textureMethods, /* tp_methods */ + 0, /* tp_members */ + textureGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Texture_init, /* tp_init */ + 0, /* tp_alloc */ + Texture_new, /* tp_new */ +}; diff --git a/source/gameengine/VideoTexture/Texture.h b/source/gameengine/VideoTexture/Texture.h new file mode 100644 index 00000000000..1bbef8f0f9e --- /dev/null +++ b/source/gameengine/VideoTexture/Texture.h @@ -0,0 +1,92 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2006 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined TEXTURE_H +#define TEXTURE_H + +#include <PyObjectPlus.h> +#include <structmember.h> + +#include <DNA_image_types.h> +#include <BL_Texture.h> +#include <KX_BlenderMaterial.h> + +#include "ImageBase.h" +#include "BlendType.h" +#include "Exception.h" + + +// type Texture declaration +struct Texture +{ + PyObject_HEAD + + // texture is using blender material + bool m_useMatTexture; + + // video texture bind code + unsigned int m_actTex; + // original texture bind code + unsigned int m_orgTex; + // original texture saved + bool m_orgSaved; + + // texture image for game materials + Image * m_imgTexture; + // texture for blender materials + BL_Texture * m_matTexture; + + // use mipmapping + bool m_mipmap; + + // scaled image buffer + unsigned int * m_scaledImg; + // scaled image buffer size + unsigned int m_scaledImgSize; + // last refresh + double m_lastClock; + + // image source + PyImage * m_source; +}; + + +// Texture type description +extern PyTypeObject TextureType; + +// load texture +void loadTexture (unsigned int texId, unsigned int * texture, short * size, + bool mipmap = false); + +// get material +RAS_IPolyMaterial * getMaterial (PyObject *obj, short matID); + +// get material ID +short getMaterialID (PyObject * obj, char * name); + +// Exceptions +extern ExceptionID MaterialNotAvail; + +// object type +extern BlendType<KX_GameObject> gameObjectType; + +#endif diff --git a/source/gameengine/VideoTexture/VideoBase.cpp b/source/gameengine/VideoTexture/VideoBase.cpp new file mode 100644 index 00000000000..5de7a9e80a9 --- /dev/null +++ b/source/gameengine/VideoTexture/VideoBase.cpp @@ -0,0 +1,198 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if defined WIN32 +#define WINDOWS_LEAN_AND_MEAN +#include <windows.h> +#endif + +#include "VideoBase.h" + +#include "FilterSource.h" + +// VideoBase implementation + + +// initialize image data +void VideoBase::init(short width, short height) +{ + // save original sizes + m_orgSize[0] = width; + m_orgSize[1] = height; + // call base class initialization + ImageBase::init(width, height); +} + + +// process video frame +void VideoBase::process (BYTE * sample) +{ + // if scale was changed + if (m_scaleChange) + // reset image + init(m_orgSize[0], m_orgSize[1]); + // if image is allocated and is able to store new image + if (m_image != NULL && !m_avail) + { + // filters used + // convert video format to image + switch (m_format) + { + case RGBA32: + { + FilterRGBA32 filtRGBA; + // use filter object for format to convert image + filterImage(filtRGBA, sample, m_orgSize); + // finish + break; + } + case RGB24: + { + FilterRGB24 filtRGB; + // use filter object for format to convert image + filterImage(filtRGB, sample, m_orgSize); + // finish + break; + } + case YV12: + { + // use filter object for format to convert image + FilterYV12 filtYUV; + filtYUV.setBuffs(sample, m_orgSize); + filterImage(filtYUV, sample, m_orgSize); + // finish + break; + } + } + } +} + + +// python functions + + +// exceptions for video source initialization +ExceptionID SourceVideoEmpty, SourceVideoCreation; +ExpDesc SourceVideoEmptyDesc (SourceVideoEmpty, "Source Video is empty"); +ExpDesc SourceVideoCreationDesc (SourceVideoCreation, "SourceVideo object was not created"); + +// open video source +void Video_open (VideoBase * self, char * file, short captureID) +{ + // if file is empty, throw exception + if (file == NULL) THRWEXCP(SourceVideoEmpty, S_OK); + + // open video file or capture device + if (captureID >= 0) + self->openCam(file, captureID); + else + self->openFile(file); +} + + +// play video +PyObject * Video_play (PyImage * self) +{ if (getVideo(self)->play()) Py_RETURN_TRUE; else Py_RETURN_FALSE; } + +// pause video +PyObject * Video_pause (PyImage * self) +{ if (getVideo(self)->pause()) Py_RETURN_TRUE; else Py_RETURN_FALSE; } + +PyObject * Video_stop (PyImage * self) +{ if (getVideo(self)->stop()) Py_RETURN_TRUE; else Py_RETURN_FALSE; } + +// get status +PyObject * Video_getStatus (PyImage * self, void * closure) +{ + return Py_BuildValue("h", getVideo(self)->getStatus()); +} + +// refresh video +PyObject * Video_refresh (PyImage * self) +{ + getVideo(self)->refresh(); + return Video_getStatus(self, NULL); +} + + +// get range +PyObject * Video_getRange (PyImage * self, void * closure) +{ + return Py_BuildValue("[ff]", getVideo(self)->getRange()[0], + getVideo(self)->getRange()[1]); +} + +// set range +int Video_setRange (PyImage * self, PyObject * value, void * closure) +{ + // check validity of parameter + if (value == NULL || !PySequence_Check(value) || PySequence_Length(value) != 2 + || !PyFloat_Check(PySequence_Fast_GET_ITEM(value, 0)) + || !PyFloat_Check(PySequence_Fast_GET_ITEM(value, 1))) + { + PyErr_SetString(PyExc_TypeError, "The value must be a sequence of 2 float"); + return -1; + } + // set range + getVideo(self)->setRange(PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0)), + PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1))); + // success + return 0; +} + +// get repeat +PyObject * Video_getRepeat (PyImage * self, void * closure) +{ return Py_BuildValue("h", getVideo(self)->getRepeat()); } + +// set repeat +int Video_setRepeat (PyImage * self, PyObject * value, void * closure) +{ + // check validity of parameter + if (value == NULL || !PyLong_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "The value must be an int"); + return -1; + } + // set repeat + getVideo(self)->setRepeat(int(PyLong_AsSsize_t(value))); + // success + return 0; +} + +// get frame rate +PyObject * Video_getFrameRate (PyImage * self, void * closure) +{ return Py_BuildValue("f", double(getVideo(self)->getFrameRate())); } + +// set frame rate +int Video_setFrameRate (PyImage * self, PyObject * value, void * closure) +{ + // check validity of parameter + if (value == NULL || !PyFloat_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "The value must be a float"); + return -1; + } + // set repeat + getVideo(self)->setFrameRate(float(PyFloat_AsDouble(value))); + // success + return 0; +} diff --git a/source/gameengine/VideoTexture/VideoBase.h b/source/gameengine/VideoTexture/VideoBase.h new file mode 100644 index 00000000000..0c8668ee0bc --- /dev/null +++ b/source/gameengine/VideoTexture/VideoBase.h @@ -0,0 +1,196 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#if !defined VIDEOBASE_H +#define VIDEOBASE_H + + +#include <PyObjectPlus.h> + +#include "ImageBase.h" + +#include "Exception.h" + +// source states +const int SourceError = -1; +const int SourceEmpty = 0; +const int SourceReady = 1; +const int SourcePlaying = 2; +const int SourceStopped = 3; + + +// video source formats +enum VideoFormat { None, RGB24, YV12, RGBA32 }; + + +/// base class for video source +class VideoBase : public ImageBase +{ +public: + /// constructor + VideoBase (void) : ImageBase(true), m_format(None), m_status(SourceEmpty), + m_repeat(0), m_frameRate(1.0) + { + m_orgSize[0] = m_orgSize[1] = 0; + m_range[0] = m_range[1] = 0.0; + } + + /// destructor + virtual ~VideoBase (void) {} + + /// open video file + virtual void openFile (char * file) + { + m_isFile = true; + m_status = SourceReady; + } + /// open video capture device + virtual void openCam (char * file, short camIdx) + { + m_isFile = false; + m_status = SourceReady; + } + + /// play video + virtual bool play (void) + { + if (m_status == SourceReady || m_status == SourceStopped) + { + m_status = SourcePlaying; + return true; + } + return false; + } + /// pause video + virtual bool pause (void) + { + if (m_status == SourcePlaying) + { + m_status = SourceStopped; + return true; + } + return false; + } + /// stop video + virtual bool stop (void) + { + if (m_status == SourcePlaying) + { + m_status = SourceStopped; + return true; + } + return false; + } + + // get video status + int getStatus (void) { return m_status; } + + /// get play range + const double * getRange (void) { return m_range; } + /// set play range + virtual void setRange (double start, double stop) + { + if (m_isFile) + { + m_range[0] = start; + m_range[1] = stop; + } + } + + // get video repeat + int getRepeat (void) { return m_repeat; } + /// set video repeat + virtual void setRepeat (int rep) + { if (m_isFile) m_repeat = rep; } + + /// get frame rate + float getFrameRate (void) { return m_frameRate; } + /// set frame rate + virtual void setFrameRate (float rate) + { if (m_isFile) m_frameRate = rate > 0.0 ? rate : 1.0f; } + +protected: + /// video format + VideoFormat m_format; + /// original video size + short m_orgSize[2]; + + /// video status + int m_status; + + /// is source file + bool m_isFile; + + /// replay range + double m_range[2]; + /// repeat count + int m_repeat; + /// frame rate + float m_frameRate; + + /// initialize image data + void init (short width, short height); + + /// process source data + void process (BYTE * sample); +}; + + + +// python fuctions + + +// cast Image pointer to Video +inline VideoBase * getVideo (PyImage * self) +{ return static_cast<VideoBase*>(self->m_image); } + + +extern ExceptionID SourceVideoCreation; + +// object initialization +template <class T> void Video_init (PyImage * self) +{ + // create source video object + if (self->m_image != NULL) delete self->m_image; + HRESULT hRslt = S_OK; + self->m_image = new T(&hRslt); + CHCKHRSLT(hRslt, SourceVideoCreation); +} + + +// video functions +void Video_open (VideoBase * self, char * file, short captureID); +PyObject * Video_play (PyImage * self); +PyObject * Video_pause (PyImage * self); +PyObject * Video_stop (PyImage * self); +PyObject * Video_refresh (PyImage * self); +PyObject * Video_getStatus (PyImage * self, void * closure); +PyObject * Video_getRange (PyImage * self, void * closure); +int Video_setRange (PyImage * self, PyObject * value, void * closure); +PyObject * Video_getRepeat (PyImage * self, void * closure); +int Video_setRepeat (PyImage * self, PyObject * value, void * closure); +PyObject * Video_getFrameRate (PyImage * self, void * closure); +int Video_setFrameRate (PyImage * self, PyObject * value, void * closure); + + +#endif + diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp new file mode 100644 index 00000000000..f21555a95c9 --- /dev/null +++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp @@ -0,0 +1,1323 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#ifdef WITH_FFMPEG + +// INT64_C fix for some linux machines (C99ism) +#define __STDC_CONSTANT_MACROS +#include <stdint.h> + + +#include "MEM_guardedalloc.h" +#include "PIL_time.h" + +#include <string> + +#include "Exception.h" +#include "VideoFFmpeg.h" + + +// default framerate +const double defFrameRate = 25.0; +// time scale constant +const long timeScale = 1000; + +// macro for exception handling and logging +#define CATCH_EXCP catch (Exception & exp) \ +{ exp.report(); m_status = SourceError; } + +extern "C" void do_init_ffmpeg(); + +// class RenderVideo + +// constructor +VideoFFmpeg::VideoFFmpeg (HRESULT * hRslt) : VideoBase(), +m_codec(NULL), m_formatCtx(NULL), m_codecCtx(NULL), +m_frame(NULL), m_frameDeinterlaced(NULL), m_frameRGB(NULL), m_imgConvertCtx(NULL), +m_deinterlace(false), m_preseek(0), m_videoStream(-1), m_baseFrameRate(25.0), +m_lastFrame(-1), m_eof(false), m_curPosition(-1), m_startTime(0), +m_captWidth(0), m_captHeight(0), m_captRate(0.f), m_isImage(false), +m_isThreaded(false), m_stopThread(false), m_cacheStarted(false) +{ + // set video format + m_format = RGB24; + // force flip because ffmpeg always return the image in the wrong orientation for texture + setFlip(true); + // construction is OK + *hRslt = S_OK; + m_thread.first = m_thread.last = NULL; + pthread_mutex_init(&m_cacheMutex, NULL); + m_frameCacheFree.first = m_frameCacheFree.last = NULL; + m_frameCacheBase.first = m_frameCacheBase.last = NULL; + m_packetCacheFree.first = m_packetCacheFree.last = NULL; + m_packetCacheBase.first = m_packetCacheBase.last = NULL; +} + +// destructor +VideoFFmpeg::~VideoFFmpeg () +{ +} + + +// release components +bool VideoFFmpeg::release() +{ + // release + stopCache(); + if (m_codecCtx) + { + avcodec_close(m_codecCtx); + m_codecCtx = NULL; + } + if (m_formatCtx) + { + av_close_input_file(m_formatCtx); + m_formatCtx = NULL; + } + if (m_frame) + { + av_free(m_frame); + m_frame = NULL; + } + if (m_frameDeinterlaced) + { + MEM_freeN(m_frameDeinterlaced->data[0]); + av_free(m_frameDeinterlaced); + m_frameDeinterlaced = NULL; + } + if (m_frameRGB) + { + MEM_freeN(m_frameRGB->data[0]); + av_free(m_frameRGB); + m_frameRGB = NULL; + } + if (m_imgConvertCtx) + { + sws_freeContext(m_imgConvertCtx); + m_imgConvertCtx = NULL; + } + m_codec = NULL; + m_status = SourceStopped; + m_lastFrame = -1; + return true; +} + +AVFrame *VideoFFmpeg::allocFrameRGB() +{ + AVFrame *frame; + frame = avcodec_alloc_frame(); + if (m_format == RGBA32) + { + avpicture_fill((AVPicture*)frame, + (uint8_t*)MEM_callocN(avpicture_get_size( + PIX_FMT_RGBA, + m_codecCtx->width, m_codecCtx->height), + "ffmpeg rgba"), + PIX_FMT_RGBA, m_codecCtx->width, m_codecCtx->height); + } else + { + avpicture_fill((AVPicture*)frame, + (uint8_t*)MEM_callocN(avpicture_get_size( + PIX_FMT_RGB24, + m_codecCtx->width, m_codecCtx->height), + "ffmpeg rgb"), + PIX_FMT_RGB24, m_codecCtx->width, m_codecCtx->height); + } + return frame; +} + +// set initial parameters +void VideoFFmpeg::initParams (short width, short height, float rate, bool image) +{ + m_captWidth = width; + m_captHeight = height; + m_captRate = rate; + m_isImage = image; +} + + +int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AVFormatParameters *formatParams) +{ + AVFormatContext *formatCtx; + int i, videoStream; + AVCodec *codec; + AVCodecContext *codecCtx; + + if(av_open_input_file(&formatCtx, filename, inputFormat, 0, formatParams)!=0) + return -1; + + if(av_find_stream_info(formatCtx)<0) + { + av_close_input_file(formatCtx); + return -1; + } + + /* Find the first video stream */ + videoStream=-1; + for(i=0; i<formatCtx->nb_streams; i++) + { + if(formatCtx->streams[i] && + get_codec_from_stream(formatCtx->streams[i]) && + (get_codec_from_stream(formatCtx->streams[i])->codec_type==CODEC_TYPE_VIDEO)) + { + videoStream=i; + break; + } + } + + if(videoStream==-1) + { + av_close_input_file(formatCtx); + return -1; + } + + codecCtx = get_codec_from_stream(formatCtx->streams[videoStream]); + + /* Find the decoder for the video stream */ + codec=avcodec_find_decoder(codecCtx->codec_id); + if(codec==NULL) + { + av_close_input_file(formatCtx); + return -1; + } + codecCtx->workaround_bugs = 1; + if(avcodec_open(codecCtx, codec)<0) + { + av_close_input_file(formatCtx); + return -1; + } + +#ifdef FFMPEG_OLD_FRAME_RATE + if(codecCtx->frame_rate>1000 && codecCtx->frame_rate_base==1) + codecCtx->frame_rate_base=1000; + m_baseFrameRate = (double)codecCtx->frame_rate / (double)codecCtx->frame_rate_base; +#else + m_baseFrameRate = av_q2d(formatCtx->streams[videoStream]->r_frame_rate); +#endif + if (m_baseFrameRate <= 0.0) + m_baseFrameRate = defFrameRate; + + m_codec = codec; + m_codecCtx = codecCtx; + m_formatCtx = formatCtx; + m_videoStream = videoStream; + m_frame = avcodec_alloc_frame(); + m_frameDeinterlaced = avcodec_alloc_frame(); + + // allocate buffer if deinterlacing is required + avpicture_fill((AVPicture*)m_frameDeinterlaced, + (uint8_t*)MEM_callocN(avpicture_get_size( + m_codecCtx->pix_fmt, + m_codecCtx->width, m_codecCtx->height), + "ffmpeg deinterlace"), + m_codecCtx->pix_fmt, m_codecCtx->width, m_codecCtx->height); + + // check if the pixel format supports Alpha + if (m_codecCtx->pix_fmt == PIX_FMT_RGB32 || + m_codecCtx->pix_fmt == PIX_FMT_BGR32 || + m_codecCtx->pix_fmt == PIX_FMT_RGB32_1 || + m_codecCtx->pix_fmt == PIX_FMT_BGR32_1) + { + // allocate buffer to store final decoded frame + m_format = RGBA32; + // allocate sws context + m_imgConvertCtx = sws_getContext( + m_codecCtx->width, + m_codecCtx->height, + m_codecCtx->pix_fmt, + m_codecCtx->width, + m_codecCtx->height, + PIX_FMT_RGBA, + SWS_FAST_BILINEAR, + NULL, NULL, NULL); + } else + { + // allocate buffer to store final decoded frame + m_format = RGB24; + // allocate sws context + m_imgConvertCtx = sws_getContext( + m_codecCtx->width, + m_codecCtx->height, + m_codecCtx->pix_fmt, + m_codecCtx->width, + m_codecCtx->height, + PIX_FMT_RGB24, + SWS_FAST_BILINEAR, + NULL, NULL, NULL); + } + m_frameRGB = allocFrameRGB(); + + if (!m_imgConvertCtx) { + avcodec_close(m_codecCtx); + m_codecCtx = NULL; + av_close_input_file(m_formatCtx); + m_formatCtx = NULL; + av_free(m_frame); + m_frame = NULL; + MEM_freeN(m_frameDeinterlaced->data[0]); + av_free(m_frameDeinterlaced); + m_frameDeinterlaced = NULL; + MEM_freeN(m_frameRGB->data[0]); + av_free(m_frameRGB); + m_frameRGB = NULL; + return -1; + } + return 0; +} + +/* + * This thread is used to load video frame asynchronously. + * It provides a frame caching service. + * The main thread is responsible for positionning the frame pointer in the + * file correctly before calling startCache() which starts this thread. + * The cache is organized in two layers: 1) a cache of 20-30 undecoded packets to keep + * memory and CPU low 2) a cache of 5 decoded frames. + * If the main thread does not find the frame in the cache (because the video has restarted + * or because the GE is lagging), it stops the cache with StopCache() (this is a synchronous + * function: it sends a signal to stop the cache thread and wait for confirmation), then + * change the position in the stream and restarts the cache thread. + */ +void *VideoFFmpeg::cacheThread(void *data) +{ + VideoFFmpeg* video = (VideoFFmpeg*)data; + // holds the frame that is being decoded + CacheFrame *currentFrame = NULL; + CachePacket *cachePacket; + bool endOfFile = false; + int frameFinished = 0; + + while (!video->m_stopThread) + { + // packet cache is used solely by this thread, no need to lock + // In case the stream/file contains other stream than the one we are looking for, + // allow a bit of cycling to get rid quickly of those frames + frameFinished = 0; + while ( !endOfFile + && (cachePacket = (CachePacket *)video->m_packetCacheFree.first) != NULL + && frameFinished < 25) + { + // free packet => packet cache is not full yet, just read more + if (av_read_frame(video->m_formatCtx, &cachePacket->packet)>=0) + { + if (cachePacket->packet.stream_index == video->m_videoStream) + { + // make sure fresh memory is allocated for the packet and move it to queue + av_dup_packet(&cachePacket->packet); + BLI_remlink(&video->m_packetCacheFree, cachePacket); + BLI_addtail(&video->m_packetCacheBase, cachePacket); + break; + } else { + // this is not a good packet for us, just leave it on free queue + // Note: here we could handle sound packet + av_free_packet(&cachePacket->packet); + frameFinished++; + } + + } else { + if (video->m_isFile) + // this mark the end of the file + endOfFile = true; + // if we cannot read a packet, no need to continue + break; + } + } + // frame cache is also used by main thread, lock + if (currentFrame == NULL) + { + // no current frame being decoded, take free one + pthread_mutex_lock(&video->m_cacheMutex); + if ((currentFrame = (CacheFrame *)video->m_frameCacheFree.first) != NULL) + BLI_remlink(&video->m_frameCacheFree, currentFrame); + pthread_mutex_unlock(&video->m_cacheMutex); + } + if (currentFrame != NULL) + { + // this frame is out of free and busy queue, we can manipulate it without locking + frameFinished = 0; + while (!frameFinished && (cachePacket = (CachePacket *)video->m_packetCacheBase.first) != NULL) + { + BLI_remlink(&video->m_packetCacheBase, cachePacket); + // use m_frame because when caching, it is not used in main thread + // we can't use currentFrame directly because we need to convert to RGB first + avcodec_decode_video(video->m_codecCtx, + video->m_frame, &frameFinished, + cachePacket->packet.data, cachePacket->packet.size); + if(frameFinished) + { + AVFrame * input = video->m_frame; + + /* This means the data wasnt read properly, this check stops crashing */ + if ( input->data[0]!=0 || input->data[1]!=0 + || input->data[2]!=0 || input->data[3]!=0) + { + if (video->m_deinterlace) + { + if (avpicture_deinterlace( + (AVPicture*) video->m_frameDeinterlaced, + (const AVPicture*) video->m_frame, + video->m_codecCtx->pix_fmt, + video->m_codecCtx->width, + video->m_codecCtx->height) >= 0) + { + input = video->m_frameDeinterlaced; + } + } + // convert to RGB24 + sws_scale(video->m_imgConvertCtx, + input->data, + input->linesize, + 0, + video->m_codecCtx->height, + currentFrame->frame->data, + currentFrame->frame->linesize); + // move frame to queue, this frame is necessarily the next one + currentFrame->framePosition = ++video->m_curPosition; + pthread_mutex_lock(&video->m_cacheMutex); + BLI_addtail(&video->m_frameCacheBase, currentFrame); + pthread_mutex_unlock(&video->m_cacheMutex); + currentFrame = NULL; + } + } + av_free_packet(&cachePacket->packet); + BLI_addtail(&video->m_packetCacheFree, cachePacket); + } + if (currentFrame && endOfFile) + { + // no more packet and end of file => put a special frame that indicates that + currentFrame->framePosition = -1; + pthread_mutex_lock(&video->m_cacheMutex); + BLI_addtail(&video->m_frameCacheBase, currentFrame); + pthread_mutex_unlock(&video->m_cacheMutex); + currentFrame = NULL; + // no need to stay any longer in this thread + break; + } + } + // small sleep to avoid unnecessary looping + PIL_sleep_ms(10); + } + // before quitting, put back the current frame to queue to allow freeing + if (currentFrame) + { + pthread_mutex_lock(&video->m_cacheMutex); + BLI_addtail(&video->m_frameCacheFree, currentFrame); + pthread_mutex_unlock(&video->m_cacheMutex); + } + return 0; +} + +// start thread to cache video frame from file/capture/stream +// this function should be called only when the position in the stream is set for the +// first frame to cache +bool VideoFFmpeg::startCache() +{ + if (!m_cacheStarted && m_isThreaded) + { + m_stopThread = false; + for (int i=0; i<CACHE_FRAME_SIZE; i++) + { + CacheFrame *frame = new CacheFrame(); + frame->frame = allocFrameRGB(); + BLI_addtail(&m_frameCacheFree, frame); + } + for (int i=0; i<CACHE_PACKET_SIZE; i++) + { + CachePacket *packet = new CachePacket(); + BLI_addtail(&m_packetCacheFree, packet); + } + BLI_init_threads(&m_thread, cacheThread, 1); + BLI_insert_thread(&m_thread, this); + m_cacheStarted = true; + } + return m_cacheStarted; +} + +void VideoFFmpeg::stopCache() +{ + if (m_cacheStarted) + { + m_stopThread = true; + BLI_end_threads(&m_thread); + // now delete the cache + CacheFrame *frame; + CachePacket *packet; + while ((frame = (CacheFrame *)m_frameCacheBase.first) != NULL) + { + BLI_remlink(&m_frameCacheBase, frame); + MEM_freeN(frame->frame->data[0]); + av_free(frame->frame); + delete frame; + } + while ((frame = (CacheFrame *)m_frameCacheFree.first) != NULL) + { + BLI_remlink(&m_frameCacheFree, frame); + MEM_freeN(frame->frame->data[0]); + av_free(frame->frame); + delete frame; + } + while((packet = (CachePacket *)m_packetCacheBase.first) != NULL) + { + BLI_remlink(&m_packetCacheBase, packet); + av_free_packet(&packet->packet); + delete packet; + } + while((packet = (CachePacket *)m_packetCacheFree.first) != NULL) + { + BLI_remlink(&m_packetCacheFree, packet); + delete packet; + } + m_cacheStarted = false; + } +} + +void VideoFFmpeg::releaseFrame(AVFrame* frame) +{ + if (frame == m_frameRGB) + { + // this is not a frame from the cache, ignore + return; + } + // this frame MUST be the first one of the queue + pthread_mutex_lock(&m_cacheMutex); + CacheFrame *cacheFrame = (CacheFrame *)m_frameCacheBase.first; + assert (cacheFrame != NULL && cacheFrame->frame == frame); + BLI_remlink(&m_frameCacheBase, cacheFrame); + BLI_addtail(&m_frameCacheFree, cacheFrame); + pthread_mutex_unlock(&m_cacheMutex); +} + +// open video file +void VideoFFmpeg::openFile (char * filename) +{ + do_init_ffmpeg(); + + if (openStream(filename, NULL, NULL) != 0) + return; + + if (m_codecCtx->gop_size) + m_preseek = (m_codecCtx->gop_size < 25) ? m_codecCtx->gop_size+1 : 25; + else if (m_codecCtx->has_b_frames) + m_preseek = 25; // should determine gopsize + else + m_preseek = 0; + + // get video time range + m_range[0] = 0.0; + m_range[1] = (double)m_formatCtx->duration / AV_TIME_BASE; + + // open base class + VideoBase::openFile(filename); + + if ( + // ffmpeg reports that http source are actually non stream + // but it is really not desirable to seek on http file, so force streaming. + // It would be good to find this information from the context but there are no simple indication + !strncmp(filename, "http://", 7) || +#ifdef FFMPEG_PB_IS_POINTER + (m_formatCtx->pb && m_formatCtx->pb->is_streamed) +#else + m_formatCtx->pb.is_streamed +#endif + ) + { + // the file is in fact a streaming source, prevent seeking + m_isFile = false; + // for streaming it is important to do non blocking read + m_formatCtx->flags |= AVFMT_FLAG_NONBLOCK; + } + + if (m_isImage) + { + // the file is to be treated as an image, i.e. load the first frame only + m_isFile = false; + // in case of reload, the filename is taken from m_imageName, no need to change it + if (m_imageName.Ptr() != filename) + m_imageName = filename; + m_preseek = 0; + m_avail = false; + play(); + } + // check if we should do multi-threading? + if (!m_isImage && BLI_system_thread_count() > 1) + { + // never thread image: there are no frame to read ahead + // no need to thread if the system has a single core + m_isThreaded = true; + } +} + + +// open video capture device +void VideoFFmpeg::openCam (char * file, short camIdx) +{ + // open camera source + AVInputFormat *inputFormat; + AVFormatParameters formatParams; + AVRational frameRate; + char *p, filename[28], rateStr[20]; + + do_init_ffmpeg(); + + memset(&formatParams, 0, sizeof(formatParams)); +#ifdef WIN32 + // video capture on windows only through Video For Windows driver + inputFormat = av_find_input_format("vfwcap"); + if (!inputFormat) + // Video For Windows not supported?? + return; + sprintf(filename, "%d", camIdx); +#else + // In Linux we support two types of devices: VideoForLinux and DV1394. + // the user specify it with the filename: + // [<device_type>][:<standard>] + // <device_type> : 'v4l' for VideoForLinux, 'dv1394' for DV1394. By default 'v4l' + // <standard> : 'pal', 'secam' or 'ntsc'. By default 'ntsc' + // The driver name is constructed automatically from the device type: + // v4l : /dev/video<camIdx> + // dv1394: /dev/dv1394/<camIdx> + // If you have different driver name, you can specify the driver name explicitely + // instead of device type. Examples of valid filename: + // /dev/v4l/video0:pal + // /dev/ieee1394/1:ntsc + // dv1394:secam + // v4l:pal + if (file && strstr(file, "1394") != NULL) + { + // the user specifies a driver, check if it is v4l or d41394 + inputFormat = av_find_input_format("dv1394"); + sprintf(filename, "/dev/dv1394/%d", camIdx); + } else + { + inputFormat = av_find_input_format("video4linux"); + sprintf(filename, "/dev/video%d", camIdx); + } + if (!inputFormat) + // these format should be supported, check ffmpeg compilation + return; + if (file && strncmp(file, "/dev", 4) == 0) + { + // user does not specify a driver + strncpy(filename, file, sizeof(filename)); + filename[sizeof(filename)-1] = 0; + if ((p = strchr(filename, ':')) != 0) + *p = 0; + } + if (file && (p = strchr(file, ':')) != NULL) + formatParams.standard = p+1; +#endif + //frame rate + if (m_captRate <= 0.f) + m_captRate = defFrameRate; + sprintf(rateStr, "%f", m_captRate); + av_parse_video_frame_rate(&frameRate, rateStr); + // populate format parameters + // need to specify the time base = inverse of rate + formatParams.time_base.num = frameRate.den; + formatParams.time_base.den = frameRate.num; + formatParams.width = m_captWidth; + formatParams.height = m_captHeight; + + if (openStream(filename, inputFormat, &formatParams) != 0) + return; + + // for video capture it is important to do non blocking read + m_formatCtx->flags |= AVFMT_FLAG_NONBLOCK; + // open base class + VideoBase::openCam(file, camIdx); + // check if we should do multi-threading? + if (BLI_system_thread_count() > 1) + { + // no need to thread if the system has a single core + m_isThreaded = true; + } +} + +// play video +bool VideoFFmpeg::play (void) +{ + try + { + // if object is able to play + if (VideoBase::play()) + { + // set video position + setPositions(); + // return success + return true; + } + } + CATCH_EXCP; + return false; +} + + +// pause video +bool VideoFFmpeg::pause (void) +{ + try + { + if (VideoBase::pause()) + { + return true; + } + } + CATCH_EXCP; + return false; +} + +// stop video +bool VideoFFmpeg::stop (void) +{ + try + { + VideoBase::stop(); + // force restart when play + m_lastFrame = -1; + return true; + } + CATCH_EXCP; + return false; +} + + +// set video range +void VideoFFmpeg::setRange (double start, double stop) +{ + try + { + // set range + if (m_isFile) + { + VideoBase::setRange(start, stop); + // set range for video + setPositions(); + } + } + CATCH_EXCP; +} + +// set framerate +void VideoFFmpeg::setFrameRate (float rate) +{ + VideoBase::setFrameRate(rate); +} + + +// image calculation +void VideoFFmpeg::calcImage (unsigned int texId) +{ + loadFrame(); +} + + +// load frame from video +void VideoFFmpeg::loadFrame (void) +{ + if (m_status == SourcePlaying) + { + // get actual time + double startTime = PIL_check_seconds_timer(); + if (m_lastFrame == -1 && !m_isFile) + m_startTime = startTime; + double actTime = startTime - m_startTime; + // if video has ended + if (m_isFile && actTime * m_frameRate >= m_range[1]) + { + // in any case, this resets the cache + stopCache(); + // if repeats are set, decrease them + if (m_repeat > 0) + --m_repeat; + // if video has to be replayed + if (m_repeat != 0) + { + // reset its position + actTime -= (m_range[1] - m_range[0]) / m_frameRate; + m_startTime += (m_range[1] - m_range[0]) / m_frameRate; + } + // if video has to be stopped, stop it + else + { + m_status = SourceStopped; + return; + } + } + // actual frame + long actFrame = (m_isImage) ? m_lastFrame+1 : long(actTime * actFrameRate()); + // if actual frame differs from last frame + if (actFrame != m_lastFrame) + { + AVFrame* frame; + // get image + if((frame = grabFrame(actFrame)) != NULL) + { + if (!m_isFile && !m_cacheStarted) + { + // streaming without cache: detect synchronization problem + double execTime = PIL_check_seconds_timer() - startTime; + if (execTime > 0.005) + { + // exec time is too long, it means that the function was blocking + // resynchronize the stream from this time + m_startTime += execTime; + } + } + // save actual frame + m_lastFrame = actFrame; + // init image, if needed + init(short(m_codecCtx->width), short(m_codecCtx->height)); + // process image + process((BYTE*)(frame->data[0])); + // finished with the frame, release it so that cache can reuse it + releaseFrame(frame); + // in case it is an image, automatically stop reading it + if (m_isImage) + { + m_status = SourceStopped; + // close the file as we don't need it anymore + release(); + } + } else if (!m_isFile) + { + // we didn't get a frame and we are streaming, this may be due to + // a delay in the network or because we are getting the frame too fast. + // In the later case, shift time by a small amount to compensate for a drift + m_startTime += 0.01; + } + } + } +} + + +// set actual position +void VideoFFmpeg::setPositions (void) +{ + // set video start time + m_startTime = PIL_check_seconds_timer(); + // if file is played and actual position is before end position + if (!m_eof && m_lastFrame >= 0 && (!m_isFile || m_lastFrame < m_range[1] * actFrameRate())) + // continue from actual position + m_startTime -= double(m_lastFrame) / actFrameRate(); + else { + m_startTime -= m_range[0]; + // start from begining, stop cache just in case + stopCache(); + } +} + +// position pointer in file, position in second +AVFrame *VideoFFmpeg::grabFrame(long position) +{ + AVPacket packet; + int frameFinished; + int posFound = 1; + bool frameLoaded = false; + long long targetTs = 0; + CacheFrame *frame; + + if (m_cacheStarted) + { + // when cache is active, we must not read the file directly + do { + pthread_mutex_lock(&m_cacheMutex); + frame = (CacheFrame *)m_frameCacheBase.first; + pthread_mutex_unlock(&m_cacheMutex); + // no need to remove the frame from the queue: the cache thread does not touch the head, only the tail + if (frame == NULL) + { + // no frame in cache, in case of file it is an abnormal situation + if (m_isFile) + { + // go back to no threaded reading + stopCache(); + break; + } + return NULL; + } + if (frame->framePosition == -1) + { + // this frame mark the end of the file (only used for file) + // leave in cache to make sure we don't miss it + m_eof = true; + return NULL; + } + // for streaming, always return the next frame, + // that's what grabFrame does in non cache mode anyway. + if (!m_isFile || frame->framePosition == position) + { + return frame->frame; + } + // this frame is not useful, release it + pthread_mutex_lock(&m_cacheMutex); + BLI_remlink(&m_frameCacheBase, frame); + BLI_addtail(&m_frameCacheFree, frame); + pthread_mutex_unlock(&m_cacheMutex); + } while (true); + } + // come here when there is no cache or cache has been stopped + // locate the frame, by seeking if necessary (seeking is only possible for files) + if (m_isFile) + { + // first check if the position that we are looking for is in the preseek range + // if so, just read the frame until we get there + if (position > m_curPosition + 1 + && m_preseek + && position - (m_curPosition + 1) < m_preseek) + { + while(av_read_frame(m_formatCtx, &packet)>=0) + { + if (packet.stream_index == m_videoStream) + { + avcodec_decode_video( + m_codecCtx, + m_frame, &frameFinished, + packet.data, packet.size); + if (frameFinished) + m_curPosition++; + } + av_free_packet(&packet); + if (position == m_curPosition+1) + break; + } + } + // if the position is not in preseek, do a direct jump + if (position != m_curPosition + 1) + { + double timeBase = av_q2d(m_formatCtx->streams[m_videoStream]->time_base); + int64_t pos = (int64_t)((position - m_preseek) / (m_baseFrameRate*timeBase)); + int64_t startTs = m_formatCtx->streams[m_videoStream]->start_time; + int seekres; + + if (pos < 0) + pos = 0; + + if (startTs != AV_NOPTS_VALUE) + pos += startTs; + + if (position <= m_curPosition || !m_eof) + { +#if 0 + // Tried to make this work but couldn't: seeking on byte is ignored by the + // format plugin and it will generally continue to read from last timestamp. + // Too bad because frame seek is not always able to get the first frame + // of the file. + if (position <= m_preseek) + { + // we can safely go the begining of the file + if (av_seek_frame(m_formatCtx, m_videoStream, 0, AVSEEK_FLAG_BYTE) >= 0) + { + // binary seek does not reset the timestamp, must do it now + av_update_cur_dts(m_formatCtx, m_formatCtx->streams[m_videoStream], startTs); + m_curPosition = 0; + } + } + else +#endif + { + // current position is now lost, guess a value. + if (av_seek_frame(m_formatCtx, m_videoStream, pos, AVSEEK_FLAG_BACKWARD) >= 0) + { + // current position is now lost, guess a value. + // It's not important because it will be set at this end of this function + m_curPosition = position - m_preseek - 1; + } + } + } + // this is the timestamp of the frame we're looking for + targetTs = (int64_t)(position / (m_baseFrameRate * timeBase)); + if (startTs != AV_NOPTS_VALUE) + targetTs += startTs; + + posFound = 0; + avcodec_flush_buffers(m_codecCtx); + } + } else if (m_isThreaded) + { + // cache is not started but threading is possible + // better not read the stream => make take some time, better start caching + if (startCache()) + return NULL; + // Abnormal!!! could not start cache, fall back on direct read + m_isThreaded = false; + } + + // find the correct frame, in case of streaming and no cache, it means just + // return the next frame. This is not quite correct, may need more work + while(av_read_frame(m_formatCtx, &packet)>=0) + { + if(packet.stream_index == m_videoStream) + { + avcodec_decode_video(m_codecCtx, + m_frame, &frameFinished, + packet.data, packet.size); + + if (frameFinished && !posFound) + { + if (packet.dts >= targetTs) + posFound = 1; + } + + if(frameFinished && posFound == 1) + { + AVFrame * input = m_frame; + + /* This means the data wasnt read properly, + this check stops crashing */ + if ( input->data[0]==0 && input->data[1]==0 + && input->data[2]==0 && input->data[3]==0) + { + av_free_packet(&packet); + break; + } + + if (m_deinterlace) + { + if (avpicture_deinterlace( + (AVPicture*) m_frameDeinterlaced, + (const AVPicture*) m_frame, + m_codecCtx->pix_fmt, + m_codecCtx->width, + m_codecCtx->height) >= 0) + { + input = m_frameDeinterlaced; + } + } + // convert to RGB24 + sws_scale(m_imgConvertCtx, + input->data, + input->linesize, + 0, + m_codecCtx->height, + m_frameRGB->data, + m_frameRGB->linesize); + av_free_packet(&packet); + frameLoaded = true; + break; + } + } + av_free_packet(&packet); + } + m_eof = m_isFile && !frameLoaded; + if (frameLoaded) + { + m_curPosition = position; + if (m_isThreaded) + { + // normal case for file: first locate, then start cache + if (!startCache()) + { + // Abnormal!! could not start cache, return to non-cache mode + m_isThreaded = false; + } + } + return m_frameRGB; + } + return NULL; +} + + +// python methods + + +// cast Image pointer to VideoFFmpeg +inline VideoFFmpeg * getVideoFFmpeg (PyImage * self) +{ return static_cast<VideoFFmpeg*>(self->m_image); } + + +// object initialization +static int VideoFFmpeg_init (PyObject * pySelf, PyObject * args, PyObject * kwds) +{ + PyImage * self = reinterpret_cast<PyImage*>(pySelf); + // parameters - video source + // file name or format type for capture (only for Linux: video4linux or dv1394) + char * file = NULL; + // capture device number + short capt = -1; + // capture width, only if capt is >= 0 + short width = 0; + // capture height, only if capt is >= 0 + short height = 0; + // capture rate, only if capt is >= 0 + float rate = 25.f; + + static char *kwlist[] = {"file", "capture", "rate", "width", "height", NULL}; + + // get parameters + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|hfhh", kwlist, &file, &capt, + &rate, &width, &height)) + return -1; + + try + { + // create video object + Video_init<VideoFFmpeg>(self); + + // set thread usage + getVideoFFmpeg(self)->initParams(width, height, rate); + + // open video source + Video_open(getVideo(self), file, capt); + } + catch (Exception & exp) + { + exp.report(); + return -1; + } + // initialization succeded + return 0; +} + +PyObject * VideoFFmpeg_getPreseek (PyImage *self, void * closure) +{ + return Py_BuildValue("h", getFFmpeg(self)->getPreseek()); +} + +// set range +int VideoFFmpeg_setPreseek (PyImage * self, PyObject * value, void * closure) +{ + // check validity of parameter + if (value == NULL || !PyLong_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "The value must be an integer"); + return -1; + } + // set preseek + getFFmpeg(self)->setPreseek(PyLong_AsSsize_t(value)); + // success + return 0; +} + +// get deinterlace +PyObject * VideoFFmpeg_getDeinterlace (PyImage * self, void * closure) +{ + if (getFFmpeg(self)->getDeinterlace()) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +// set flip +int VideoFFmpeg_setDeinterlace (PyImage * self, PyObject * value, void * closure) +{ + // check parameter, report failure + if (value == NULL || !PyBool_Check(value)) + { + PyErr_SetString(PyExc_TypeError, "The value must be a bool"); + return -1; + } + // set deinterlace + getFFmpeg(self)->setDeinterlace(value == Py_True); + // success + return 0; +} + +// methods structure +static PyMethodDef videoMethods[] = +{ // methods from VideoBase class + {"play", (PyCFunction)Video_play, METH_NOARGS, "Play (restart) video"}, + {"pause", (PyCFunction)Video_pause, METH_NOARGS, "pause video"}, + {"stop", (PyCFunction)Video_stop, METH_NOARGS, "stop video (play will replay it from start)"}, + {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh video - get its status"}, + {NULL} +}; +// attributes structure +static PyGetSetDef videoGetSets[] = +{ // methods from VideoBase class + {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL}, + {(char*)"range", (getter)Video_getRange, (setter)Video_setRange, (char*)"replay range", NULL}, + {(char*)"repeat", (getter)Video_getRepeat, (setter)Video_setRepeat, (char*)"repeat count, -1 for infinite repeat", NULL}, + {(char*)"framerate", (getter)Video_getFrameRate, (setter)Video_setFrameRate, (char*)"frame rate", NULL}, + // attributes from ImageBase class + {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, + {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, + {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL}, + {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, + {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, + {(char*)"preseek", (getter)VideoFFmpeg_getPreseek, (setter)VideoFFmpeg_setPreseek, (char*)"nb of frames of preseek", NULL}, + {(char*)"deinterlace", (getter)VideoFFmpeg_getDeinterlace, (setter)VideoFFmpeg_setDeinterlace, (char*)"deinterlace image", NULL}, + {NULL} +}; + +// python type declaration +PyTypeObject VideoFFmpegType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.VideoFFmpeg", /*tp_name*/ + sizeof(PyImage), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Image_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "FFmpeg video source", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + videoMethods, /* tp_methods */ + 0, /* tp_members */ + videoGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)VideoFFmpeg_init, /* tp_init */ + 0, /* tp_alloc */ + Image_allocNew, /* tp_new */ +}; + +// object initialization +static int ImageFFmpeg_init (PyObject * pySelf, PyObject * args, PyObject * kwds) +{ + PyImage * self = reinterpret_cast<PyImage*>(pySelf); + // parameters - video source + // file name or format type for capture (only for Linux: video4linux or dv1394) + char * file = NULL; + + // get parameters + if (!PyArg_ParseTuple(args, "s:ImageFFmpeg", &file)) + return -1; + + try + { + // create video object + Video_init<VideoFFmpeg>(self); + + getVideoFFmpeg(self)->initParams(0, 0, 1.0, true); + + // open video source + Video_open(getVideo(self), file, -1); + } + catch (Exception & exp) + { + exp.report(); + return -1; + } + // initialization succeded + return 0; +} + +PyObject * Image_reload (PyImage * self, PyObject *args) +{ + char * newname = NULL; + if (!PyArg_ParseTuple(args, "|s:reload", &newname)) + return NULL; + if (self->m_image != NULL) + { + VideoFFmpeg* video = getFFmpeg(self); + // check type of object + if (!newname) + newname = video->getImageName(); + if (!newname) { + // if not set, retport error + PyErr_SetString(PyExc_RuntimeError, "No image file name given"); + return NULL; + } + // make sure the previous file is cleared + video->release(); + // open the new file + video->openFile(newname); + } + Py_RETURN_NONE; +} + +// methods structure +static PyMethodDef imageMethods[] = +{ // methods from VideoBase class + {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh image, i.e. load it"}, + {"reload", (PyCFunction)Image_reload, METH_VARARGS, "Reload image, i.e. reopen it"}, + {NULL} +}; +// attributes structure +static PyGetSetDef imageGetSets[] = +{ // methods from VideoBase class + {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL}, + // attributes from ImageBase class + {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL}, + {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL}, + {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL}, + {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL}, + {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL}, + {NULL} +}; + +// python type declaration +PyTypeObject ImageFFmpegType = +{ + PyVarObject_HEAD_INIT(NULL, 0) + "VideoTexture.ImageFFmpeg", /*tp_name*/ + sizeof(PyImage), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Image_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "FFmpeg image source", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + imageMethods, /* tp_methods */ + 0, /* tp_members */ + imageGetSets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)ImageFFmpeg_init, /* tp_init */ + 0, /* tp_alloc */ + Image_allocNew, /* tp_new */ +}; + +#endif //WITH_FFMPEG + + diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.h b/source/gameengine/VideoTexture/VideoFFmpeg.h new file mode 100644 index 00000000000..fbd04e7e1fc --- /dev/null +++ b/source/gameengine/VideoTexture/VideoFFmpeg.h @@ -0,0 +1,210 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2007 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ +#if !defined VIDEOFFMPEG_H +#define VIDEOFFMPEG_H + +#ifdef WITH_FFMPEG +extern "C" { +#include <pthread.h> +#include <libavformat/avformat.h> +#include <libavcodec/avcodec.h> +#include <libavutil/rational.h> +#include <libswscale/swscale.h> +#include "DNA_listBase.h" +#include "BLI_threads.h" +#include "BLI_blenlib.h" +} + + +#if LIBAVFORMAT_VERSION_INT < (49 << 16) +#define FFMPEG_OLD_FRAME_RATE 1 +#else +#define FFMPEG_CODEC_IS_POINTER 1 +#endif + +#if LIBAVFORMAT_VERSION_INT >= (52 << 16) +#define FFMPEG_PB_IS_POINTER 1 +#endif + +#ifdef FFMPEG_CODEC_IS_POINTER +static inline AVCodecContext* get_codec_from_stream(AVStream* stream) +{ + return stream->codec; +} +#else +static inline AVCodecContext* get_codec_from_stream(AVStream* stream) +{ + return &stream->codec; +} +#endif + +#include "VideoBase.h" + +#define CACHE_FRAME_SIZE 5 +#define CACHE_PACKET_SIZE 30 + +// type VideoFFmpeg declaration +class VideoFFmpeg : public VideoBase +{ +public: + /// constructor + VideoFFmpeg (HRESULT * hRslt); + /// destructor + virtual ~VideoFFmpeg (); + + /// set initial parameters + void initParams (short width, short height, float rate, bool image=false); + /// open video/image file + virtual void openFile (char * file); + /// open video capture device + virtual void openCam (char * driver, short camIdx); + + /// release video source + virtual bool release (void); + + /// play video + virtual bool play (void); + /// pause video + virtual bool pause (void); + /// stop video + virtual bool stop (void); + /// set play range + virtual void setRange (double start, double stop); + /// set frame rate + virtual void setFrameRate (float rate); + // some specific getters and setters + int getPreseek(void) { return m_preseek; } + void setPreseek(int preseek) { if (preseek >= 0) m_preseek = preseek; } + bool getDeinterlace(void) { return m_deinterlace; } + void setDeinterlace(bool deinterlace) { m_deinterlace = deinterlace; } + char *getImageName(void) { return (m_isImage) ? m_imageName.Ptr() : NULL; } + +protected: + // format and codec information + AVCodec *m_codec; + AVFormatContext *m_formatCtx; + AVCodecContext *m_codecCtx; + // raw frame extracted from video file + AVFrame *m_frame; + // deinterlaced frame if codec requires it + AVFrame *m_frameDeinterlaced; + // decoded RGB24 frame if codec requires it + AVFrame *m_frameRGB; + // conversion from raw to RGB is done with sws_scale + struct SwsContext *m_imgConvertCtx; + // should the codec be deinterlaced? + bool m_deinterlace; + // number of frame of preseek + int m_preseek; + // order number of stream holding the video in format context + int m_videoStream; + + // the actual frame rate + double m_baseFrameRate; + + /// last displayed frame + long m_lastFrame; + + /// end of file reached + bool m_eof; + + /// current file pointer position in file expressed in frame number + long m_curPosition; + + /// time of video play start + double m_startTime; + + /// width of capture in pixel + short m_captWidth; + + /// height of capture in pixel + short m_captHeight; + + /// frame rate of capture in frames per seconds + float m_captRate; + + /// is file an image? + bool m_isImage; + + /// is image loading done in a separate thread? + bool m_isThreaded; + + /// keep last image name + STR_String m_imageName; + + /// image calculation + virtual void calcImage (unsigned int texId); + + /// load frame from video + void loadFrame (void); + + /// set actual position + void setPositions (void); + + /// get actual framerate + double actFrameRate (void) { return m_frameRate * m_baseFrameRate; } + + /// common function to video file and capture + int openStream(const char *filename, AVInputFormat *inputFormat, AVFormatParameters *formatParams); + + /// check if a frame is available and load it in pFrame, return true if a frame could be retrieved + AVFrame* grabFrame(long frame); + + /// in case of caching, put the frame back in free queue + void releaseFrame(AVFrame* frame); + + /// start thread to load the video file/capture/stream + bool startCache(); + void stopCache(); + +private: + typedef struct { + Link link; + long framePosition; + AVFrame *frame; + } CacheFrame; + typedef struct { + Link link; + AVPacket packet; + } CachePacket; + + bool m_stopThread; + bool m_cacheStarted; + ListBase m_thread; + ListBase m_frameCacheBase; // list of frames that are ready + ListBase m_frameCacheFree; // list of frames that are unused + ListBase m_packetCacheBase; // list of packets that are ready for decoding + ListBase m_packetCacheFree; // list of packets that are unused + pthread_mutex_t m_cacheMutex; + + AVFrame *allocFrameRGB(); + static void *cacheThread(void *); +}; + +inline VideoFFmpeg * getFFmpeg (PyImage * self) +{ + return static_cast<VideoFFmpeg*>(self->m_image); +} + +#endif //WITH_FFMPEG + +#endif diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp new file mode 100644 index 00000000000..998d63506b0 --- /dev/null +++ b/source/gameengine/VideoTexture/blendVideoTex.cpp @@ -0,0 +1,222 @@ +/* $Id$ +----------------------------------------------------------------------------- +This source file is part of VideoTexture library + +Copyright (c) 2006 The Zdeno Ash Miklas + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA, or go to +http://www.gnu.org/copyleft/lesser.txt. +----------------------------------------------------------------------------- +*/ + +#include <PyObjectPlus.h> + +#include <RAS_GLExtensionManager.h> + +#include <RAS_IPolygonMaterial.h> + +//Old API +//#include "TexPlayer.h" +//#include "TexImage.h" +//#include "TexFrameBuff.h" + +//#include "TexPlayerGL.h" + +#include "ImageBase.h" +#include "FilterBase.h" +#include "Texture.h" + +#include "Exception.h" + + +// get material id +static PyObject * getMaterialID (PyObject *self, PyObject *args) +{ + // parameters - game object with video texture + PyObject * obj = NULL; + // material name + char * matName; + + // get parameters + if (!PyArg_ParseTuple(args, "Os:materialID", &obj, &matName)) + return NULL; + // get material id + short matID = getMaterialID(obj, matName); + // if material was not found, report errot + if (matID < 0) + { + PyErr_SetString(PyExc_RuntimeError, "VideoTexture.materialID(ob, string): Object doesn't have material with given name"); + return NULL; + } + // return material ID + return Py_BuildValue("h", matID); +} + + +// get last error description +static PyObject * getLastError (PyObject *self, PyObject *args) +{ + return PyUnicode_FromString(Exception::m_lastError.c_str()); +} + +// set log file +static PyObject * setLogFile (PyObject *self, PyObject *args) +{ + // get parameters + if (!PyArg_ParseTuple(args, "s:setLogFile", &Exception::m_logFile)) + return Py_BuildValue("i", -1); + // log file was loaded + return Py_BuildValue("i", 0); +} + + +// image to numpy array +static PyObject * imageToArray (PyObject * self, PyObject *args) +{ + // parameter is Image object + PyObject * pyImg; + if (!PyArg_ParseTuple(args, "O:imageToArray", &pyImg) || !pyImageTypes.in(pyImg->ob_type)) + { + // if object is incorect, report error + PyErr_SetString(PyExc_TypeError, "VideoTexture.imageToArray(image): The value must be a image source object"); + return NULL; + } + // get image structure + PyImage * img = reinterpret_cast<PyImage*>(pyImg); + // create array object + unsigned int * imgBuff = img->m_image->getImage(); + // if image is available, convert it to array + if (imgBuff != NULL) + // Nasty problem here: the image buffer is an array of integers + // in the processor endian format. The user must take care of that in the script. + // Need to find an elegant solution to this problem + return Py_BuildValue("s#", imgBuff, img->m_image->getBuffSize()); + // otherwise return None + Py_RETURN_NONE; +} + + +// metody modulu +static PyMethodDef moduleMethods[] = +{ + {"materialID", getMaterialID, METH_VARARGS, "Gets object's Blender Material ID"}, + {"getLastError", getLastError, METH_NOARGS, "Gets last error description"}, + {"setLogFile", setLogFile, METH_VARARGS, "Sets log file name"}, + {"imageToArray", imageToArray, METH_VARARGS, "get array from image source"}, + {NULL} /* Sentinel */ +}; + +#if WITH_FFMPEG +extern PyTypeObject VideoFFmpegType; +extern PyTypeObject ImageFFmpegType; +#endif +extern PyTypeObject FilterBlueScreenType; +extern PyTypeObject FilterGrayType; +extern PyTypeObject FilterColorType; +extern PyTypeObject FilterLevelType; +extern PyTypeObject FilterNormalType; +extern PyTypeObject FilterRGB24Type; +extern PyTypeObject FilterRGBA32Type; +extern PyTypeObject FilterBGR24Type; +extern PyTypeObject ImageBuffType; +extern PyTypeObject ImageMixType; +extern PyTypeObject ImageRenderType; +extern PyTypeObject ImageMirrorType; +extern PyTypeObject ImageViewportType; +extern PyTypeObject ImageViewportType; + + +static void registerAllTypes(void) +{ +#if WITH_FFMPEG + pyImageTypes.add(&VideoFFmpegType, "VideoFFmpeg"); + pyImageTypes.add(&ImageFFmpegType, "ImageFFmpeg"); +#endif + pyImageTypes.add(&ImageBuffType, "ImageBuff"); + pyImageTypes.add(&ImageMixType, "ImageMix"); + pyImageTypes.add(&ImageRenderType, "ImageRender"); + pyImageTypes.add(&ImageMirrorType, "ImageMirror"); + pyImageTypes.add(&ImageViewportType, "ImageViewport"); + + pyFilterTypes.add(&FilterBlueScreenType, "FilterBlueScreen"); + pyFilterTypes.add(&FilterGrayType, "FilterGray"); + pyFilterTypes.add(&FilterColorType, "FilterColor"); + pyFilterTypes.add(&FilterLevelType, "FilterLevel"); + pyFilterTypes.add(&FilterNormalType, "FilterNormal"); + pyFilterTypes.add(&FilterRGB24Type, "FilterRGB24"); + pyFilterTypes.add(&FilterRGBA32Type, "FilterRGBA32"); + pyFilterTypes.add(&FilterBGR24Type, "FilterBGR24"); +} + +static struct PyModuleDef VideoTexture_module_def = { + {}, /* m_base */ + "VideoTexture", /* m_name */ + "Module that allows to play video files on textures in GameBlender.", /* m_doc */ + 0, /* m_size */ + moduleMethods, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; + +PyObject* initVideoTexture(void) +{ + PyObject * m; + + // initialize GL extensions + //bgl::InitExtensions(0); + + // prepare classes + registerAllTypes(); + registerAllExceptions(); + + if (!pyImageTypes.ready()) + return NULL; + if (!pyFilterTypes.ready()) + return NULL; + if (PyType_Ready(&TextureType) < 0) + return NULL; + + /* Use existing module where possible + * be careful not to init any runtime vars after this */ + m = PyImport_ImportModule( "VideoTexture" ); + if(m) { + Py_DECREF(m); + return m; + } + else { + PyErr_Clear(); + + m = PyModule_Create(&VideoTexture_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), VideoTexture_module_def.m_name, m); + } + + if (m == NULL) + return NULL; + + // initialize classes + pyImageTypes.reg(m); + pyFilterTypes.reg(m); + + Py_INCREF(&TextureType); + PyModule_AddObject(m, (char*)"Texture", (PyObject*)&TextureType); + + // init last error description + Exception::m_lastError[0] = '\0'; + + return m; +} + +// registration to Image types, put here because of silly linker bug |