diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2011-09-15 17:02:37 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2011-09-15 17:02:37 +0400 |
commit | 30293dc2ca8052ad0c7113c77365feca590f4d05 (patch) | |
tree | c5f4a092be7204ef2107792c0a16c0d9f331dbba /source/gameengine | |
parent | e715a7185ca176c8a73cd638d4acaa40f75a7d77 (diff) | |
parent | 9648c6016b35a72aa23395f5d200e342df16490b (diff) |
svn merge -r39834:40222 https://svn.blender.org/svnroot/bf-blender/trunk/blender
Diffstat (limited to 'source/gameengine')
73 files changed, 3534 insertions, 547 deletions
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index 40f1701e44a..ce542671425 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -169,6 +169,11 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c int disableVBO = (U.gameflags & USER_DISABLE_VBO); U.gameflags |= USER_DISABLE_VBO; + // Globals to be carried on over blender files + GlobalSettings gs; + gs.matmode= startscene->gm.matmode; + gs.glslflag= startscene->gm.flag; + do { View3D *v3d= CTX_wm_view3d(C); @@ -239,6 +244,9 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c ketsjiengine->SetTimingDisplay(frameRate, profile, properties); ketsjiengine->SetRestrictAnimationFPS(restrictAnimFPS); + //set the global settings (carried over if restart/load new files) + ketsjiengine->SetGlobalSettings(&gs); + #ifdef WITH_PYTHON CValue::SetDeprecationWarnings(nodepwarnings); #endif @@ -370,12 +378,12 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c if(GPU_glsl_support()) useglslmat = true; - else if(scene->gm.matmode == GAME_MAT_GLSL) + else if(gs.matmode == GAME_MAT_GLSL) usemat = false; - if(usemat && (scene->gm.matmode != GAME_MAT_TEXFACE)) + if(usemat && (gs.matmode != GAME_MAT_TEXFACE)) sceneconverter->SetMaterials(true); - if(useglslmat && (scene->gm.matmode == GAME_MAT_GLSL)) + if(useglslmat && (gs.matmode == GAME_MAT_GLSL)) sceneconverter->SetGLSLMaterials(true); KX_Scene* startscene = new KX_Scene(keyboarddevice, @@ -494,6 +502,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c } printf("Blender Game Engine Finished\n"); exitstring = ketsjiengine->GetExitString(); + gs = *(ketsjiengine->GetGlobalSettings()); // when exiting the mainloop @@ -507,9 +516,10 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c //PyDict_Clear(PyModule_GetDict(gameLogic)); // Keep original items, means python plugins will autocomplete members - int listIndex; PyObject *gameLogic_keys_new = PyDict_Keys(PyModule_GetDict(gameLogic)); - for (listIndex=0; listIndex < PyList_Size(gameLogic_keys_new); listIndex++) { + const Py_ssize_t numitems= PyList_GET_SIZE(gameLogic_keys_new); + Py_ssize_t listIndex; + for (listIndex=0; listIndex < numitems; listIndex++) { PyObject* item = PyList_GET_ITEM(gameLogic_keys_new, listIndex); if (!PySequence_Contains(gameLogic_keys, item)) { PyDict_DelItem( PyModule_GetDict(gameLogic), item); diff --git a/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h b/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h index 67a2279d824..7e9a57a0fe7 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h @@ -51,197 +51,195 @@ /** Base Class for Blender specific inputdevices. Blender specific inputdevices are used when the gameengine is running in embedded mode instead of standalone mode. */ -class BL_BlenderInputDevice : public SCA_IInputDevice +class BL_BlenderInputDevice : public SCA_IInputDevice { // this map is Blender specific: a conversion between blender and ketsji enums std::map<int,KX_EnumInputs> m_reverseKeyTranslateTable; public: - BL_BlenderInputDevice() - { - - /* The reverse table. In order to not confuse ourselves, we */ - /* immediately convert all events that come in to KX codes. */ - m_reverseKeyTranslateTable[LEFTMOUSE ] = KX_LEFTMOUSE ; - m_reverseKeyTranslateTable[MIDDLEMOUSE ] = KX_MIDDLEMOUSE ; - m_reverseKeyTranslateTable[RIGHTMOUSE ] = KX_RIGHTMOUSE ; - m_reverseKeyTranslateTable[WHEELUPMOUSE ] = KX_WHEELUPMOUSE ; - m_reverseKeyTranslateTable[WHEELDOWNMOUSE ] = KX_WHEELDOWNMOUSE ; - m_reverseKeyTranslateTable[MOUSEX ] = KX_MOUSEX ; - m_reverseKeyTranslateTable[MOUSEY ] = KX_MOUSEY ; - - // TIMERS - - m_reverseKeyTranslateTable[TIMER0 ] = KX_TIMER0 ; - m_reverseKeyTranslateTable[TIMER1 ] = KX_TIMER1 ; - m_reverseKeyTranslateTable[TIMER2 ] = KX_TIMER2 ; - - // SYSTEM -#if 0 - /* **** XXX **** */ - m_reverseKeyTranslateTable[KEYBD ] = KX_KEYBD ; - m_reverseKeyTranslateTable[RAWKEYBD ] = KX_RAWKEYBD ; - m_reverseKeyTranslateTable[REDRAW ] = KX_REDRAW ; - m_reverseKeyTranslateTable[INPUTCHANGE ] = KX_INPUTCHANGE ; - m_reverseKeyTranslateTable[QFULL ] = KX_QFULL ; - m_reverseKeyTranslateTable[WINFREEZE ] = KX_WINFREEZE ; - m_reverseKeyTranslateTable[WINTHAW ] = KX_WINTHAW ; - 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 ; - m_reverseKeyTranslateTable[BKEY ] = KX_BKEY ; - m_reverseKeyTranslateTable[CKEY ] = KX_CKEY ; - m_reverseKeyTranslateTable[DKEY ] = KX_DKEY ; - m_reverseKeyTranslateTable[EKEY ] = KX_EKEY ; - m_reverseKeyTranslateTable[FKEY ] = KX_FKEY ; - m_reverseKeyTranslateTable[GKEY ] = KX_GKEY ; -//XXX clean up + BL_BlenderInputDevice() + { + + /* The reverse table. In order to not confuse ourselves, we */ + /* immediately convert all events that come in to KX codes. */ + m_reverseKeyTranslateTable[LEFTMOUSE ] = KX_LEFTMOUSE; + m_reverseKeyTranslateTable[MIDDLEMOUSE ] = KX_MIDDLEMOUSE; + m_reverseKeyTranslateTable[RIGHTMOUSE ] = KX_RIGHTMOUSE; + m_reverseKeyTranslateTable[WHEELUPMOUSE ] = KX_WHEELUPMOUSE; + m_reverseKeyTranslateTable[WHEELDOWNMOUSE ] = KX_WHEELDOWNMOUSE; + m_reverseKeyTranslateTable[MOUSEX ] = KX_MOUSEX; + m_reverseKeyTranslateTable[MOUSEY ] = KX_MOUSEY; + + // TIMERS + + m_reverseKeyTranslateTable[TIMER0 ] = KX_TIMER0; + m_reverseKeyTranslateTable[TIMER1 ] = KX_TIMER1; + m_reverseKeyTranslateTable[TIMER2 ] = KX_TIMER2; + + // SYSTEM +#if 0 + /* **** XXX **** */ + m_reverseKeyTranslateTable[KEYBD ] = KX_KEYBD; + m_reverseKeyTranslateTable[RAWKEYBD ] = KX_RAWKEYBD; + m_reverseKeyTranslateTable[REDRAW ] = KX_REDRAW; + m_reverseKeyTranslateTable[INPUTCHANGE ] = KX_INPUTCHANGE; + m_reverseKeyTranslateTable[QFULL ] = KX_QFULL; + m_reverseKeyTranslateTable[WINFREEZE ] = KX_WINFREEZE; + m_reverseKeyTranslateTable[WINTHAW ] = KX_WINTHAW; + 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; + m_reverseKeyTranslateTable[BKEY ] = KX_BKEY; + m_reverseKeyTranslateTable[CKEY ] = KX_CKEY; + m_reverseKeyTranslateTable[DKEY ] = KX_DKEY; + 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 + 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 ; - m_reverseKeyTranslateTable[LKEY ] = KX_LKEY ; - m_reverseKeyTranslateTable[MKEY ] = KX_MKEY ; - m_reverseKeyTranslateTable[NKEY ] = KX_NKEY ; - m_reverseKeyTranslateTable[OKEY ] = KX_OKEY ; - m_reverseKeyTranslateTable[PKEY ] = KX_PKEY ; - m_reverseKeyTranslateTable[QKEY ] = KX_QKEY ; - m_reverseKeyTranslateTable[RKEY ] = KX_RKEY ; - m_reverseKeyTranslateTable[SKEY ] = KX_SKEY ; - m_reverseKeyTranslateTable[TKEY ] = KX_TKEY ; - m_reverseKeyTranslateTable[UKEY ] = KX_UKEY ; - m_reverseKeyTranslateTable[VKEY ] = KX_VKEY ; - m_reverseKeyTranslateTable[WKEY ] = KX_WKEY ; - m_reverseKeyTranslateTable[XKEY ] = KX_XKEY ; - m_reverseKeyTranslateTable[YKEY ] = KX_YKEY ; - m_reverseKeyTranslateTable[ZKEY ] = KX_ZKEY ; - - m_reverseKeyTranslateTable[ZEROKEY ] = KX_ZEROKEY ; - m_reverseKeyTranslateTable[ONEKEY ] = KX_ONEKEY ; - m_reverseKeyTranslateTable[TWOKEY ] = KX_TWOKEY ; - m_reverseKeyTranslateTable[THREEKEY ] = KX_THREEKEY ; - m_reverseKeyTranslateTable[FOURKEY ] = KX_FOURKEY ; - m_reverseKeyTranslateTable[FIVEKEY ] = KX_FIVEKEY ; - m_reverseKeyTranslateTable[SIXKEY ] = KX_SIXKEY ; - m_reverseKeyTranslateTable[SEVENKEY ] = KX_SEVENKEY ; - m_reverseKeyTranslateTable[EIGHTKEY ] = KX_EIGHTKEY ; - m_reverseKeyTranslateTable[NINEKEY ] = KX_NINEKEY ; - - m_reverseKeyTranslateTable[CAPSLOCKKEY ] = KX_CAPSLOCKKEY ; - - m_reverseKeyTranslateTable[LEFTCTRLKEY ] = KX_LEFTCTRLKEY ; - m_reverseKeyTranslateTable[LEFTALTKEY ] = KX_LEFTALTKEY ; - m_reverseKeyTranslateTable[RIGHTALTKEY ] = KX_RIGHTALTKEY ; - m_reverseKeyTranslateTable[RIGHTCTRLKEY ] = KX_RIGHTCTRLKEY ; - m_reverseKeyTranslateTable[RIGHTSHIFTKEY ] = KX_RIGHTSHIFTKEY ; - m_reverseKeyTranslateTable[LEFTSHIFTKEY ] = KX_LEFTSHIFTKEY ; - - m_reverseKeyTranslateTable[ESCKEY ] = KX_ESCKEY ; - m_reverseKeyTranslateTable[TABKEY ] = KX_TABKEY ; - m_reverseKeyTranslateTable[RETKEY ] = KX_RETKEY ; - m_reverseKeyTranslateTable[SPACEKEY ] = KX_SPACEKEY ; - m_reverseKeyTranslateTable[LINEFEEDKEY ] = KX_LINEFEEDKEY ; - m_reverseKeyTranslateTable[BACKSPACEKEY ] = KX_BACKSPACEKEY ; - m_reverseKeyTranslateTable[DELKEY ] = KX_DELKEY ; - m_reverseKeyTranslateTable[SEMICOLONKEY ] = KX_SEMICOLONKEY ; - m_reverseKeyTranslateTable[PERIODKEY ] = KX_PERIODKEY ; - m_reverseKeyTranslateTable[COMMAKEY ] = KX_COMMAKEY ; - m_reverseKeyTranslateTable[QUOTEKEY ] = KX_QUOTEKEY ; - m_reverseKeyTranslateTable[ACCENTGRAVEKEY ] = KX_ACCENTGRAVEKEY ; - m_reverseKeyTranslateTable[MINUSKEY ] = KX_MINUSKEY ; - m_reverseKeyTranslateTable[SLASHKEY ] = KX_SLASHKEY ; - m_reverseKeyTranslateTable[BACKSLASHKEY ] = KX_BACKSLASHKEY ; - m_reverseKeyTranslateTable[EQUALKEY ] = KX_EQUALKEY ; - m_reverseKeyTranslateTable[LEFTBRACKETKEY ] = KX_LEFTBRACKETKEY ; - m_reverseKeyTranslateTable[RIGHTBRACKETKEY ] = KX_RIGHTBRACKETKEY ; - - m_reverseKeyTranslateTable[LEFTARROWKEY ] = KX_LEFTARROWKEY ; - m_reverseKeyTranslateTable[DOWNARROWKEY ] = KX_DOWNARROWKEY ; - m_reverseKeyTranslateTable[RIGHTARROWKEY ] = KX_RIGHTARROWKEY ; - m_reverseKeyTranslateTable[UPARROWKEY ] = KX_UPARROWKEY ; - - m_reverseKeyTranslateTable[PAD2 ] = KX_PAD2 ; - m_reverseKeyTranslateTable[PAD4 ] = KX_PAD4 ; - m_reverseKeyTranslateTable[PAD6 ] = KX_PAD6 ; - m_reverseKeyTranslateTable[PAD8 ] = KX_PAD8 ; - - m_reverseKeyTranslateTable[PAD1 ] = KX_PAD1 ; - m_reverseKeyTranslateTable[PAD3 ] = KX_PAD3 ; - m_reverseKeyTranslateTable[PAD5 ] = KX_PAD5 ; - m_reverseKeyTranslateTable[PAD7 ] = KX_PAD7 ; - m_reverseKeyTranslateTable[PAD9 ] = KX_PAD9 ; - - m_reverseKeyTranslateTable[PADPERIOD ] = KX_PADPERIOD ; - m_reverseKeyTranslateTable[PADSLASHKEY ] = KX_PADSLASHKEY ; - m_reverseKeyTranslateTable[PADASTERKEY ] = KX_PADASTERKEY ; - - - m_reverseKeyTranslateTable[PAD0 ] = KX_PAD0 ; - m_reverseKeyTranslateTable[PADMINUS ] = KX_PADMINUS ; - m_reverseKeyTranslateTable[PADENTER ] = KX_PADENTER ; - m_reverseKeyTranslateTable[PADPLUSKEY ] = KX_PADPLUSKEY ; - - - m_reverseKeyTranslateTable[F1KEY ] = KX_F1KEY ; - m_reverseKeyTranslateTable[F2KEY ] = KX_F2KEY ; - m_reverseKeyTranslateTable[F3KEY ] = KX_F3KEY ; - m_reverseKeyTranslateTable[F4KEY ] = KX_F4KEY ; - m_reverseKeyTranslateTable[F5KEY ] = KX_F5KEY ; - m_reverseKeyTranslateTable[F6KEY ] = KX_F6KEY ; - m_reverseKeyTranslateTable[F7KEY ] = KX_F7KEY ; - m_reverseKeyTranslateTable[F8KEY ] = KX_F8KEY ; - m_reverseKeyTranslateTable[F9KEY ] = KX_F9KEY ; - m_reverseKeyTranslateTable[F10KEY ] = KX_F10KEY ; - m_reverseKeyTranslateTable[F11KEY ] = KX_F11KEY ; - m_reverseKeyTranslateTable[F12KEY ] = KX_F12KEY ; - m_reverseKeyTranslateTable[F13KEY ] = KX_F13KEY ; - m_reverseKeyTranslateTable[F14KEY ] = KX_F14KEY ; - m_reverseKeyTranslateTable[F15KEY ] = KX_F15KEY ; - m_reverseKeyTranslateTable[F16KEY ] = KX_F16KEY ; - m_reverseKeyTranslateTable[F17KEY ] = KX_F17KEY ; - m_reverseKeyTranslateTable[F18KEY ] = KX_F18KEY ; - m_reverseKeyTranslateTable[F19KEY ] = KX_F19KEY ; - - m_reverseKeyTranslateTable[PAUSEKEY ] = KX_PAUSEKEY ; - m_reverseKeyTranslateTable[INSERTKEY ] = KX_INSERTKEY ; - m_reverseKeyTranslateTable[HOMEKEY ] = KX_HOMEKEY ; - m_reverseKeyTranslateTable[PAGEUPKEY ] = KX_PAGEUPKEY ; - m_reverseKeyTranslateTable[PAGEDOWNKEY ] = KX_PAGEDOWNKEY ; - m_reverseKeyTranslateTable[ENDKEY ] = KX_ENDKEY ; - - - } + m_reverseKeyTranslateTable[IKEY ] = KX_IKEY; + m_reverseKeyTranslateTable[JKEY ] = KX_JKEY; + m_reverseKeyTranslateTable[KKEY ] = KX_KKEY; + m_reverseKeyTranslateTable[LKEY ] = KX_LKEY; + m_reverseKeyTranslateTable[MKEY ] = KX_MKEY; + m_reverseKeyTranslateTable[NKEY ] = KX_NKEY; + m_reverseKeyTranslateTable[OKEY ] = KX_OKEY; + m_reverseKeyTranslateTable[PKEY ] = KX_PKEY; + m_reverseKeyTranslateTable[QKEY ] = KX_QKEY; + m_reverseKeyTranslateTable[RKEY ] = KX_RKEY; + m_reverseKeyTranslateTable[SKEY ] = KX_SKEY; + m_reverseKeyTranslateTable[TKEY ] = KX_TKEY; + m_reverseKeyTranslateTable[UKEY ] = KX_UKEY; + m_reverseKeyTranslateTable[VKEY ] = KX_VKEY; + m_reverseKeyTranslateTable[WKEY ] = KX_WKEY; + m_reverseKeyTranslateTable[XKEY ] = KX_XKEY; + m_reverseKeyTranslateTable[YKEY ] = KX_YKEY; + m_reverseKeyTranslateTable[ZKEY ] = KX_ZKEY; + + m_reverseKeyTranslateTable[ZEROKEY ] = KX_ZEROKEY; + m_reverseKeyTranslateTable[ONEKEY ] = KX_ONEKEY; + m_reverseKeyTranslateTable[TWOKEY ] = KX_TWOKEY; + m_reverseKeyTranslateTable[THREEKEY ] = KX_THREEKEY; + m_reverseKeyTranslateTable[FOURKEY ] = KX_FOURKEY; + m_reverseKeyTranslateTable[FIVEKEY ] = KX_FIVEKEY; + m_reverseKeyTranslateTable[SIXKEY ] = KX_SIXKEY; + m_reverseKeyTranslateTable[SEVENKEY ] = KX_SEVENKEY; + m_reverseKeyTranslateTable[EIGHTKEY ] = KX_EIGHTKEY; + m_reverseKeyTranslateTable[NINEKEY ] = KX_NINEKEY; + + m_reverseKeyTranslateTable[CAPSLOCKKEY ] = KX_CAPSLOCKKEY; + + m_reverseKeyTranslateTable[LEFTCTRLKEY ] = KX_LEFTCTRLKEY; + m_reverseKeyTranslateTable[LEFTALTKEY ] = KX_LEFTALTKEY; + m_reverseKeyTranslateTable[RIGHTALTKEY ] = KX_RIGHTALTKEY; + m_reverseKeyTranslateTable[RIGHTCTRLKEY ] = KX_RIGHTCTRLKEY; + m_reverseKeyTranslateTable[RIGHTSHIFTKEY ] = KX_RIGHTSHIFTKEY; + m_reverseKeyTranslateTable[LEFTSHIFTKEY ] = KX_LEFTSHIFTKEY; + + m_reverseKeyTranslateTable[ESCKEY ] = KX_ESCKEY; + m_reverseKeyTranslateTable[TABKEY ] = KX_TABKEY; + m_reverseKeyTranslateTable[RETKEY ] = KX_RETKEY; + m_reverseKeyTranslateTable[SPACEKEY ] = KX_SPACEKEY; + m_reverseKeyTranslateTable[LINEFEEDKEY ] = KX_LINEFEEDKEY; + m_reverseKeyTranslateTable[BACKSPACEKEY ] = KX_BACKSPACEKEY; + m_reverseKeyTranslateTable[DELKEY ] = KX_DELKEY; + m_reverseKeyTranslateTable[SEMICOLONKEY ] = KX_SEMICOLONKEY; + m_reverseKeyTranslateTable[PERIODKEY ] = KX_PERIODKEY; + m_reverseKeyTranslateTable[COMMAKEY ] = KX_COMMAKEY; + m_reverseKeyTranslateTable[QUOTEKEY ] = KX_QUOTEKEY; + m_reverseKeyTranslateTable[ACCENTGRAVEKEY ] = KX_ACCENTGRAVEKEY; + m_reverseKeyTranslateTable[MINUSKEY ] = KX_MINUSKEY; + m_reverseKeyTranslateTable[SLASHKEY ] = KX_SLASHKEY; + m_reverseKeyTranslateTable[BACKSLASHKEY ] = KX_BACKSLASHKEY; + m_reverseKeyTranslateTable[EQUALKEY ] = KX_EQUALKEY; + m_reverseKeyTranslateTable[LEFTBRACKETKEY ] = KX_LEFTBRACKETKEY; + m_reverseKeyTranslateTable[RIGHTBRACKETKEY ] = KX_RIGHTBRACKETKEY; + + m_reverseKeyTranslateTable[LEFTARROWKEY ] = KX_LEFTARROWKEY; + m_reverseKeyTranslateTable[DOWNARROWKEY ] = KX_DOWNARROWKEY; + m_reverseKeyTranslateTable[RIGHTARROWKEY ] = KX_RIGHTARROWKEY; + m_reverseKeyTranslateTable[UPARROWKEY ] = KX_UPARROWKEY; + + m_reverseKeyTranslateTable[PAD2 ] = KX_PAD2; + m_reverseKeyTranslateTable[PAD4 ] = KX_PAD4; + m_reverseKeyTranslateTable[PAD6 ] = KX_PAD6; + m_reverseKeyTranslateTable[PAD8 ] = KX_PAD8; + + m_reverseKeyTranslateTable[PAD1 ] = KX_PAD1; + m_reverseKeyTranslateTable[PAD3 ] = KX_PAD3; + m_reverseKeyTranslateTable[PAD5 ] = KX_PAD5; + m_reverseKeyTranslateTable[PAD7 ] = KX_PAD7; + m_reverseKeyTranslateTable[PAD9 ] = KX_PAD9; + + m_reverseKeyTranslateTable[PADPERIOD ] = KX_PADPERIOD; + m_reverseKeyTranslateTable[PADSLASHKEY ] = KX_PADSLASHKEY; + m_reverseKeyTranslateTable[PADASTERKEY ] = KX_PADASTERKEY; + + + m_reverseKeyTranslateTable[PAD0 ] = KX_PAD0; + m_reverseKeyTranslateTable[PADMINUS ] = KX_PADMINUS; + m_reverseKeyTranslateTable[PADENTER ] = KX_PADENTER; + m_reverseKeyTranslateTable[PADPLUSKEY ] = KX_PADPLUSKEY; + + + m_reverseKeyTranslateTable[F1KEY ] = KX_F1KEY; + m_reverseKeyTranslateTable[F2KEY ] = KX_F2KEY; + m_reverseKeyTranslateTable[F3KEY ] = KX_F3KEY; + m_reverseKeyTranslateTable[F4KEY ] = KX_F4KEY; + m_reverseKeyTranslateTable[F5KEY ] = KX_F5KEY; + m_reverseKeyTranslateTable[F6KEY ] = KX_F6KEY; + m_reverseKeyTranslateTable[F7KEY ] = KX_F7KEY; + m_reverseKeyTranslateTable[F8KEY ] = KX_F8KEY; + m_reverseKeyTranslateTable[F9KEY ] = KX_F9KEY; + m_reverseKeyTranslateTable[F10KEY ] = KX_F10KEY; + m_reverseKeyTranslateTable[F11KEY ] = KX_F11KEY; + m_reverseKeyTranslateTable[F12KEY ] = KX_F12KEY; + m_reverseKeyTranslateTable[F13KEY ] = KX_F13KEY; + m_reverseKeyTranslateTable[F14KEY ] = KX_F14KEY; + m_reverseKeyTranslateTable[F15KEY ] = KX_F15KEY; + m_reverseKeyTranslateTable[F16KEY ] = KX_F16KEY; + m_reverseKeyTranslateTable[F17KEY ] = KX_F17KEY; + m_reverseKeyTranslateTable[F18KEY ] = KX_F18KEY; + m_reverseKeyTranslateTable[F19KEY ] = KX_F19KEY; + + m_reverseKeyTranslateTable[PAUSEKEY ] = KX_PAUSEKEY; + m_reverseKeyTranslateTable[INSERTKEY ] = KX_INSERTKEY; + m_reverseKeyTranslateTable[HOMEKEY ] = KX_HOMEKEY; + m_reverseKeyTranslateTable[PAGEUPKEY ] = KX_PAGEUPKEY; + m_reverseKeyTranslateTable[PAGEDOWNKEY ] = KX_PAGEDOWNKEY; + m_reverseKeyTranslateTable[ENDKEY ] = KX_ENDKEY; + } virtual ~BL_BlenderInputDevice() - { + { - } - - KX_EnumInputs ToNative(unsigned short incode) { + } + + KX_EnumInputs ToNative(unsigned short incode) { return m_reverseKeyTranslateTable[incode]; } virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode)=0; -// virtual const SCA_InputEvent& GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode)=0; + // 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(size_t 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/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index 50afac6992e..895def17e8e 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -88,10 +88,10 @@ BL_ActionActuator::BL_ActionActuator(SCA_IObject* gameobj, m_blendin(blendin), m_blendstart(0), m_stridelength(stride), + m_layer_weight(layer_weight), m_playtype(playtype), m_priority(priority), m_layer(layer), - m_layer_weight(layer_weight), m_ipo_flags(ipo_flags), m_pose(NULL), m_blendpose(NULL), @@ -129,6 +129,50 @@ void BL_ActionActuator::SetBlendTime (float newtime){ m_blendframe = newtime; } +void BL_ActionActuator::SetLocalTime(float curtime) +{ + float dt = (curtime-m_starttime)*KX_KetsjiEngine::GetAnimFrameRate(); + + if (m_endframe < m_startframe) + dt = -dt; + + m_localtime = m_startframe + dt; + + // Handle wrap around + if (m_localtime < min(m_startframe, m_endframe) || m_localtime > max(m_startframe, m_endframe)) + { + switch(m_playtype) + { + case ACT_ACTION_PLAY: + // Clamp + m_localtime = m_endframe; + break; + case ACT_ACTION_LOOP_END: + // Put the time back to the beginning + m_localtime = m_startframe; + m_starttime = curtime; + break; + case ACT_ACTION_PINGPONG: + // Swap the start and end frames + float temp = m_startframe; + m_startframe = m_endframe; + m_endframe = temp; + + m_starttime = curtime; + + break; + } + } +} + +void BL_ActionActuator::ResetStartTime(float curtime) +{ + float dt = m_localtime - m_startframe; + + m_starttime = curtime - dt / (KX_KetsjiEngine::GetAnimFrameRate()); + //SetLocalTime(curtime); +} + CValue* BL_ActionActuator::GetReplica() { BL_ActionActuator* replica = new BL_ActionActuator(*this);//m_float,GetName()); replica->ProcessReplica(); @@ -173,6 +217,9 @@ bool BL_ActionActuator::Update(double curtime, bool frame) case ACT_ACTION_FROM_PROP: CValue* prop = GetParent()->GetProperty(m_propname); + // If we don't have a property, we can't do anything, so just bail + if (!prop) return false; + playtype = BL_Action::ACT_MODE_PLAY; start = end = prop->GetNumber(); @@ -194,11 +241,46 @@ bool BL_ActionActuator::Update(double curtime, bool frame) RemoveAllEvents(); } + if (m_flag & ACT_FLAG_ATTEMPT_PLAY) + SetLocalTime(curtime); + if (bUseContinue && (m_flag & ACT_FLAG_ACTIVE)) + { m_localtime = obj->GetActionFrame(m_layer); + ResetStartTime(curtime); + } + + // Handle a frame property if it's defined + if ((m_flag & ACT_FLAG_ACTIVE) && m_framepropname[0] != 0) + { + CValue* oldprop = obj->GetProperty(m_framepropname); + CValue* newval = new CFloatValue(obj->GetActionFrame(m_layer)); + if (oldprop) + oldprop->SetValue(newval); + else + obj->SetProperty(m_framepropname, newval); + + newval->Release(); + } + + // Handle a finished animation + if ((m_flag & ACT_FLAG_PLAY_END) && obj->IsActionDone(m_layer)) + { + m_flag &= ~ACT_FLAG_ACTIVE; + m_flag &= ~ACT_FLAG_ATTEMPT_PLAY; + obj->StopAction(m_layer); + return false; + } - if (bPositiveEvent) + // If a different action is playing, we've been overruled and are no longer active + if (obj->GetCurrentAction(m_layer) != m_action) + m_flag &= ~ACT_FLAG_ACTIVE; + + if (bPositiveEvent || (m_flag & ACT_FLAG_ATTEMPT_PLAY && !(m_flag & ACT_FLAG_ACTIVE))) { + if (bPositiveEvent) + ResetStartTime(curtime); + if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, playtype, m_layer_weight, m_ipo_flags)) { m_flag |= ACT_FLAG_ACTIVE; @@ -210,11 +292,11 @@ bool BL_ActionActuator::Update(double curtime, bool frame) else m_flag &= ~ACT_FLAG_PLAY_END; } - else - return false; + m_flag |= ACT_FLAG_ATTEMPT_PLAY; } else if ((m_flag & ACT_FLAG_ACTIVE) && bNegativeEvent) { + m_flag &= ~ACT_FLAG_ATTEMPT_PLAY; bAction *curr_action = obj->GetCurrentAction(m_layer); if (curr_action && curr_action != m_action) { @@ -259,27 +341,6 @@ bool BL_ActionActuator::Update(double curtime, bool frame) } } - // Handle a frame property if it's defined - if ((m_flag & ACT_FLAG_ACTIVE) && m_framepropname[0] != 0) - { - CValue* oldprop = obj->GetProperty(m_framepropname); - CValue* newval = new CFloatValue(obj->GetActionFrame(m_layer)); - if (oldprop) - oldprop->SetValue(newval); - else - obj->SetProperty(m_framepropname, newval); - - newval->Release(); - } - - // Handle a finished animation - if ((m_flag & ACT_FLAG_PLAY_END) && obj->IsActionDone(m_layer)) - { - m_flag &= ~ACT_FLAG_ACTIVE; - obj->StopAction(m_layer); - return false; - } - return true; } diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h index 5324cb10885..357c2b4a05e 100644 --- a/source/gameengine/Converter/BL_ActionActuator.h +++ b/source/gameengine/Converter/BL_ActionActuator.h @@ -64,6 +64,8 @@ public: virtual void ProcessReplica(); void SetBlendTime (float newtime); + void SetLocalTime (float curtime); + void ResetStartTime (float curtime); bAction* GetAction() { return m_action; } void SetAction(bAction* act) { m_action= act; } @@ -150,7 +152,7 @@ enum { ACT_FLAG_ACTIVE = 1<<3, ACT_FLAG_CONTINUE = 1<<4, ACT_FLAG_PLAY_END = 1<<5, - + ACT_FLAG_ATTEMPT_PLAY = 1<<6, }; #endif diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index 395cae4ba87..684bd3f341e 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -231,10 +231,10 @@ BL_ArmatureObject::BL_ArmatureObject( m_timestep(0.040), m_activeAct(NULL), m_activePriority(999), + m_vert_deform_type(vert_deform_type), m_constraintNumber(0), m_channelNumber(0), - m_lastapplyframe(0.0), - m_vert_deform_type(vert_deform_type) + m_lastapplyframe(0.0) { m_armature = (bArmature *)armature->data; diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index fcfc07e631e..d4b43cd7ac1 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -180,6 +180,9 @@ extern Material defmaterial; /* material.c */ #include "BL_ArmatureObject.h" #include "BL_DeformableGameObject.h" +#include "KX_NavMeshObject.h" +#include "KX_ObstacleSimulation.h" + #ifdef __cplusplus extern "C" { #endif @@ -1741,7 +1744,14 @@ static KX_GameObject *gameobject_from_blenderobject( // needed for python scripting kxscene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj); - + + if (ob->gameflag & OB_NAVMESH) + { + gameobj = new KX_NavMeshObject(kxscene,KX_Scene::m_callbacks); + gameobj->AddMesh(meshobj); + break; + } + gameobj = new BL_DeformableGameObject(ob,kxscene,KX_Scene::m_callbacks); // set transformation @@ -2710,6 +2720,46 @@ void BL_ConvertBlenderObjects(struct Main* maggie, converter->RegisterWorldInfo(worldinfo); kxscene->SetWorldInfo(worldinfo); + //create object representations for obstacle simulation + KX_ObstacleSimulation* obssimulation = kxscene->GetObstacleSimulation(); + if (obssimulation) + { + for ( i=0;i<objectlist->GetCount();i++) + { + KX_GameObject* gameobj = static_cast<KX_GameObject*>(objectlist->GetValue(i)); + struct Object* blenderobject = gameobj->GetBlenderObject(); + if (blenderobject->gameflag & OB_HASOBSTACLE) + { + obssimulation->AddObstacleForObj(gameobj); + } + } + } + + //process navigation mesh objects + for ( i=0; i<objectlist->GetCount();i++) + { + KX_GameObject* gameobj = static_cast<KX_GameObject*>(objectlist->GetValue(i)); + struct Object* blenderobject = gameobj->GetBlenderObject(); + if (blenderobject->type==OB_MESH && (blenderobject->gameflag & OB_NAVMESH)) + { + KX_NavMeshObject* navmesh = static_cast<KX_NavMeshObject*>(gameobj); + navmesh->SetVisible(0, true); + navmesh->BuildNavMesh(); + if (obssimulation) + obssimulation->AddObstaclesForNavMesh(navmesh); + } + } + for ( i=0; i<inactivelist->GetCount();i++) + { + KX_GameObject* gameobj = static_cast<KX_GameObject*>(inactivelist->GetValue(i)); + struct Object* blenderobject = gameobj->GetBlenderObject(); + if (blenderobject->type==OB_MESH && (blenderobject->gameflag & OB_NAVMESH)) + { + KX_NavMeshObject* navmesh = static_cast<KX_NavMeshObject*>(gameobj); + navmesh->SetVisible(0, true); + } + } + #define CONVERT_LOGIC #ifdef CONVERT_LOGIC // convert logic bricks, sensors, controllers and actuators diff --git a/source/gameengine/Converter/BL_MeshDeformer.h b/source/gameengine/Converter/BL_MeshDeformer.h index 90466e930fb..0968478ce7e 100644 --- a/source/gameengine/Converter/BL_MeshDeformer.h +++ b/source/gameengine/Converter/BL_MeshDeformer.h @@ -88,7 +88,7 @@ protected: // -- int m_tvtot; BL_DeformableGameObject* m_gameobj; - double m_lastDeformUpdate; + double m_lastDeformUpdate; #ifdef WITH_CXX_GUARDEDALLOC diff --git a/source/gameengine/Converter/BL_ShapeDeformer.h b/source/gameengine/Converter/BL_ShapeDeformer.h index 655cc9d7aeb..609603ae52b 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.h +++ b/source/gameengine/Converter/BL_ShapeDeformer.h @@ -46,8 +46,8 @@ class BL_ShapeDeformer : public BL_SkinDeformer { public: BL_ShapeDeformer(BL_DeformableGameObject *gameobj, - Object *bmeshobj, - RAS_MeshObject *mesh); + Object *bmeshobj, + RAS_MeshObject *mesh); /* this second constructor is needed for making a mesh deformable on the fly. */ BL_ShapeDeformer(BL_DeformableGameObject *gameobj, diff --git a/source/gameengine/Converter/BL_SkinDeformer.cpp b/source/gameengine/Converter/BL_SkinDeformer.cpp index 3a379e8b0ed..93c65eb38de 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.cpp +++ b/source/gameengine/Converter/BL_SkinDeformer.cpp @@ -243,7 +243,6 @@ void BL_SkinDeformer::BGEDeformVerts() for (int i=0; i<m_bmesh->totvert; ++i) { float contrib = 0.f, weight, max_weight=0.f; - Bone *bone; bPoseChannel *pchan=NULL; MDeformVert *dvert; Eigen::Map<Eigen::Vector3f> norm(m_transnors[i]); @@ -266,7 +265,6 @@ void BL_SkinDeformer::BGEDeformVerts() if (index < numGroups && (pchan=m_dfnrToPC[index])) { weight = dvert->dw[j].weight; - bone = pchan->bone; if (weight) { @@ -318,8 +316,8 @@ bool BL_SkinDeformer::UpdateInternal(bool shape_applied) /* duplicate */ for (int v =0; v<m_bmesh->totvert; v++) { - VECCOPY(m_transverts[v], m_bmesh->mvert[v].co); - VECCOPY(m_transnors[v], m_bmesh->mvert[v].no); + copy_v3_v3(m_transverts[v], m_bmesh->mvert[v].co); + normal_short_to_float_v3(m_transnors[v], m_bmesh->mvert[v].no); } } diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt index 3a217ce9d74..039f454e870 100644 --- a/source/gameengine/Converter/CMakeLists.txt +++ b/source/gameengine/Converter/CMakeLists.txt @@ -56,6 +56,7 @@ set(INC ../../../intern/guardedalloc ../../../intern/moto/include ../../../intern/string + ../../../extern/recastnavigation/Detour/Include ) set(INC_SYS diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index ffb9a8ce691..656dcfa3220 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -385,6 +385,12 @@ void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene, //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(); + +#ifndef USE_BULLET + /* quiet compiler warning */ + (void)useDbvtCulling; +#endif + } // This function removes all entities stored in the converter for that scene @@ -679,7 +685,7 @@ void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo(bool clearIpo) MEM_freeN( tmpicu ); localDel_ipoCurve( tmpicu ); } - } + } } else { ipo = NULL; // XXX add_ipo(blenderObject->id.name+2, ID_OB); blenderObject->ipo = ipo; diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index a84a1419d0d..a14e5fb5449 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -72,6 +72,7 @@ #include "KX_SCA_ReplaceMeshActuator.h" #include "KX_ParentActuator.h" #include "KX_SCA_DynamicActuator.h" +#include "KX_SteeringActuator.h" #include "KX_Scene.h" #include "KX_KetsjiEngine.h" @@ -100,6 +101,7 @@ #include "BL_ActionActuator.h" #include "BL_ShapeActionActuator.h" #include "BL_ArmatureActuator.h" +#include "RNA_access.h" #include "BL_Action.h" /* end of blender include block */ @@ -413,14 +415,21 @@ void BL_ConvertActuators(char* maggiename, // if sound shall be 3D but isn't mono, we have to make it mono! if(is3d) { - AUD_Reference<AUD_IReader> reader = snd_sound->createReader(); - if(reader->getSpecs().channels != AUD_CHANNELS_MONO) + try { - AUD_DeviceSpecs specs; - specs.channels = AUD_CHANNELS_MONO; - specs.rate = AUD_RATE_INVALID; - specs.format = AUD_FORMAT_INVALID; - snd_sound = new AUD_ChannelMapperFactory(snd_sound, specs); + AUD_Reference<AUD_IReader> reader = snd_sound->createReader(); + if(reader->getSpecs().channels != AUD_CHANNELS_MONO) + { + AUD_DeviceSpecs specs; + specs.channels = AUD_CHANNELS_MONO; + specs.rate = AUD_RATE_INVALID; + specs.format = AUD_FORMAT_INVALID; + snd_sound = new AUD_ChannelMapperFactory(snd_sound, specs); + } + } + catch(AUD_Exception&) + { + // sound cannot be played... ignore } } } @@ -942,7 +951,7 @@ void BL_ConvertActuators(char* maggiename, case ACT_2DFILTER: { bTwoDFilterActuator *_2dfilter = (bTwoDFilterActuator*) bact->data; - SCA_2DFilterActuator *tmp = NULL; + SCA_2DFilterActuator *tmp = NULL; RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode; switch(_2dfilter->type) @@ -1057,6 +1066,45 @@ void BL_ConvertActuators(char* maggiename, baseact = tmparmact; break; } + case ACT_STEERING: + { + bSteeringActuator *stAct = (bSteeringActuator *) bact->data; + KX_GameObject *navmeshob = NULL; + if (stAct->navmesh) + { + PointerRNA settings_ptr; + RNA_pointer_create((ID *)stAct->navmesh, &RNA_GameObjectSettings, stAct->navmesh, &settings_ptr); + if (RNA_enum_get(&settings_ptr, "physics_type") == OB_BODY_TYPE_NAVMESH) + navmeshob = converter->FindGameObject(stAct->navmesh); + } + KX_GameObject *targetob = converter->FindGameObject(stAct->target); + + int mode = KX_SteeringActuator::KX_STEERING_NODEF; + switch(stAct->type) + { + case ACT_STEERING_SEEK: + mode = KX_SteeringActuator::KX_STEERING_SEEK; + break; + case ACT_STEERING_FLEE: + mode = KX_SteeringActuator::KX_STEERING_FLEE; + break; + case ACT_STEERING_PATHFOLLOWING: + mode = KX_SteeringActuator::KX_STEERING_PATHFOLLOWING; + break; + } + + bool selfTerminated = (stAct->flag & ACT_STEERING_SELFTERMINATED) !=0; + bool enableVisualization = (stAct->flag & ACT_STEERING_ENABLEVISUALIZATION) !=0; + short facingMode = (stAct->flag & ACT_STEERING_AUTOMATICFACING) ? stAct->facingaxis : 0; + bool normalup = (stAct->flag & ACT_STEERING_NORMALUP) !=0; + KX_SteeringActuator *tmpstact + = new KX_SteeringActuator(gameobj, mode, targetob, navmeshob,stAct->dist, + stAct->velocity, stAct->acceleration, stAct->turnspeed, + selfTerminated, stAct->updateTime, + scene->GetObstacleSimulation(), facingMode, normalup, enableVisualization); + baseact = tmpstact; + break; + } default: ; /* generate some error */ } diff --git a/source/gameengine/Converter/KX_IpoConvert.cpp b/source/gameengine/Converter/KX_IpoConvert.cpp index 0ee99f5335b..b13dbe324f5 100644 --- a/source/gameengine/Converter/KX_IpoConvert.cpp +++ b/source/gameengine/Converter/KX_IpoConvert.cpp @@ -257,7 +257,7 @@ SG_Controller *BL_CreateCameraIPO(struct bAction *action, KX_GameObject* camera ipocontr->m_clipstart = blendercamera->clipsta; ipocontr->m_clipend = blendercamera->clipend; - BL_InterpolatorList *adtList= GetAdtList(blendercamera->adt->action, converter); + BL_InterpolatorList *adtList= GetAdtList(action, converter); // For each active channel in the adtList add an // interpolator to the game object. diff --git a/source/gameengine/Converter/SConscript b/source/gameengine/Converter/SConscript index 0ae22d548c5..e155677e522 100644 --- a/source/gameengine/Converter/SConscript +++ b/source/gameengine/Converter/SConscript @@ -20,6 +20,7 @@ incs += ' #source/blender/misc #source/blender/blenloader #source/blender/gpu' incs += ' #source/blender/windowmanager' incs += ' #source/blender/makesrna' incs += ' #source/blender/ikplugin' +incs += ' #extern/recastnavigation/Detour/Include' incs += ' #extern/Eigen2' incs += ' ' + env['BF_BULLET_INC'] diff --git a/source/gameengine/Expressions/IfExpr.h b/source/gameengine/Expressions/IfExpr.h index 5ac8d835afd..e67134c2271 100644 --- a/source/gameengine/Expressions/IfExpr.h +++ b/source/gameengine/Expressions/IfExpr.h @@ -20,7 +20,7 @@ #if !defined(AFX_IFEXPR_H__1F691841_C5C7_11D1_A863_0000B4542BD8__INCLUDED_) #define AFX_IFEXPR_H__1F691841_C5C7_11D1_A863_0000B4542BD8__INCLUDED_ -#if _MSC_VER >= 1000 +#if defined(_MSC_VER) && _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 diff --git a/source/gameengine/Expressions/ListValue.cpp b/source/gameengine/Expressions/ListValue.cpp index 271d5067dd9..934f2a8dd87 100644 --- a/source/gameengine/Expressions/ListValue.cpp +++ b/source/gameengine/Expressions/ListValue.cpp @@ -387,7 +387,7 @@ PyObject* listvalue_buffer_slice(PyObject* self,Py_ssize_t ilow, Py_ssize_t ihig static PyObject *listvalue_buffer_concat(PyObject * self, PyObject * other) { CListValue *listval= static_cast<CListValue *>(BGE_PROXY_REF(self)); - int i, numitems, numitems_orig; + Py_ssize_t i, numitems, numitems_orig; if (listval==NULL) { PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG); @@ -408,7 +408,7 @@ static PyObject *listvalue_buffer_concat(PyObject * self, PyObject * other) CValue* listitemval; bool error = false; - numitems = PyList_Size(other); + numitems = PyList_GET_SIZE(other); /* copy the first part of the list */ listval_new->Resize(numitems_orig + numitems); diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp index e60b380e95c..41c0850a779 100644 --- a/source/gameengine/Expressions/Value.cpp +++ b/source/gameengine/Expressions/Value.cpp @@ -546,8 +546,8 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj, const char *error_prefix) CListValue* listval = new CListValue(); bool error = false; - int i; - int numitems = PyList_Size(pyobj); + Py_ssize_t i; + Py_ssize_t numitems = PyList_GET_SIZE(pyobj); for (i=0;i<numitems;i++) { PyObject* listitem = PyList_GetItem(pyobj,i); /* borrowed ref */ diff --git a/source/gameengine/GameLogic/SCA_2DFilterActuator.h b/source/gameengine/GameLogic/SCA_2DFilterActuator.h index 7f31c1713f4..82c82ac3be5 100644 --- a/source/gameengine/GameLogic/SCA_2DFilterActuator.h +++ b/source/gameengine/GameLogic/SCA_2DFilterActuator.h @@ -52,19 +52,19 @@ private: public: - SCA_2DFilterActuator( - class SCA_IObject* gameobj, - RAS_2DFilterManager::RAS_2DFILTER_MODE type, - short flag, - float float_arg, - int int_arg, - RAS_IRasterizer* rasterizer, - SCA_IScene* scene); + SCA_2DFilterActuator( + class SCA_IObject* gameobj, + RAS_2DFilterManager::RAS_2DFILTER_MODE type, + short flag, + float float_arg, + int int_arg, + RAS_IRasterizer* rasterizer, + SCA_IScene* scene); void SetShaderText(const char *text); - virtual ~SCA_2DFilterActuator(); - virtual bool Update(); + virtual ~SCA_2DFilterActuator(); + virtual bool Update(); - virtual CValue* GetReplica(); + virtual CValue* GetReplica(); }; #endif diff --git a/source/gameengine/GameLogic/SCA_IActuator.h b/source/gameengine/GameLogic/SCA_IActuator.h index bfcec983e2a..d2a8de32895 100644 --- a/source/gameengine/GameLogic/SCA_IActuator.h +++ b/source/gameengine/GameLogic/SCA_IActuator.h @@ -90,6 +90,7 @@ public: KX_ACT_SHAPEACTION, KX_ACT_STATE, KX_ACT_ARMATURE, + KX_ACT_STEERING, }; SCA_IActuator(SCA_IObject* gameobj, KX_ACTUATOR_TYPE type); diff --git a/source/gameengine/GameLogic/SCA_PythonController.h b/source/gameengine/GameLogic/SCA_PythonController.h index 3ccbfea7ed5..739e566237b 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.h +++ b/source/gameengine/GameLogic/SCA_PythonController.h @@ -34,7 +34,7 @@ #ifndef KX_PYTHONCONTROLLER_H #define KX_PYTHONCONTROLLER_H - + #include "SCA_IController.h" #include "SCA_LogicManager.h" #include "BoolValue.h" diff --git a/source/gameengine/GameLogic/SCA_RandomActuator.cpp b/source/gameengine/GameLogic/SCA_RandomActuator.cpp index d76f3f775a5..c9d11a27c76 100644 --- a/source/gameengine/GameLogic/SCA_RandomActuator.cpp +++ b/source/gameengine/GameLogic/SCA_RandomActuator.cpp @@ -207,10 +207,10 @@ bool SCA_RandomActuator::Update() sensible values. The termination condition states two things: 1. s >= 0 is not allowed: to prevent the distro from - getting a bias towards high values. This is a small + getting a bias towards high values. This is a small correction, really, and might also be left out. 2. s == 0 is not allowed: to prevent a division by zero - when renormalising the drawn value to the desired + when renormalising the drawn value to the desired distribution shape. As a side effect, the distro will never yield the exact mean. I am not sure whether this is consistent, since the error diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index c5daae9c963..7b47d74d424 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -151,7 +151,7 @@ GPG_Application::~GPG_Application(void) -bool GPG_Application::SetGameEngineData(struct Main* maggie, Scene *scene, int argc, char **argv) +bool GPG_Application::SetGameEngineData(struct Main* maggie, Scene *scene, GlobalSettings *gs, int argc, char **argv) { bool result = false; @@ -168,6 +168,9 @@ bool GPG_Application::SetGameEngineData(struct Main* maggie, Scene *scene, int a m_argc= argc; m_argv= argv; + /* Global Settings */ + m_globalSettings= gs; + return result; } @@ -192,7 +195,7 @@ static LRESULT CALLBACK screenSaverWindowProc(HWND hwnd, UINT uMsg, WPARAM wPara LONG dx = scr_save_mouse_pos.x - pt.x; LONG dy = scr_save_mouse_pos.y - pt.y; if (abs(dx) > SCR_SAVE_MOUSE_MOVE_THRESHOLD - || abs(dy) > SCR_SAVE_MOUSE_MOVE_THRESHOLD) + || abs(dy) > SCR_SAVE_MOUSE_MOVE_THRESHOLD) { close = TRUE; } @@ -511,6 +514,12 @@ int GPG_Application::getExitRequested(void) } +GlobalSettings* GPG_Application::getGlobalSettings(void) +{ + return m_ketsjiengine->GetGlobalSettings(); +} + + const STR_String& GPG_Application::getExitString(void) { @@ -552,7 +561,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) if(GPU_glsl_support()) m_blenderglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0); - else if(gm->matmode == GAME_MAT_GLSL) + else if(m_globalSettings->matmode == GAME_MAT_GLSL) m_blendermat = false; // create the canvas, rasterizer and rendertools @@ -629,6 +638,9 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) m_ketsjiengine->SetTimingDisplay(frameRate, profile, properties); m_ketsjiengine->SetRestrictAnimationFPS(restrictAnimFPS); + //set the global settings (carried over if restart/load new files) + m_ketsjiengine->SetGlobalSettings(m_globalSettings); + m_engineInitialized = true; } @@ -685,9 +697,9 @@ bool GPG_Application::startEngine(void) // if (always_use_expand_framing) // sceneconverter->SetAlwaysUseExpandFraming(true); - if(m_blendermat && (m_startScene->gm.matmode != GAME_MAT_TEXFACE)) + if(m_blendermat && (m_globalSettings->matmode != GAME_MAT_TEXFACE)) m_sceneconverter->SetMaterials(true); - if(m_blenderglslmat && (m_startScene->gm.matmode == GAME_MAT_GLSL)) + if(m_blenderglslmat && (m_globalSettings->matmode == GAME_MAT_GLSL)) m_sceneconverter->SetGLSLMaterials(true); KX_Scene* startscene = new KX_Scene(m_keyboard, diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.h b/source/gameengine/GamePlayer/ghost/GPG_Application.h index c0638517657..df87aea1195 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.h +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.h @@ -39,6 +39,8 @@ #include <wtypes.h> #endif +#include "KX_KetsjiEngine.h" + class KX_KetsjiEngine; class KX_ISceneConverter; class NG_LoopBackNetworkDeviceInterface; @@ -61,7 +63,7 @@ public: GPG_Application(GHOST_ISystem* system); ~GPG_Application(void); - bool SetGameEngineData(struct Main* maggie, struct Scene* scene, int argc, char** argv); + bool SetGameEngineData(struct Main* maggie, struct Scene* scene, GlobalSettings* gs, int argc, char** argv); bool startWindow(STR_String& title, int windowLeft, int windowTop, int windowWidth, int windowHeight, const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0); bool startFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0); @@ -74,6 +76,7 @@ public: virtual bool processEvent(GHOST_IEvent* event); int getExitRequested(void); const STR_String& getExitString(void); + GlobalSettings* getGlobalSettings(void); bool StartGameEngine(int stereoMode); void StopGameEngine(); @@ -111,6 +114,8 @@ protected: /* Exit state. */ int m_exitRequested; STR_String m_exitString; + GlobalSettings* m_globalSettings; + /* GHOST system abstraction. */ GHOST_ISystem* m_system; /* Main window. */ diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index 5318c417916..2695a67ac4f 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -751,6 +751,11 @@ int main(int argc, char** argv) if(filename[0]) BLI_path_cwd(filename); + + // fill the GlobalSettings with the first scene files + // those may change during the game and persist after using Game Actuator + GlobalSettings gs; + do { // Read the Blender file @@ -804,9 +809,13 @@ int main(int argc, char** argv) Scene *scene = bfd->curscene; G.main = maggie; - if (firstTimeRunning) + if (firstTimeRunning) { G.fileflags = bfd->fileflags; + gs.matmode= scene->gm.matmode; + gs.glslflag= scene->gm.flag; + } + //Seg Fault; icon.c gIcons == 0 BKE_icons_init(1); @@ -866,7 +875,7 @@ int main(int argc, char** argv) } // GPG_Application app (system, maggie, startscenename); - app.SetGameEngineData(maggie, scene, argc, argv); /* this argc cant be argc_py_clamped, since python uses it */ + app.SetGameEngineData(maggie, scene, &gs, argc, argv); /* this argc cant be argc_py_clamped, since python uses it */ BLI_strncpy(pathname, maggie->name, sizeof(pathname)); if(G.main != maggie) { BLI_strncpy(G.main->name, maggie->name, sizeof(G.main->name)); @@ -962,6 +971,7 @@ int main(int argc, char** argv) { run = false; exitstring = app.getExitString(); + gs = *app.getGlobalSettings(); } } app.StopGameEngine(); diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index 99c9fb25a65..9d8b1781869 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -57,6 +57,8 @@ set(INC set(INC_SYS ${GLEW_INCLUDE_PATH} + ../../../extern/recastnavigation/Recast/Include + ../../../extern/recastnavigation/Detour/Include ) set(SRC @@ -90,9 +92,11 @@ set(SRC KX_MeshProxy.cpp KX_MotionState.cpp KX_MouseFocusSensor.cpp + KX_NavMeshObject.cpp KX_NearSensor.cpp KX_ObColorIpoSGController.cpp KX_ObjectActuator.cpp + KX_ObstacleSimulation.cpp KX_OrientationInterpolator.cpp KX_ParentActuator.cpp KX_PhysicsObjectWrapper.cpp @@ -120,6 +124,7 @@ set(SRC KX_SceneActuator.cpp KX_SoundActuator.cpp KX_StateActuator.cpp + KX_SteeringActuator.cpp KX_TimeCategoryLogger.cpp KX_TimeLogger.cpp KX_TouchEventManager.cpp @@ -167,9 +172,11 @@ set(SRC KX_MeshProxy.h KX_MotionState.h KX_MouseFocusSensor.h + KX_NavMeshObject.h KX_NearSensor.h KX_ObColorIpoSGController.h KX_ObjectActuator.h + KX_ObstacleSimulation.h KX_OrientationInterpolator.h KX_ParentActuator.h KX_PhysicsEngineEnums.h @@ -199,6 +206,7 @@ set(SRC KX_SceneActuator.h KX_SoundActuator.h KX_StateActuator.h + KX_SteeringActuator.h KX_TimeCategoryLogger.h KX_TimeLogger.h KX_TouchEventManager.h diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h index ff9131f464e..405e2d52989 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h @@ -43,7 +43,7 @@ class KX_NetworkEventManager : public SCA_EventManager public: KX_NetworkEventManager(class SCA_LogicManager* logicmgr, - class NG_NetworkDeviceInterface *ndi); + class NG_NetworkDeviceInterface *ndi); virtual ~KX_NetworkEventManager (); virtual void NextFrame(); @@ -51,7 +51,7 @@ public: SCA_LogicManager* GetLogicManager() { return m_logicmgr; } class NG_NetworkDeviceInterface* GetNetworkDevice() { - return m_ndi; } + return m_ndi; } }; #endif //KX_NETWORK_EVENTMANAGER_H diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 67178803457..ae8d7094015 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -73,6 +73,7 @@ typedef unsigned long uint_ptr; #include "SCA_ISensor.h" #include "SCA_IController.h" #include "NG_NetworkScene.h" //Needed for sendMessage() +#include "KX_ObstacleSimulation.h" #include "BL_ActionManager.h" @@ -110,8 +111,9 @@ KX_GameObject::KX_GameObject( m_xray(false), m_pHitObject(NULL), m_actionManager(NULL), - m_isDeformable(false) - #ifdef WITH_PYTHON + m_isDeformable(false), + m_pObstacleSimulation(NULL) +#ifdef WITH_PYTHON , m_attr_dict(NULL) #endif { @@ -157,8 +159,15 @@ KX_GameObject::~KX_GameObject() { delete m_pGraphicController; } + + if (m_pObstacleSimulation) + { + m_pObstacleSimulation->DestroyObstacleForObj(this); + } + if (m_actionManager) { + KX_GetActiveScene()->RemoveAnimatedObject(this); delete m_actionManager; } #ifdef WITH_PYTHON @@ -355,8 +364,8 @@ BL_ActionManager* KX_GameObject::GetActionManager() { // We only want to create an action manager if we need it if (!m_actionManager) - m_actionManager = new BL_ActionManager(this); - + { KX_GetActiveScene()->AddAnimatedObject(this); m_actionManager = new BL_ActionManager(this); + } return m_actionManager; } @@ -427,6 +436,14 @@ void KX_GameObject::ProcessReplica() m_actionManager = new BL_ActionManager(this); m_state = 0; + KX_Scene* scene = KX_GetActiveScene(); + KX_ObstacleSimulation* obssimulation = scene->GetObstacleSimulation(); + struct Object* blenderobject = GetBlenderObject(); + if (obssimulation && (blenderobject->gameflag & OB_HASOBSTACLE)) + { + obssimulation->AddObstacleForObj(this); + } + #ifdef WITH_PYTHON if(m_attr_dict) m_attr_dict= PyDict_Copy(m_attr_dict); diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 6e79914172b..655bc9ff080 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -65,6 +65,7 @@ class PHY_IGraphicController; class PHY_IPhysicsEnvironment; class BL_ActionManager; struct Object; +class KX_ObstacleSimulation; struct bAction; #ifdef WITH_PYTHON @@ -115,6 +116,9 @@ protected: MT_CmMatrix4x4 m_OpenGL_4x4Matrix; + KX_ObstacleSimulation* m_pObstacleSimulation; + + // The action manager is used to play/stop/update actions BL_ActionManager* m_actionManager; @@ -864,6 +868,16 @@ public: } m_bSuspendDynamics = false; } + + void RegisterObstacle(KX_ObstacleSimulation* obstacleSimulation) + { + m_pObstacleSimulation = obstacleSimulation; + } + + void UnregisterObstacle() + { + m_pObstacleSimulation = NULL; + } KX_ClientObjectInfo* getClientInfo() { return m_pClient_info; } diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 878232f7a50..65ff06456b4 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -84,6 +84,8 @@ #include "DNA_world_types.h" #include "DNA_scene_types.h" +#include "KX_NavMeshObject.h" + // If define: little test for Nzc: guarded drawing. If the canvas is // not valid, skip rendering this frame. //#define NZC_GUARDED_OUTPUT @@ -886,8 +888,6 @@ void KX_KetsjiEngine::Render() { if((*it)->GetViewport()) { - // Change the active camera so Python scripts can figure out what viewport they're in - scene->SetActiveCamera(*it); if (scene->IsClearingZBuffer()) m_rasterizer->ClearDepthBuffer(); @@ -899,10 +899,6 @@ void KX_KetsjiEngine::Render() it++; } - - // Now change the camera back - scene->SetActiveCamera(cam); - PostRenderScene(scene); } @@ -1322,10 +1318,6 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) if (scene->GetPhysicsEnvironment()) scene->GetPhysicsEnvironment()->debugDrawWorld(); - -#ifdef WITH_PYTHON - scene->RunDrawingCallbacks(scene->GetPostDrawCB()); -#endif } void KX_KetsjiEngine::RenderFonts(KX_Scene* scene) @@ -1345,9 +1337,15 @@ To run once per scene */ void KX_KetsjiEngine::PostRenderScene(KX_Scene* scene) { + // We need to first make sure our viewport is correct (enabling multiple viewports can mess this up) + m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight()); + m_rendertools->MotionBlur(m_rasterizer); scene->Render2DFilters(m_canvas); - m_rasterizer->FlushDebugLines(); +#ifdef WITH_PYTHON + scene->RunDrawingCallbacks(scene->GetPostDrawCB()); +#endif + m_rasterizer->FlushDebugShapes(); } void KX_KetsjiEngine::StopEngine() @@ -1938,4 +1936,14 @@ void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const b = m_overrideFrameColorB; } +void KX_KetsjiEngine::SetGlobalSettings(GlobalSettings* gs) +{ + m_globalsettings.matmode = gs->matmode; + m_globalsettings.glslflag = gs->glslflag; +} + +GlobalSettings* KX_KetsjiEngine::GetGlobalSettings(void) +{ + return &m_globalsettings; +} diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index b1009c7d8f0..f2f978a0afa 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -62,6 +62,11 @@ enum KX_ExitRequestMode KX_EXIT_REQUEST_MAX }; +typedef struct { + short matmode; + short glslflag; +} GlobalSettings; + /** * KX_KetsjiEngine is the core game engine class. */ @@ -193,6 +198,9 @@ private: /** Blue component of framing bar color. */ float m_overrideFrameColorB; + /** Settings that doesn't go away with Game Actuator */ + GlobalSettings m_globalsettings; + void RenderFrame(KX_Scene* scene, KX_Camera* cam); void PostRenderScene(KX_Scene* scene); void RenderDebugProperties(); @@ -404,7 +412,10 @@ public: KX_Scene* CreateScene(const STR_String& scenename); KX_Scene* CreateScene(Scene *scene); - + + GlobalSettings* GetGlobalSettings(void); + void SetGlobalSettings(GlobalSettings* gs); + protected: /** * Processes all scheduled scene activity. diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.cpp b/source/gameengine/Ketsji/KX_NavMeshObject.cpp new file mode 100644 index 00000000000..f72c98fb4bf --- /dev/null +++ b/source/gameengine/Ketsji/KX_NavMeshObject.cpp @@ -0,0 +1,709 @@ +/** +* $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#include "BLI_math_vector.h" +#include "KX_NavMeshObject.h" +#include "RAS_MeshObject.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +extern "C" { +#include "BKE_scene.h" +#include "BKE_customdata.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_DerivedMesh.h" +#include "BKE_navmesh_conversion.h" +} + +#include "KX_PythonInit.h" +#include "KX_PyMath.h" +#include "Value.h" +#include "Recast.h" +#include "DetourStatNavMeshBuilder.h" +#include "KX_ObstacleSimulation.h" + +static const int MAX_PATH_LEN = 256; +static const float polyPickExt[3] = {2, 4, 2}; + +static void calcMeshBounds(const float* vert, int nverts, float* bmin, float* bmax) +{ + bmin[0] = bmax[0] = vert[0]; + bmin[1] = bmax[1] = vert[1]; + bmin[2] = bmax[2] = vert[2]; + for (int i=1; i<nverts; i++) + { + if (bmin[0]>vert[3*i+0]) bmin[0] = vert[3*i+0]; + if (bmin[1]>vert[3*i+1]) bmin[1] = vert[3*i+1]; + if (bmin[2]>vert[3*i+2]) bmin[2] = vert[3*i+2]; + + if (bmax[0]<vert[3*i+0]) bmax[0] = vert[3*i+0]; + if (bmax[1]<vert[3*i+1]) bmax[1] = vert[3*i+1]; + if (bmax[2]<vert[3*i+2]) bmax[2] = vert[3*i+2]; + } +} + +inline void flipAxes(float* vec) +{ + std::swap(vec[1],vec[2]); +} +KX_NavMeshObject::KX_NavMeshObject(void* sgReplicationInfo, SG_Callbacks callbacks) +: KX_GameObject(sgReplicationInfo, callbacks) +, m_navMesh(NULL) +{ + +} + +KX_NavMeshObject::~KX_NavMeshObject() +{ + if (m_navMesh) + delete m_navMesh; +} + +CValue* KX_NavMeshObject::GetReplica() +{ + KX_NavMeshObject* replica = new KX_NavMeshObject(*this); + replica->ProcessReplica(); + return replica; +} + +void KX_NavMeshObject::ProcessReplica() +{ + KX_GameObject::ProcessReplica(); + + BuildNavMesh(); + KX_Scene* scene = KX_GetActiveScene(); + KX_ObstacleSimulation* obssimulation = scene->GetObstacleSimulation(); + if (obssimulation) + obssimulation->AddObstaclesForNavMesh(this); + +} + +bool KX_NavMeshObject::BuildVertIndArrays(float *&vertices, int& nverts, + unsigned short* &polys, int& npolys, unsigned short *&dmeshes, + float *&dvertices, int &ndvertsuniq, unsigned short *&dtris, + int& ndtris, int &vertsPerPoly) +{ + DerivedMesh* dm = mesh_create_derived_no_virtual(KX_GetActiveScene()->GetBlenderScene(), GetBlenderObject(), + NULL, CD_MASK_MESH); + int* recastData = (int*) dm->getFaceDataArray(dm, CD_RECAST); + if (recastData) + { + int *dtrisToPolysMap=NULL, *dtrisToTrisMap=NULL, *trisToFacesMap=NULL; + int nAllVerts = 0; + float *allVerts = NULL; + buildNavMeshDataByDerivedMesh(dm, vertsPerPoly, nAllVerts, allVerts, ndtris, dtris, + npolys, dmeshes, polys, dtrisToPolysMap, dtrisToTrisMap, trisToFacesMap); + + unsigned short *verticesMap = new unsigned short[nAllVerts]; + memset(verticesMap, 0xffff, sizeof(unsigned short)*nAllVerts); + int curIdx = 0; + //vertices - mesh verts + //iterate over all polys and create map for their vertices first... + for (int polyidx=0; polyidx<npolys; polyidx++) + { + unsigned short* poly = &polys[polyidx*vertsPerPoly*2]; + for (int i=0; i<vertsPerPoly; i++) + { + unsigned short idx = poly[i]; + if (idx==0xffff) + break; + if (verticesMap[idx]==0xffff) + { + verticesMap[idx] = curIdx++; + } + poly[i] = verticesMap[idx]; + } + } + nverts = curIdx; + //...then iterate over detailed meshes + //transform indices to local ones (for each navigation polygon) + for (int polyidx=0; polyidx<npolys; polyidx++) + { + unsigned short *poly = &polys[polyidx*vertsPerPoly*2]; + int nv = polyNumVerts(poly, vertsPerPoly); + unsigned short *dmesh = &dmeshes[4*polyidx]; + unsigned short tribase = dmesh[2]; + unsigned short trinum = dmesh[3]; + unsigned short vbase = curIdx; + for (int j=0; j<trinum; j++) + { + unsigned short* dtri = &dtris[(tribase+j)*3*2]; + for (int k=0; k<3; k++) + { + int newVertexIdx = verticesMap[dtri[k]]; + if (newVertexIdx==0xffff) + { + newVertexIdx = curIdx++; + verticesMap[dtri[k]] = newVertexIdx; + } + + if (newVertexIdx<nverts) + { + //it's polygon vertex ("shared") + int idxInPoly = polyFindVertex(poly, vertsPerPoly, newVertexIdx); + if (idxInPoly==-1) + { + printf("Building NavMeshObject: Error! Can't find vertex in polygon\n"); + return false; + } + dtri[k] = idxInPoly; + } + else + { + dtri[k] = newVertexIdx - vbase + nv; + } + } + } + dmesh[0] = vbase-nverts; //verts base + dmesh[1] = curIdx-vbase; //verts num + } + + vertices = new float[nverts*3]; + ndvertsuniq = curIdx - nverts; + if (ndvertsuniq>0) + { + dvertices = new float[ndvertsuniq*3]; + } + for (int vi=0; vi<nAllVerts; vi++) + { + int newIdx = verticesMap[vi]; + if (newIdx!=0xffff) + { + if (newIdx<nverts) + { + //navigation mesh vertex + memcpy(vertices+3*newIdx, allVerts+3*vi, 3*sizeof(float)); + } + else + { + //detailed mesh vertex + memcpy(dvertices+3*(newIdx-nverts), allVerts+3*vi, 3*sizeof(float)); + } + } + } + } + else + { + //create from RAS_MeshObject (detailed mesh is fake) + RAS_MeshObject* meshobj = GetMesh(0); + vertsPerPoly = 3; + nverts = meshobj->m_sharedvertex_map.size(); + if (nverts >= 0xffff) + return false; + //calculate count of tris + int nmeshpolys = meshobj->NumPolygons(); + npolys = nmeshpolys; + for (int p=0; p<nmeshpolys; p++) + { + int vertcount = meshobj->GetPolygon(p)->VertexCount(); + npolys+=vertcount-3; + } + + //create verts + vertices = new float[nverts*3]; + float* vert = vertices; + for (int vi=0; vi<nverts; vi++) + { + const float* pos = !meshobj->m_sharedvertex_map[vi].empty() ? meshobj->GetVertexLocation(vi) : NULL; + if (pos) + copy_v3_v3(vert, pos); + else + { + memset(vert, 0, 3*sizeof(float)); //vertex isn't in any poly, set dummy zero coordinates + } + vert+=3; + } + + //create tris + polys = new unsigned short[npolys*3*2]; + memset(polys, 0xff, sizeof(unsigned short)*3*2*npolys); + unsigned short *poly = polys; + RAS_Polygon* raspoly; + for (int p=0; p<nmeshpolys; p++) + { + raspoly = meshobj->GetPolygon(p); + for (int v=0; v<raspoly->VertexCount()-2; v++) + { + poly[0]= raspoly->GetVertex(0)->getOrigIndex(); + for (size_t i=1; i<3; i++) + { + poly[i]= raspoly->GetVertex(v+i)->getOrigIndex(); + } + poly += 6; + } + } + dmeshes = NULL; + dvertices = NULL; + ndvertsuniq = 0; + dtris = NULL; + ndtris = npolys; + } + dm->release(dm); + + return true; +} + + +bool KX_NavMeshObject::BuildNavMesh() +{ + if (m_navMesh) + { + delete m_navMesh; + m_navMesh = NULL; + } + + if (GetMeshCount()==0) + { + printf("Can't find mesh for navmesh object: %s \n", m_name.ReadPtr()); + return false; + } + + float *vertices = NULL, *dvertices = NULL; + unsigned short *polys = NULL, *dtris = NULL, *dmeshes = NULL; + int nverts = 0, npolys = 0, ndvertsuniq = 0, ndtris = 0; + int vertsPerPoly = 0; + if (!BuildVertIndArrays(vertices, nverts, polys, npolys, + dmeshes, dvertices, ndvertsuniq, dtris, ndtris, vertsPerPoly ) + || vertsPerPoly<3) + { + printf("Can't build navigation mesh data for object:%s \n", m_name.ReadPtr()); + return false; + } + + MT_Point3 pos; + if (dmeshes==NULL) + { + for (int i=0; i<nverts; i++) + { + flipAxes(&vertices[i*3]); + } + for (int i=0; i<ndvertsuniq; i++) + { + flipAxes(&dvertices[i*3]); + } + } + + buildMeshAdjacency(polys, npolys, nverts, vertsPerPoly); + + float cs = 0.2f; + + if (!nverts || !npolys) + return false; + + float bmin[3], bmax[3]; + calcMeshBounds(vertices, nverts, bmin, bmax); + //quantize vertex pos + unsigned short* vertsi = new unsigned short[3*nverts]; + float ics = 1.f/cs; + for (int i=0; i<nverts; i++) + { + vertsi[3*i+0] = static_cast<unsigned short>((vertices[3*i+0]-bmin[0])*ics); + vertsi[3*i+1] = static_cast<unsigned short>((vertices[3*i+1]-bmin[1])*ics); + vertsi[3*i+2] = static_cast<unsigned short>((vertices[3*i+2]-bmin[2])*ics); + } + + // Calculate data size + const int headerSize = sizeof(dtStatNavMeshHeader); + const int vertsSize = sizeof(float)*3*nverts; + const int polysSize = sizeof(dtStatPoly)*npolys; + const int nodesSize = sizeof(dtStatBVNode)*npolys*2; + const int detailMeshesSize = sizeof(dtStatPolyDetail)*npolys; + const int detailVertsSize = sizeof(float)*3*ndvertsuniq; + const int detailTrisSize = sizeof(unsigned char)*4*ndtris; + + const int dataSize = headerSize + vertsSize + polysSize + nodesSize + + detailMeshesSize + detailVertsSize + detailTrisSize; + unsigned char* data = new unsigned char[dataSize]; + if (!data) + return false; + memset(data, 0, dataSize); + + unsigned char* d = data; + dtStatNavMeshHeader* header = (dtStatNavMeshHeader*)d; d += headerSize; + float* navVerts = (float*)d; d += vertsSize; + dtStatPoly* navPolys = (dtStatPoly*)d; d += polysSize; + dtStatBVNode* navNodes = (dtStatBVNode*)d; d += nodesSize; + dtStatPolyDetail* navDMeshes = (dtStatPolyDetail*)d; d += detailMeshesSize; + float* navDVerts = (float*)d; d += detailVertsSize; + unsigned char* navDTris = (unsigned char*)d; d += detailTrisSize; + + // Store header + header->magic = DT_STAT_NAVMESH_MAGIC; + header->version = DT_STAT_NAVMESH_VERSION; + header->npolys = npolys; + header->nverts = nverts; + header->cs = cs; + header->bmin[0] = bmin[0]; + header->bmin[1] = bmin[1]; + header->bmin[2] = bmin[2]; + header->bmax[0] = bmax[0]; + header->bmax[1] = bmax[1]; + header->bmax[2] = bmax[2]; + header->ndmeshes = npolys; + header->ndverts = ndvertsuniq; + header->ndtris = ndtris; + + // Store vertices + for (int i = 0; i < nverts; ++i) + { + const unsigned short* iv = &vertsi[i*3]; + float* v = &navVerts[i*3]; + v[0] = bmin[0] + iv[0] * cs; + v[1] = bmin[1] + iv[1] * cs; + v[2] = bmin[2] + iv[2] * cs; + } + //memcpy(navVerts, vertices, nverts*3*sizeof(float)); + + // Store polygons + const unsigned short* src = polys; + for (int i = 0; i < npolys; ++i) + { + dtStatPoly* p = &navPolys[i]; + p->nv = 0; + for (int j = 0; j < vertsPerPoly; ++j) + { + if (src[j] == 0xffff) break; + p->v[j] = src[j]; + p->n[j] = src[vertsPerPoly+j]+1; + p->nv++; + } + src += vertsPerPoly*2; + } + + header->nnodes = createBVTree(vertsi, nverts, polys, npolys, vertsPerPoly, + cs, cs, npolys*2, navNodes); + + + if (dmeshes==NULL) + { + //create fake detail meshes + for (int i = 0; i < npolys; ++i) + { + dtStatPolyDetail& dtl = navDMeshes[i]; + dtl.vbase = 0; + dtl.nverts = 0; + dtl.tbase = i; + dtl.ntris = 1; + } + // setup triangles. + unsigned char* tri = navDTris; + for(size_t i=0; i<ndtris; i++) + { + for (size_t j=0; j<3; j++) + tri[4*i+j] = j; + } + } + else + { + //verts + memcpy(navDVerts, dvertices, ndvertsuniq*3*sizeof(float)); + //tris + unsigned char* tri = navDTris; + for(size_t i=0; i<ndtris; i++) + { + for (size_t j=0; j<3; j++) + tri[4*i+j] = dtris[6*i+j]; + } + //detailed meshes + for (int i = 0; i < npolys; ++i) + { + dtStatPolyDetail& dtl = navDMeshes[i]; + dtl.vbase = dmeshes[i*4+0]; + dtl.nverts = dmeshes[i*4+1]; + dtl.tbase = dmeshes[i*4+2]; + dtl.ntris = dmeshes[i*4+3]; + } + } + + m_navMesh = new dtStatNavMesh; + m_navMesh->init(data, dataSize, true); + + delete [] vertices; + delete [] polys; + if (dvertices) + { + delete [] dvertices; + } + + return true; +} + +dtStatNavMesh* KX_NavMeshObject::GetNavMesh() +{ + return m_navMesh; +} + +void KX_NavMeshObject::DrawNavMesh(NavMeshRenderMode renderMode) +{ + if (!m_navMesh) + return; + MT_Vector3 color(0.f, 0.f, 0.f); + + switch (renderMode) + { + case RM_POLYS : + case RM_WALLS : + for (int pi=0; pi<m_navMesh->getPolyCount(); pi++) + { + const dtStatPoly* poly = m_navMesh->getPoly(pi); + + for (int i = 0, j = (int)poly->nv-1; i < (int)poly->nv; j = i++) + { + if (poly->n[j] && renderMode==RM_WALLS) + continue; + const float* vif = m_navMesh->getVertex(poly->v[i]); + const float* vjf = m_navMesh->getVertex(poly->v[j]); + MT_Point3 vi(vif[0], vif[2], vif[1]); + MT_Point3 vj(vjf[0], vjf[2], vjf[1]); + vi = TransformToWorldCoords(vi); + vj = TransformToWorldCoords(vj); + KX_RasterizerDrawDebugLine(vi, vj, color); + } + } + break; + case RM_TRIS : + for (int i = 0; i < m_navMesh->getPolyDetailCount(); ++i) + { + const dtStatPoly* p = m_navMesh->getPoly(i); + const dtStatPolyDetail* pd = m_navMesh->getPolyDetail(i); + + for (int j = 0; j < pd->ntris; ++j) + { + const unsigned char* t = m_navMesh->getDetailTri(pd->tbase+j); + MT_Point3 tri[3]; + for (int k = 0; k < 3; ++k) + { + const float* v; + if (t[k] < p->nv) + v = m_navMesh->getVertex(p->v[t[k]]); + else + v = m_navMesh->getDetailVertex(pd->vbase+(t[k]-p->nv)); + float pos[3]; + vcopy(pos, v); + flipAxes(pos); + tri[k].setValue(pos); + } + + for (int k=0; k<3; k++) + tri[k] = TransformToWorldCoords(tri[k]); + + for (int k=0; k<3; k++) + KX_RasterizerDrawDebugLine(tri[k], tri[(k+1)%3], color); + } + } + break; + default: + /* pass */ + break; + } +} + +MT_Point3 KX_NavMeshObject::TransformToLocalCoords(const MT_Point3& wpos) +{ + MT_Matrix3x3 orientation = NodeGetWorldOrientation(); + const MT_Vector3& scaling = NodeGetWorldScaling(); + orientation.scale(scaling[0], scaling[1], scaling[2]); + MT_Transform worldtr(NodeGetWorldPosition(), orientation); + MT_Transform invworldtr; + invworldtr.invert(worldtr); + MT_Point3 lpos = invworldtr(wpos); + return lpos; +} + +MT_Point3 KX_NavMeshObject::TransformToWorldCoords(const MT_Point3& lpos) +{ + MT_Matrix3x3 orientation = NodeGetWorldOrientation(); + const MT_Vector3& scaling = NodeGetWorldScaling(); + orientation.scale(scaling[0], scaling[1], scaling[2]); + MT_Transform worldtr(NodeGetWorldPosition(), orientation); + MT_Point3 wpos = worldtr(lpos); + return wpos; +} + +int KX_NavMeshObject::FindPath(const MT_Point3& from, const MT_Point3& to, float* path, int maxPathLen) +{ + if (!m_navMesh) + return 0; + MT_Point3 localfrom = TransformToLocalCoords(from); + MT_Point3 localto = TransformToLocalCoords(to); + float spos[3], epos[3]; + localfrom.getValue(spos); flipAxes(spos); + localto.getValue(epos); flipAxes(epos); + dtStatPolyRef sPolyRef = m_navMesh->findNearestPoly(spos, polyPickExt); + dtStatPolyRef ePolyRef = m_navMesh->findNearestPoly(epos, polyPickExt); + + int pathLen = 0; + if (sPolyRef && ePolyRef) + { + dtStatPolyRef* polys = new dtStatPolyRef[maxPathLen]; + int npolys; + npolys = m_navMesh->findPath(sPolyRef, ePolyRef, spos, epos, polys, maxPathLen); + if (npolys) + { + pathLen = m_navMesh->findStraightPath(spos, epos, polys, npolys, path, maxPathLen); + for (int i=0; i<pathLen; i++) + { + flipAxes(&path[i*3]); + MT_Point3 waypoint(&path[i*3]); + waypoint = TransformToWorldCoords(waypoint); + waypoint.getValue(&path[i*3]); + } + } + } + + return pathLen; +} + +float KX_NavMeshObject::Raycast(const MT_Point3& from, const MT_Point3& to) +{ + if (!m_navMesh) + return 0.f; + MT_Point3 localfrom = TransformToLocalCoords(from); + MT_Point3 localto = TransformToLocalCoords(to); + float spos[3], epos[3]; + localfrom.getValue(spos); flipAxes(spos); + localto.getValue(epos); flipAxes(epos); + dtStatPolyRef sPolyRef = m_navMesh->findNearestPoly(spos, polyPickExt); + float t=0; + static dtStatPolyRef polys[MAX_PATH_LEN]; + m_navMesh->raycast(sPolyRef, spos, epos, t, polys, MAX_PATH_LEN); + return t; +} + +void KX_NavMeshObject::DrawPath(const float *path, int pathLen, const MT_Vector3& color) +{ + MT_Vector3 a,b; + for (int i=0; i<pathLen-1; i++) + { + a.setValue(&path[3*i]); + b.setValue(&path[3*(i+1)]); + KX_RasterizerDrawDebugLine(a, b, color); + } +} + + +#ifndef DISABLE_PYTHON +//---------------------------------------------------------------------------- +//Python + +PyTypeObject KX_NavMeshObject::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "KX_NavMeshObject", + 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, + &KX_GameObject::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyAttributeDef KX_NavMeshObject::Attributes[] = { + { NULL } //Sentinel +}; + +//KX_PYMETHODTABLE_NOARGS(KX_GameObject, getD), +PyMethodDef KX_NavMeshObject::Methods[] = { + KX_PYMETHODTABLE(KX_NavMeshObject, findPath), + KX_PYMETHODTABLE(KX_NavMeshObject, raycast), + KX_PYMETHODTABLE(KX_NavMeshObject, draw), + KX_PYMETHODTABLE(KX_NavMeshObject, rebuild), + {NULL,NULL} //Sentinel +}; + +KX_PYMETHODDEF_DOC(KX_NavMeshObject, findPath, + "findPath(start, goal): find path from start to goal points\n" + "Returns a path as list of points)\n") +{ + PyObject *ob_from, *ob_to; + if (!PyArg_ParseTuple(args,"OO:getPath",&ob_from,&ob_to)) + return NULL; + MT_Point3 from, to; + if (!PyVecTo(ob_from, from) || !PyVecTo(ob_to, to)) + return NULL; + + float path[MAX_PATH_LEN*3]; + int pathLen = FindPath(from, to, path, MAX_PATH_LEN); + PyObject *pathList = PyList_New( pathLen ); + for (int i=0; i<pathLen; i++) + { + MT_Point3 point(&path[3*i]); + PyList_SET_ITEM(pathList, i, PyObjectFrom(point)); + } + + return pathList; +} + +KX_PYMETHODDEF_DOC(KX_NavMeshObject, raycast, + "raycast(start, goal): raycast from start to goal points\n" + "Returns hit factor)\n") +{ + PyObject *ob_from, *ob_to; + if (!PyArg_ParseTuple(args,"OO:getPath",&ob_from,&ob_to)) + return NULL; + MT_Point3 from, to; + if (!PyVecTo(ob_from, from) || !PyVecTo(ob_to, to)) + return NULL; + float hit = Raycast(from, to); + return PyFloat_FromDouble(hit); +} + +KX_PYMETHODDEF_DOC(KX_NavMeshObject, draw, + "draw(mode): navigation mesh debug drawing\n" + "mode: WALLS, POLYS, TRIS\n") +{ + int arg; + NavMeshRenderMode renderMode = RM_TRIS; + if (PyArg_ParseTuple(args,"i:rebuild",&arg) && arg>=0 && arg<RM_MAX) + renderMode = (NavMeshRenderMode)arg; + DrawNavMesh(renderMode); + Py_RETURN_NONE; +} + +KX_PYMETHODDEF_DOC_NOARGS(KX_NavMeshObject, rebuild, + "rebuild(): rebuild navigation mesh\n") +{ + BuildNavMesh(); + Py_RETURN_NONE; +} + +#endif // DISABLE_PYTHON diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.h b/source/gameengine/Ketsji/KX_NavMeshObject.h new file mode 100644 index 00000000000..78e9488ad1c --- /dev/null +++ b/source/gameengine/Ketsji/KX_NavMeshObject.h @@ -0,0 +1,83 @@ +/** +* $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL LICENSE BLOCK ***** +*/ +#ifndef __KX_NAVMESHOBJECT +#define __KX_NAVMESHOBJECT +#include "DetourStatNavMesh.h" +#include "KX_GameObject.h" +#include "PyObjectPlus.h" +#include <vector> + +class RAS_MeshObject; +class MT_Transform; + +class KX_NavMeshObject: public KX_GameObject +{ + Py_Header; + +protected: + dtStatNavMesh* m_navMesh; + + bool BuildVertIndArrays(float *&vertices, int& nverts, + unsigned short* &polys, int& npolys, unsigned short *&dmeshes, + float *&dvertices, int &ndvertsuniq, unsigned short* &dtris, + int& ndtris, int &vertsPerPoly); + +public: + KX_NavMeshObject(void* sgReplicationInfo, SG_Callbacks callbacks); + ~KX_NavMeshObject(); + + virtual CValue* GetReplica(); + virtual void ProcessReplica(); + + + bool BuildNavMesh(); + dtStatNavMesh* GetNavMesh(); + int FindPath(const MT_Point3& from, const MT_Point3& to, float* path, int maxPathLen); + float Raycast(const MT_Point3& from, const MT_Point3& to); + + enum NavMeshRenderMode {RM_WALLS, RM_POLYS, RM_TRIS, RM_MAX}; + void DrawNavMesh(NavMeshRenderMode mode); + void DrawPath(const float *path, int pathLen, const MT_Vector3& color); + + MT_Point3 TransformToLocalCoords(const MT_Point3& wpos); + MT_Point3 TransformToWorldCoords(const MT_Point3& lpos); +#ifndef DISABLE_PYTHON + /* --------------------------------------------------------------------- */ + /* Python interface ---------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + + KX_PYMETHOD_DOC(KX_NavMeshObject, findPath); + KX_PYMETHOD_DOC(KX_NavMeshObject, raycast); + KX_PYMETHOD_DOC(KX_NavMeshObject, draw); + KX_PYMETHOD_DOC_NOARGS(KX_NavMeshObject, rebuild); +#endif +}; + +#endif //__KX_NAVMESHOBJECT + diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp index 7289ffc6e29..cb59ef42699 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp @@ -237,9 +237,9 @@ bool KX_ObjectActuator::Update() if (m_current_linear_factor > 1.0) m_current_linear_factor = 1.0; linV = m_current_linear_factor * m_linear_velocity; - parent->setLinearVelocity(linV,(m_bitLocalFlag.LinearVelocity) != 0); + parent->setLinearVelocity(linV,(m_bitLocalFlag.LinearVelocity) != 0); } else { - parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0); + parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0); } } } @@ -260,7 +260,7 @@ bool KX_ObjectActuator::Update() if (m_current_angular_factor > 1.0) m_current_angular_factor = 1.0; angV = m_current_angular_factor * m_angular_velocity; - parent->setAngularVelocity(angV,(m_bitLocalFlag.AngularVelocity) != 0); + parent->setAngularVelocity(angV,(m_bitLocalFlag.AngularVelocity) != 0); } else { parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0); } diff --git a/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp b/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp new file mode 100644 index 00000000000..5f78d9a3722 --- /dev/null +++ b/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp @@ -0,0 +1,869 @@ +/** +* Simulation for obstacle avoidance behavior +* +* $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. The Blender +* Foundation also sells licenses for use in proprietary software under +* the Blender License. See http://www.blender.org/BL/ for information +* about this. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#include "KX_ObstacleSimulation.h" +#include "KX_NavMeshObject.h" +#include "KX_PythonInit.h" +#include "DNA_object_types.h" +#include "BLI_math.h" + +namespace +{ + inline float perp(const MT_Vector2& a, const MT_Vector2& b) { return a.x()*b.y() - a.y()*b.x(); } + + inline float sqr(float x) { return x*x; } + inline float lerp(float a, float b, float t) { return a + (b-a)*t; } + inline float clamp(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); } + + inline float vdistsqr(const float* a, const float* b) { return sqr(b[0]-a[0]) + sqr(b[1]-a[1]); } + inline float vdist(const float* a, const float* b) { return sqrtf(vdistsqr(a,b)); } + inline void vcpy(float* a, const float* b) { a[0]=b[0]; a[1]=b[1]; } + inline float vdot(const float* a, const float* b) { return a[0]*b[0] + a[1]*b[1]; } + inline float vperp(const float* a, const float* b) { return a[0]*b[1] - a[1]*b[0]; } + inline void vsub(float* v, const float* a, const float* b) { v[0] = a[0]-b[0]; v[1] = a[1]-b[1]; } + inline void vadd(float* v, const float* a, const float* b) { v[0] = a[0]+b[0]; v[1] = a[1]+b[1]; } + inline void vscale(float* v, const float* a, const float s) { v[0] = a[0]*s; v[1] = a[1]*s; } + inline void vset(float* v, float x, float y) { v[0]=x; v[1]=y; } + inline float vlensqr(const float* v) { return vdot(v,v); } + inline float vlen(const float* v) { return sqrtf(vlensqr(v)); } + inline void vlerp(float* v, const float* a, const float* b, float t) { v[0] = lerp(a[0], b[0], t); v[1] = lerp(a[1], b[1], t); } + inline void vmad(float* v, const float* a, const float* b, float s) { v[0] = a[0] + b[0]*s; v[1] = a[1] + b[1]*s; } + inline void vnorm(float* v) + { + float d = vlen(v); + if (d > 0.0001f) + { + d = 1.0f/d; + v[0] *= d; + v[1] *= d; + } + } +} +inline float triarea(const float* a, const float* b, const float* c) +{ + return (b[0]*a[1] - a[0]*b[1]) + (c[0]*b[1] - b[0]*c[1]) + (a[0]*c[1] - c[0]*a[1]); +} + +static void closestPtPtSeg(const float* pt, + const float* sp, const float* sq, + float& t) +{ + float dir[2],diff[3]; + vsub(dir,sq,sp); + vsub(diff,pt,sp); + t = vdot(diff,dir); + if (t <= 0.0f) { t = 0; return; } + float d = vdot(dir,dir); + if (t >= d) { t = 1; return; } + t /= d; +} + +static float distPtSegSqr(const float* pt, const float* sp, const float* sq) +{ + float t; + closestPtPtSeg(pt, sp,sq, t); + float np[2]; + vlerp(np, sp,sq, t); + return vdistsqr(pt,np); +} + +static int sweepCircleCircle(const MT_Vector3& pos0, const MT_Scalar r0, const MT_Vector2& v, + const MT_Vector3& pos1, const MT_Scalar r1, + float& tmin, float& tmax) +{ + static const float EPS = 0.0001f; + MT_Vector2 c0(pos0.x(), pos0.y()); + MT_Vector2 c1(pos1.x(), pos1.y()); + MT_Vector2 s = c1 - c0; + MT_Scalar r = r0+r1; + float c = s.length2() - r*r; + float a = v.length2(); + if (a < EPS) return 0; // not moving + + // Overlap, calc time to exit. + float b = MT_dot(v,s); + float d = b*b - a*c; + if (d < 0.0f) return 0; // no intersection. + tmin = (b - sqrtf(d)) / a; + tmax = (b + sqrtf(d)) / a; + return 1; +} + +static int sweepCircleSegment(const MT_Vector3& pos0, const MT_Scalar r0, const MT_Vector2& v, + const MT_Vector3& pa, const MT_Vector3& pb, const MT_Scalar sr, + float& tmin, float &tmax) +{ + // equation parameters + MT_Vector2 c0(pos0.x(), pos0.y()); + MT_Vector2 sa(pa.x(), pa.y()); + MT_Vector2 sb(pb.x(), pb.y()); + MT_Vector2 L = sb-sa; + MT_Vector2 H = c0-sa; + MT_Scalar radius = r0+sr; + float l2 = L.length2(); + float r2 = radius * radius; + float dl = perp(v, L); + float hl = perp(H, L); + float a = dl * dl; + float b = 2.0f * hl * dl; + float c = hl * hl - (r2 * l2); + float d = (b*b) - (4.0f * a * c); + + // infinite line missed by infinite ray. + if (d < 0.0f) + return 0; + + d = sqrtf(d); + tmin = (-b - d) / (2.0f * a); + tmax = (-b + d) / (2.0f * a); + + // line missed by ray range. + /* if (tmax < 0.0f || tmin > 1.0f) + return 0;*/ + + // find what part of the ray was collided. + MT_Vector2 Pedge; + Pedge = c0+v*tmin; + H = Pedge - sa; + float e0 = MT_dot(H, L) / l2; + Pedge = c0 + v*tmax; + H = Pedge - sa; + float e1 = MT_dot(H, L) / l2; + + if (e0 < 0.0f || e1 < 0.0f) + { + float ctmin, ctmax; + if (sweepCircleCircle(pos0, r0, v, pa, sr, ctmin, ctmax)) + { + if (e0 < 0.0f && ctmin > tmin) + tmin = ctmin; + if (e1 < 0.0f && ctmax < tmax) + tmax = ctmax; + } + else + { + return 0; + } + } + + if (e0 > 1.0f || e1 > 1.0f) + { + float ctmin, ctmax; + if (sweepCircleCircle(pos0, r0, v, pb, sr, ctmin, ctmax)) + { + if (e0 > 1.0f && ctmin > tmin) + tmin = ctmin; + if (e1 > 1.0f && ctmax < tmax) + tmax = ctmax; + } + else + { + return 0; + } + } + + return 1; +} + +static bool inBetweenAngle(float a, float amin, float amax, float& t) +{ + if (amax < amin) amax += (float)M_PI*2; + if (a < amin-(float)M_PI) a += (float)M_PI*2; + if (a > amin+(float)M_PI) a -= (float)M_PI*2; + if (a >= amin && a < amax) + { + t = (a-amin) / (amax-amin); + return true; + } + return false; +} + +static float interpolateToi(float a, const float* dir, const float* toi, const int ntoi) +{ + for (int i = 0; i < ntoi; ++i) + { + int next = (i+1) % ntoi; + float t; + if (inBetweenAngle(a, dir[i], dir[next], t)) + { + return lerp(toi[i], toi[next], t); + } + } + return 0; +} + +KX_ObstacleSimulation::KX_ObstacleSimulation(MT_Scalar levelHeight, bool enableVisualization) +: m_levelHeight(levelHeight) +, m_enableVisualization(enableVisualization) +{ + +} + +KX_ObstacleSimulation::~KX_ObstacleSimulation() +{ + for (size_t i=0; i<m_obstacles.size(); i++) + { + KX_Obstacle* obs = m_obstacles[i]; + delete obs; + } + m_obstacles.clear(); +} +KX_Obstacle* KX_ObstacleSimulation::CreateObstacle(KX_GameObject* gameobj) +{ + KX_Obstacle* obstacle = new KX_Obstacle(); + obstacle->m_gameObj = gameobj; + + vset(obstacle->vel, 0,0); + vset(obstacle->pvel, 0,0); + vset(obstacle->dvel, 0,0); + vset(obstacle->nvel, 0,0); + for (int i = 0; i < VEL_HIST_SIZE; ++i) + vset(&obstacle->hvel[i*2], 0,0); + obstacle->hhead = 0; + + gameobj->RegisterObstacle(this); + m_obstacles.push_back(obstacle); + return obstacle; +} + +void KX_ObstacleSimulation::AddObstacleForObj(KX_GameObject* gameobj) +{ + KX_Obstacle* obstacle = CreateObstacle(gameobj); + struct Object* blenderobject = gameobj->GetBlenderObject(); + obstacle->m_type = KX_OBSTACLE_OBJ; + obstacle->m_shape = KX_OBSTACLE_CIRCLE; + obstacle->m_rad = blenderobject->obstacleRad; +} + +void KX_ObstacleSimulation::AddObstaclesForNavMesh(KX_NavMeshObject* navmeshobj) +{ + dtStatNavMesh* navmesh = navmeshobj->GetNavMesh(); + if (navmesh) + { + int npoly = navmesh->getPolyCount(); + for (int pi=0; pi<npoly; pi++) + { + const dtStatPoly* poly = navmesh->getPoly(pi); + + for (int i = 0, j = (int)poly->nv-1; i < (int)poly->nv; j = i++) + { + if (poly->n[j]) continue; + const float* vj = navmesh->getVertex(poly->v[j]); + const float* vi = navmesh->getVertex(poly->v[i]); + + KX_Obstacle* obstacle = CreateObstacle(navmeshobj); + obstacle->m_type = KX_OBSTACLE_NAV_MESH; + obstacle->m_shape = KX_OBSTACLE_SEGMENT; + obstacle->m_pos = MT_Point3(vj[0], vj[2], vj[1]); + obstacle->m_pos2 = MT_Point3(vi[0], vi[2], vi[1]); + obstacle->m_rad = 0; + } + } + } +} + +void KX_ObstacleSimulation::DestroyObstacleForObj(KX_GameObject* gameobj) +{ + for (size_t i=0; i<m_obstacles.size(); ) + { + if (m_obstacles[i]->m_gameObj == gameobj) + { + KX_Obstacle* obstacle = m_obstacles[i]; + obstacle->m_gameObj->UnregisterObstacle(); + m_obstacles[i] = m_obstacles.back(); + m_obstacles.pop_back(); + delete obstacle; + } + else + i++; + } +} + +void KX_ObstacleSimulation::UpdateObstacles() +{ + for (size_t i=0; i<m_obstacles.size(); i++) + { + if (m_obstacles[i]->m_type==KX_OBSTACLE_NAV_MESH || m_obstacles[i]->m_shape==KX_OBSTACLE_SEGMENT) + continue; + + KX_Obstacle* obs = m_obstacles[i]; + obs->m_pos = obs->m_gameObj->NodeGetWorldPosition(); + obs->vel[0] = obs->m_gameObj->GetLinearVelocity().x(); + obs->vel[1] = obs->m_gameObj->GetLinearVelocity().y(); + + // Update velocity history and calculate perceived (average) velocity. + vcpy(&obs->hvel[obs->hhead*2], obs->vel); + obs->hhead = (obs->hhead+1) % VEL_HIST_SIZE; + vset(obs->pvel,0,0); + for (int j = 0; j < VEL_HIST_SIZE; ++j) + vadd(obs->pvel, obs->pvel, &obs->hvel[j*2]); + vscale(obs->pvel, obs->pvel, 1.0f/VEL_HIST_SIZE); + } +} + +KX_Obstacle* KX_ObstacleSimulation::GetObstacle(KX_GameObject* gameobj) +{ + for (size_t i=0; i<m_obstacles.size(); i++) + { + if (m_obstacles[i]->m_gameObj == gameobj) + return m_obstacles[i]; + } + + return NULL; +} + +void KX_ObstacleSimulation::AdjustObstacleVelocity(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + MT_Vector3& velocity, MT_Scalar maxDeltaSpeed,MT_Scalar maxDeltaAngle) +{ +} + +void KX_ObstacleSimulation::DrawObstacles() +{ + if (!m_enableVisualization) + return; + static const MT_Vector3 bluecolor(0,0,1); + static const MT_Vector3 normal(0.,0.,1.); + static const int SECTORS_NUM = 32; + for (size_t i=0; i<m_obstacles.size(); i++) + { + if (m_obstacles[i]->m_shape==KX_OBSTACLE_SEGMENT) + { + MT_Point3 p1 = m_obstacles[i]->m_pos; + MT_Point3 p2 = m_obstacles[i]->m_pos2; + //apply world transform + if (m_obstacles[i]->m_type == KX_OBSTACLE_NAV_MESH) + { + KX_NavMeshObject* navmeshobj = static_cast<KX_NavMeshObject*>(m_obstacles[i]->m_gameObj); + p1 = navmeshobj->TransformToWorldCoords(p1); + p2 = navmeshobj->TransformToWorldCoords(p2); + } + + KX_RasterizerDrawDebugLine(p1, p2, bluecolor); + } + else if (m_obstacles[i]->m_shape==KX_OBSTACLE_CIRCLE) + { + KX_RasterizerDrawDebugCircle(m_obstacles[i]->m_pos, m_obstacles[i]->m_rad, bluecolor, + normal, SECTORS_NUM); + } + } +} + +static MT_Point3 nearestPointToObstacle(MT_Point3& pos ,KX_Obstacle* obstacle) +{ + switch (obstacle->m_shape) + { + case KX_OBSTACLE_SEGMENT : + { + MT_Vector3 ab = obstacle->m_pos2 - obstacle->m_pos; + if (!ab.fuzzyZero()) + { + MT_Vector3 abdir = ab.normalized(); + MT_Vector3 v = pos - obstacle->m_pos; + MT_Scalar proj = abdir.dot(v); + CLAMP(proj, 0, ab.length()); + MT_Point3 res = obstacle->m_pos + abdir*proj; + return res; + } + } + case KX_OBSTACLE_CIRCLE : + default: + return obstacle->m_pos; + } +} + +static bool filterObstacle(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, KX_Obstacle* otherObst, + float levelHeight) +{ + //filter obstacles by type + if ( (otherObst == activeObst) || + (otherObst->m_type==KX_OBSTACLE_NAV_MESH && otherObst->m_gameObj!=activeNavMeshObj) ) + return false; + + //filter obstacles by position + MT_Point3 p = nearestPointToObstacle(activeObst->m_pos, otherObst); + if ( fabs(activeObst->m_pos.z() - p.z()) > levelHeight) + return false; + + return true; +} + +///////////*********TOI_rays**********///////////////// +KX_ObstacleSimulationTOI::KX_ObstacleSimulationTOI(MT_Scalar levelHeight, bool enableVisualization) +: KX_ObstacleSimulation(levelHeight, enableVisualization), + m_maxSamples(32), + m_minToi(0.0f), + m_maxToi(0.0f), + m_velWeight(1.0f), + m_curVelWeight(1.0f), + m_toiWeight(1.0f), + m_collisionWeight(1.0f) +{ +} + + +void KX_ObstacleSimulationTOI::AdjustObstacleVelocity(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + MT_Vector3& velocity, MT_Scalar maxDeltaSpeed, MT_Scalar maxDeltaAngle) +{ + int nobs = m_obstacles.size(); + int obstidx = std::find(m_obstacles.begin(), m_obstacles.end(), activeObst) - m_obstacles.begin(); + if (obstidx == nobs) + return; + + vset(activeObst->dvel, velocity.x(), velocity.y()); + + //apply RVO + sampleRVO(activeObst, activeNavMeshObj, maxDeltaAngle); + + // Fake dynamic constraint. + float dv[2]; + float vel[2]; + vsub(dv, activeObst->nvel, activeObst->vel); + float ds = vlen(dv); + if (ds > maxDeltaSpeed || ds<-maxDeltaSpeed) + vscale(dv, dv, fabs(maxDeltaSpeed/ds)); + vadd(vel, activeObst->vel, dv); + + velocity.x() = vel[0]; + velocity.y() = vel[1]; +} + +///////////*********TOI_rays**********///////////////// +static const int AVOID_MAX_STEPS = 128; +struct TOICircle +{ + TOICircle() : n(0), minToi(0), maxToi(1) {} + float toi[AVOID_MAX_STEPS]; // Time of impact (seconds) + float toie[AVOID_MAX_STEPS]; // Time of exit (seconds) + float dir[AVOID_MAX_STEPS]; // Direction (radians) + int n; // Number of samples + float minToi, maxToi; // Min/max TOI (seconds) +}; + +KX_ObstacleSimulationTOI_rays::KX_ObstacleSimulationTOI_rays(MT_Scalar levelHeight, bool enableVisualization): + KX_ObstacleSimulationTOI(levelHeight, enableVisualization) +{ + m_maxSamples = 32; + m_minToi = 0.5f; + m_maxToi = 1.2f; + m_velWeight = 4.0f; + m_toiWeight = 1.0f; + m_collisionWeight = 100.0f; +} + + +void KX_ObstacleSimulationTOI_rays::sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + const float maxDeltaAngle) +{ + MT_Vector2 vel(activeObst->dvel[0], activeObst->dvel[1]); + float vmax = (float) vel.length(); + float odir = (float) atan2(vel.y(), vel.x()); + + MT_Vector2 ddir = vel; + ddir.normalize(); + + float bestScore = FLT_MAX; + float bestDir = odir; + float bestToi = 0; + + TOICircle tc; + tc.n = m_maxSamples; + tc.minToi = m_minToi; + tc.maxToi = m_maxToi; + + const int iforw = m_maxSamples/2; + const float aoff = (float)iforw / (float)m_maxSamples; + + size_t nobs = m_obstacles.size(); + for (int iter = 0; iter < m_maxSamples; ++iter) + { + // Calculate sample velocity + const float ndir = ((float)iter/(float)m_maxSamples) - aoff; + const float dir = odir+ndir*M_PI*2; + MT_Vector2 svel; + svel.x() = cosf(dir) * vmax; + svel.y() = sinf(dir) * vmax; + + // Find min time of impact and exit amongst all obstacles. + float tmin = m_maxToi; + float tmine = 0; + for (int i = 0; i < nobs; ++i) + { + KX_Obstacle* ob = m_obstacles[i]; + bool res = filterObstacle(activeObst, activeNavMeshObj, ob, m_levelHeight); + if (!res) + continue; + + float htmin,htmax; + + if (ob->m_shape == KX_OBSTACLE_CIRCLE) + { + MT_Vector2 vab; + if (vlen(ob->vel) < 0.01f*0.01f) + { + // Stationary, use VO + vab = svel; + } + else + { + // Moving, use RVO + vab = 2*svel - vel - ob->vel; + } + + if (!sweepCircleCircle(activeObst->m_pos, activeObst->m_rad, + vab, ob->m_pos, ob->m_rad, htmin, htmax)) + continue; + } + else if (ob->m_shape == KX_OBSTACLE_SEGMENT) + { + MT_Point3 p1 = ob->m_pos; + MT_Point3 p2 = ob->m_pos2; + //apply world transform + if (ob->m_type == KX_OBSTACLE_NAV_MESH) + { + KX_NavMeshObject* navmeshobj = static_cast<KX_NavMeshObject*>(ob->m_gameObj); + p1 = navmeshobj->TransformToWorldCoords(p1); + p2 = navmeshobj->TransformToWorldCoords(p2); + } + if (!sweepCircleSegment(activeObst->m_pos, activeObst->m_rad, svel, + p1, p2, ob->m_rad, htmin, htmax)) + continue; + } + + if (htmin > 0.0f) + { + // The closest obstacle is somewhere ahead of us, keep track of nearest obstacle. + if (htmin < tmin) + tmin = htmin; + } + else if (htmax > 0.0f) + { + // The agent overlaps the obstacle, keep track of first safe exit. + if (htmax > tmine) + tmine = htmax; + } + } + + // Calculate sample penalties and final score. + const float apen = m_velWeight * fabsf(ndir); + const float tpen = m_toiWeight * (1.0f/(0.0001f+tmin/m_maxToi)); + const float cpen = m_collisionWeight * (tmine/m_minToi)*(tmine/m_minToi); + const float score = apen + tpen + cpen; + + // Update best score. + if (score < bestScore) + { + bestDir = dir; + bestToi = tmin; + bestScore = score; + } + + tc.dir[iter] = dir; + tc.toi[iter] = tmin; + tc.toie[iter] = tmine; + } + + if (vlen(activeObst->vel) > 0.1) + { + // Constrain max turn rate. + float cura = atan2(activeObst->vel[1],activeObst->vel[0]); + float da = bestDir - cura; + if (da < -M_PI) da += (float)M_PI*2; + if (da > M_PI) da -= (float)M_PI*2; + if (da < -maxDeltaAngle) + { + bestDir = cura - maxDeltaAngle; + bestToi = min(bestToi, interpolateToi(bestDir, tc.dir, tc.toi, tc.n)); + } + else if (da > maxDeltaAngle) + { + bestDir = cura + maxDeltaAngle; + bestToi = min(bestToi, interpolateToi(bestDir, tc.dir, tc.toi, tc.n)); + } + } + + // Adjust speed when time of impact is less than min TOI. + if (bestToi < m_minToi) + vmax *= bestToi/m_minToi; + + // New steering velocity. + activeObst->nvel[0] = cosf(bestDir) * vmax; + activeObst->nvel[1] = sinf(bestDir) * vmax; +} + +///////////********* TOI_cells**********///////////////// + +static void processSamples(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + KX_Obstacles& obstacles, float levelHeight, const float vmax, + const float* spos, const float cs, const int nspos, float* res, + float maxToi, float velWeight, float curVelWeight, float sideWeight, + float toiWeight) +{ + vset(res, 0,0); + + const float ivmax = 1.0f / vmax; + + float adir[2], adist; + vcpy(adir, activeObst->pvel); + if (vlen(adir) > 0.01f) + vnorm(adir); + else + vset(adir,0,0); + float activeObstPos[2]; + vset(activeObstPos, activeObst->m_pos.x(), activeObst->m_pos.y()); + adist = vdot(adir, activeObstPos); + + float minPenalty = FLT_MAX; + + for (int n = 0; n < nspos; ++n) + { + float vcand[2]; + vcpy(vcand, &spos[n*2]); + + // Find min time of impact and exit amongst all obstacles. + float tmin = maxToi; + float side = 0; + int nside = 0; + + for (int i = 0; i < obstacles.size(); ++i) + { + KX_Obstacle* ob = obstacles[i]; + bool res = filterObstacle(activeObst, activeNavMeshObj, ob, levelHeight); + if (!res) + continue; + float htmin, htmax; + + if (ob->m_shape==KX_OBSTACLE_CIRCLE) + { + float vab[2]; + + // Moving, use RVO + vscale(vab, vcand, 2); + vsub(vab, vab, activeObst->vel); + vsub(vab, vab, ob->vel); + + // Side + // NOTE: dp, and dv are constant over the whole calculation, + // they can be precomputed per object. + const float* pa = activeObstPos; + float pb[2]; + vset(pb, ob->m_pos.x(), ob->m_pos.y()); + + const float orig[2] = {0,0}; + float dp[2],dv[2],np[2]; + vsub(dp,pb,pa); + vnorm(dp); + vsub(dv,ob->dvel, activeObst->dvel); + + const float a = triarea(orig, dp,dv); + if (a < 0.01f) + { + np[0] = -dp[1]; + np[1] = dp[0]; + } + else + { + np[0] = dp[1]; + np[1] = -dp[0]; + } + + side += clamp(min(vdot(dp,vab)*2,vdot(np,vab)*2), 0.0f, 1.0f); + nside++; + + if (!sweepCircleCircle(activeObst->m_pos, activeObst->m_rad, vab, ob->m_pos, ob->m_rad, + htmin, htmax)) + continue; + + // Handle overlapping obstacles. + if (htmin < 0.0f && htmax > 0.0f) + { + // Avoid more when overlapped. + htmin = -htmin * 0.5f; + } + } + else if (ob->m_shape == KX_OBSTACLE_SEGMENT) + { + MT_Point3 p1 = ob->m_pos; + MT_Point3 p2 = ob->m_pos2; + //apply world transform + if (ob->m_type == KX_OBSTACLE_NAV_MESH) + { + KX_NavMeshObject* navmeshobj = static_cast<KX_NavMeshObject*>(ob->m_gameObj); + p1 = navmeshobj->TransformToWorldCoords(p1); + p2 = navmeshobj->TransformToWorldCoords(p2); + } + float p[2], q[2]; + vset(p, p1.x(), p1.y()); + vset(q, p2.x(), p2.y()); + + // NOTE: the segments are assumed to come from a navmesh which is shrunken by + // the agent radius, hence the use of really small radius. + // This can be handle more efficiently by using seg-seg test instead. + // If the whole segment is to be treated as obstacle, use agent->rad instead of 0.01f! + const float r = 0.01f; // agent->rad + if (distPtSegSqr(activeObstPos, p, q) < sqr(r+ob->m_rad)) + { + float sdir[2], snorm[2]; + vsub(sdir, q, p); + snorm[0] = sdir[1]; + snorm[1] = -sdir[0]; + // If the velocity is pointing towards the segment, no collision. + if (vdot(snorm, vcand) < 0.0f) + continue; + // Else immediate collision. + htmin = 0.0f; + htmax = 10.0f; + } + else + { + if (!sweepCircleSegment(activeObstPos, r, vcand, p, q, ob->m_rad, htmin, htmax)) + continue; + } + + // Avoid less when facing walls. + htmin *= 2.0f; + } + + if (htmin >= 0.0f) + { + // The closest obstacle is somewhere ahead of us, keep track of nearest obstacle. + if (htmin < tmin) + tmin = htmin; + } + } + + // Normalize side bias, to prevent it dominating too much. + if (nside) + side /= nside; + + const float vpen = velWeight * (vdist(vcand, activeObst->dvel) * ivmax); + const float vcpen = curVelWeight * (vdist(vcand, activeObst->vel) * ivmax); + const float spen = sideWeight * side; + const float tpen = toiWeight * (1.0f/(0.1f+tmin/maxToi)); + + const float penalty = vpen + vcpen + spen + tpen; + + if (penalty < minPenalty) + { + minPenalty = penalty; + vcpy(res, vcand); + } + } +} + +void KX_ObstacleSimulationTOI_cells::sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + const float maxDeltaAngle) +{ + vset(activeObst->nvel, 0.f, 0.f); + float vmax = vlen(activeObst->dvel); + + float* spos = new float[2*m_maxSamples]; + int nspos = 0; + + if (!m_adaptive) + { + const float cvx = activeObst->dvel[0]*m_bias; + const float cvy = activeObst->dvel[1]*m_bias; + float vmax = vlen(activeObst->dvel); + const float vrange = vmax*(1-m_bias); + const float cs = 1.0f / (float)m_sampleRadius*vrange; + + for (int y = -m_sampleRadius; y <= m_sampleRadius; ++y) + { + for (int x = -m_sampleRadius; x <= m_sampleRadius; ++x) + { + if (nspos < m_maxSamples) + { + const float vx = cvx + (float)(x+0.5f)*cs; + const float vy = cvy + (float)(y+0.5f)*cs; + if (vx*vx+vy*vy > sqr(vmax+cs/2)) continue; + spos[nspos*2+0] = vx; + spos[nspos*2+1] = vy; + nspos++; + } + } + } + processSamples(activeObst, activeNavMeshObj, m_obstacles, m_levelHeight, vmax, spos, cs/2, + nspos, activeObst->nvel, m_maxToi, m_velWeight, m_curVelWeight, m_collisionWeight, m_toiWeight); + } + else + { + int rad; + float res[2]; + float cs; + // First sample location. + rad = 4; + res[0] = activeObst->dvel[0]*m_bias; + res[1] = activeObst->dvel[1]*m_bias; + cs = vmax*(2-m_bias*2) / (float)(rad-1); + + for (int k = 0; k < 5; ++k) + { + const float half = (rad-1)*cs*0.5f; + + nspos = 0; + for (int y = 0; y < rad; ++y) + { + for (int x = 0; x < rad; ++x) + { + const float vx = res[0] + x*cs - half; + const float vy = res[1] + y*cs - half; + if (vx*vx+vy*vy > sqr(vmax+cs/2)) continue; + spos[nspos*2+0] = vx; + spos[nspos*2+1] = vy; + nspos++; + } + } + + processSamples(activeObst, activeNavMeshObj, m_obstacles, m_levelHeight, vmax, spos, cs/2, + nspos, res, m_maxToi, m_velWeight, m_curVelWeight, m_collisionWeight, m_toiWeight); + + cs *= 0.5f; + } + vcpy(activeObst->nvel, res); + } +} + +KX_ObstacleSimulationTOI_cells::KX_ObstacleSimulationTOI_cells(MT_Scalar levelHeight, bool enableVisualization) +: KX_ObstacleSimulationTOI(levelHeight, enableVisualization) +, m_bias(0.4f) +, m_adaptive(true) +, m_sampleRadius(15) +{ + m_maxSamples = (m_sampleRadius*2+1)*(m_sampleRadius*2+1) + 100; + m_maxToi = 1.5f; + m_velWeight = 2.0f; + m_curVelWeight = 0.75f; + m_toiWeight = 2.5f; + m_collisionWeight = 0.75f; //side_weight +} diff --git a/source/gameengine/Ketsji/KX_ObstacleSimulation.h b/source/gameengine/Ketsji/KX_ObstacleSimulation.h new file mode 100644 index 00000000000..d926e8deb71 --- /dev/null +++ b/source/gameengine/Ketsji/KX_ObstacleSimulation.h @@ -0,0 +1,145 @@ +/** +* Simulation for obstacle avoidance behavior +* (based on Cane Project - http://code.google.com/p/cane by Mikko Mononen (c) 2009) +* +* +* $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. The Blender +* Foundation also sells licenses for use in proprietary software under +* the Blender License. See http://www.blender.org/BL/ for information +* about this. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#ifndef __KX_OBSTACLESIMULATION +#define __KX_OBSTACLESIMULATION + +#include <vector> +#include "MT_Point2.h" +#include "MT_Point3.h" + +class KX_GameObject; +class KX_NavMeshObject; + +enum KX_OBSTACLE_TYPE +{ + KX_OBSTACLE_OBJ, + KX_OBSTACLE_NAV_MESH, +}; + +enum KX_OBSTACLE_SHAPE +{ + KX_OBSTACLE_CIRCLE, + KX_OBSTACLE_SEGMENT, +}; + +#define VEL_HIST_SIZE 6 +struct KX_Obstacle +{ + KX_OBSTACLE_TYPE m_type; + KX_OBSTACLE_SHAPE m_shape; + MT_Point3 m_pos; + MT_Point3 m_pos2; + MT_Scalar m_rad; + + float vel[2]; + float pvel[2]; + float dvel[2]; + float nvel[2]; + float hvel[VEL_HIST_SIZE*2]; + int hhead; + + + KX_GameObject* m_gameObj; +}; +typedef std::vector<KX_Obstacle*> KX_Obstacles; + +class KX_ObstacleSimulation +{ +protected: + KX_Obstacles m_obstacles; + + MT_Scalar m_levelHeight; + bool m_enableVisualization; + + KX_Obstacle* CreateObstacle(KX_GameObject* gameobj); +public: + KX_ObstacleSimulation(MT_Scalar levelHeight, bool enableVisualization); + virtual ~KX_ObstacleSimulation(); + + void DrawObstacles(); + //void DebugDraw(); + + void AddObstacleForObj(KX_GameObject* gameobj); + void DestroyObstacleForObj(KX_GameObject* gameobj); + void AddObstaclesForNavMesh(KX_NavMeshObject* navmesh); + KX_Obstacle* GetObstacle(KX_GameObject* gameobj); + void UpdateObstacles(); + virtual void AdjustObstacleVelocity(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + MT_Vector3& velocity, MT_Scalar maxDeltaSpeed,MT_Scalar maxDeltaAngle); + +}; +class KX_ObstacleSimulationTOI: public KX_ObstacleSimulation +{ +protected: + int m_maxSamples; // Number of sample steps + float m_minToi; // Min TOI + float m_maxToi; // Max TOI + float m_velWeight; // Sample selection angle weight + float m_curVelWeight; // Sample selection current velocity weight + float m_toiWeight; // Sample selection TOI weight + float m_collisionWeight; // Sample selection collision weight + + virtual void sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + const float maxDeltaAngle) = 0; +public: + KX_ObstacleSimulationTOI(MT_Scalar levelHeight, bool enableVisualization); + virtual void AdjustObstacleVelocity(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + MT_Vector3& velocity, MT_Scalar maxDeltaSpeed,MT_Scalar maxDeltaAngle); +}; + +class KX_ObstacleSimulationTOI_rays: public KX_ObstacleSimulationTOI +{ +protected: + virtual void sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + const float maxDeltaAngle); +public: + KX_ObstacleSimulationTOI_rays(MT_Scalar levelHeight, bool enableVisualization); +}; + +class KX_ObstacleSimulationTOI_cells: public KX_ObstacleSimulationTOI +{ +protected: + float m_bias; + bool m_adaptive; + int m_sampleRadius; + virtual void sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + const float maxDeltaAngle); +public: + KX_ObstacleSimulationTOI_cells(MT_Scalar levelHeight, bool enableVisualization); +}; + +#endif diff --git a/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp b/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp index d9483083aa1..bd743159950 100644 --- a/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp +++ b/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp @@ -51,6 +51,6 @@ void KX_OrientationInterpolator::Execute(float currentTime) const { MT_Scalar ss = si*sh; m_target.setValue(cj*ch, sj*sc-cs, sj*cc+ss, - cj*sh, sj*ss+cc, sj*cs-sc, - -sj, cj*si, cj*ci); + cj*sh, sj*ss+cc, sj*cs-sc, + -sj, cj*si, cj*ci); } diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp index 9d0597051ad..d32f267f0e0 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp @@ -187,7 +187,7 @@ void KX_PolygonMaterial::DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& c rasty->SetCullFace(true); if ((m_drawingmode & RAS_IRasterizer::KX_LINES) || - (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) + (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) rasty->SetLines(true); else rasty->SetLines(false); diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 395e2048cb7..62ca2910c60 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -87,6 +87,8 @@ extern "C" { #include "KX_GameActuator.h" #include "KX_ParentActuator.h" #include "KX_SCA_DynamicActuator.h" +#include "KX_SteeringActuator.h" +#include "KX_NavMeshObject.h" #include "SCA_IInputDevice.h" #include "SCA_PropertySensor.h" @@ -181,6 +183,13 @@ void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,cons gp_Rasterizer->DrawDebugLine(from,to,color); } +void KX_RasterizerDrawDebugCircle(const MT_Vector3& center, const MT_Scalar radius, const MT_Vector3& color, + const MT_Vector3& normal, int nsector) +{ + if (gp_Rasterizer) + gp_Rasterizer->DrawDebugCircle(center, radius, color, normal, nsector); +} + #ifdef WITH_PYTHON static PyObject *gp_OrigPythonSysPath= NULL; @@ -725,7 +734,7 @@ static PyObject *gLibNew(PyObject*, PyObject* args) if(idcode==ID_ME) { PyObject *ret= PyList_New(0); PyObject *item; - for(int i= 0; i < PyList_GET_SIZE(names); i++) { + for(Py_ssize_t i= 0; i < PyList_GET_SIZE(names); i++) { name= _PyUnicode_AsString(PyList_GET_ITEM(names, i)); if(name) { RAS_MeshObject *meshobj= kx_scene->GetSceneConverter()->ConvertMeshSpecial(kx_scene, maggie, name); @@ -1104,7 +1113,7 @@ static PyObject* gPySetGLSLMaterialSetting(PyObject*, PyObject* args, PyObject*) { - GameData *gm= &(gp_KetsjiScene->GetBlenderScene()->gm); + GlobalSettings *gs= gp_KetsjiEngine->GetGlobalSettings(); char *setting; int enable, flag, sceneflag; @@ -1118,15 +1127,15 @@ static PyObject* gPySetGLSLMaterialSetting(PyObject*, return NULL; } - sceneflag= gm->flag; + sceneflag= gs->glslflag; if (enable) - gm->flag &= ~flag; + gs->glslflag &= ~flag; else - gm->flag |= flag; + gs->glslflag |= flag; /* display lists and GLSL materials need to be remade */ - if(sceneflag != gm->flag) { + if(sceneflag != gs->glslflag) { GPU_materials_free(); if(gp_KetsjiEngine) { KX_SceneList *scenes = gp_KetsjiEngine->CurrentScenes(); @@ -1147,7 +1156,7 @@ static PyObject* gPyGetGLSLMaterialSetting(PyObject*, PyObject* args, PyObject*) { - GameData *gm= &(gp_KetsjiScene->GetBlenderScene()->gm); + GlobalSettings *gs= gp_KetsjiEngine->GetGlobalSettings(); char *setting; int enabled = 0, flag; @@ -1161,7 +1170,7 @@ static PyObject* gPyGetGLSLMaterialSetting(PyObject*, return NULL; } - enabled = ((gm->flag & flag) != 0); + enabled = ((gs->glslflag & flag) != 0); return PyLong_FromSsize_t(enabled); } @@ -1173,18 +1182,18 @@ static PyObject* gPySetMaterialType(PyObject*, PyObject* args, PyObject*) { - GameData *gm= &(gp_KetsjiScene->GetBlenderScene()->gm); + GlobalSettings *gs= gp_KetsjiEngine->GetGlobalSettings(); int type; if (!PyArg_ParseTuple(args,"i:setMaterialType",&type)) return NULL; if(type == KX_BLENDER_GLSL_MATERIAL) - gm->matmode= GAME_MAT_GLSL; + gs->matmode= GAME_MAT_GLSL; else if(type == KX_BLENDER_MULTITEX_MATERIAL) - gm->matmode= GAME_MAT_MULTITEX; + gs->matmode= GAME_MAT_MULTITEX; else if(type == KX_TEXFACE_MATERIAL) - gm->matmode= GAME_MAT_TEXFACE; + gs->matmode= GAME_MAT_TEXFACE; else { PyErr_SetString(PyExc_ValueError, "Rasterizer.setMaterialType(int): material type is not known"); return NULL; @@ -1195,12 +1204,12 @@ static PyObject* gPySetMaterialType(PyObject*, static PyObject* gPyGetMaterialType(PyObject*) { - GameData *gm= &(gp_KetsjiScene->GetBlenderScene()->gm); + GlobalSettings *gs= gp_KetsjiEngine->GetGlobalSettings(); int flag; - if(gm->matmode == GAME_MAT_GLSL) + if(gs->matmode == GAME_MAT_GLSL) flag = KX_BLENDER_GLSL_MATERIAL; - else if(gm->matmode == GAME_MAT_MULTITEX) + else if(gs->matmode == GAME_MAT_MULTITEX) flag = KX_BLENDER_MULTITEX_MATERIAL; else flag = KX_TEXFACE_MATERIAL; @@ -1655,6 +1664,16 @@ PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack KX_MACRO_addTypesToDict(d, ROT_MODE_ZXY, ROT_MODE_ZXY); KX_MACRO_addTypesToDict(d, ROT_MODE_ZYX, ROT_MODE_ZYX); + /* Steering actuator */ + KX_MACRO_addTypesToDict(d, KX_STEERING_SEEK, KX_SteeringActuator::KX_STEERING_SEEK); + KX_MACRO_addTypesToDict(d, KX_STEERING_FLEE, KX_SteeringActuator::KX_STEERING_FLEE); + KX_MACRO_addTypesToDict(d, KX_STEERING_PATHFOLLOWING, KX_SteeringActuator::KX_STEERING_PATHFOLLOWING); + + /* KX_NavMeshObject render mode */ + KX_MACRO_addTypesToDict(d, RM_WALLS, KX_NavMeshObject::RM_WALLS); + KX_MACRO_addTypesToDict(d, RM_POLYS, KX_NavMeshObject::RM_POLYS); + KX_MACRO_addTypesToDict(d, RM_TRIS, KX_NavMeshObject::RM_TRIS); + /* BL_Action play modes */ KX_MACRO_addTypesToDict(d, KX_ACTION_MODE_PLAY, BL_Action::ACT_MODE_PLAY); KX_MACRO_addTypesToDict(d, KX_ACTION_MODE_LOOP, BL_Action::ACT_MODE_LOOP); @@ -1751,7 +1770,7 @@ static void initPySysObjects(Main *maggie) initPySysObjects__append(sys_path, gp_GamePythonPath); -// fprintf(stderr, "\nNew Path: %d ", PyList_Size(sys_path)); +// fprintf(stderr, "\nNew Path: %d ", PyList_GET_SIZE(sys_path)); // PyObject_Print(sys_path, stderr, 0); } @@ -1775,7 +1794,7 @@ static void restorePySysObjects(void) gp_OrigPythonSysModules= NULL; -// fprintf(stderr, "\nRestore Path: %d ", PyList_Size(sys_path)); +// fprintf(stderr, "\nRestore Path: %d ", PyList_GET_SIZE(sys_path)); // PyObject_Print(sys_path, stderr, 0); } diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h index 1b172c35eff..d76e8f913df 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.h +++ b/source/gameengine/Ketsji/KX_PythonInit.h @@ -72,6 +72,9 @@ class KX_KetsjiEngine* KX_GetActiveEngine(); #include "MT_Vector3.h" void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color); +void KX_RasterizerDrawDebugCircle(const MT_Vector3& center, const MT_Scalar radius, const MT_Vector3& color, + const MT_Vector3& normal, int nsector); + #endif //__KX_PYTHON_INIT diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp index 1c4a17e31fc..49a08135c38 100644 --- a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp +++ b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp @@ -68,6 +68,7 @@ #include "KX_SCA_ReplaceMeshActuator.h" #include "KX_SceneActuator.h" #include "KX_StateActuator.h" +#include "KX_SteeringActuator.h" #include "KX_TrackToActuator.h" #include "KX_VehicleWrapper.h" #include "KX_VertexProxy.h" @@ -99,6 +100,7 @@ #include "SCA_PythonController.h" #include "SCA_RandomActuator.h" #include "SCA_IController.h" +#include "KX_NavMeshObject.h" static void PyType_Attr_Set(PyGetSetDef *attr_getset, PyAttributeDef *attr) { @@ -217,9 +219,11 @@ void initPyTypes(void) 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_NavMeshObject, 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_SteeringActuator, 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); diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index a49c1bf4b4c..bdc30810b9e 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -87,6 +87,7 @@ #include "BL_ModifierDeformer.h" #include "BL_ShapeDeformer.h" #include "BL_DeformableGameObject.h" +#include "KX_ObstacleSimulation.h" #ifdef USE_BULLET #include "KX_SoftBodyDeformer.h" @@ -168,6 +169,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_lightlist= new CListValue(); m_inactivelist = new CListValue(); m_euthanasyobjects = new CListValue(); + m_animatedlist = new CListValue(); m_logicmgr = new SCA_LogicManager(); @@ -213,6 +215,19 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_bucketmanager=new RAS_BucketManager(); + bool showObstacleSimulation = scene->gm.flag & GAME_SHOW_OBSTACLE_SIMULATION; + switch (scene->gm.obstacleSimulation) + { + case OBSTSIMULATION_TOI_rays: + m_obstacleSimulation = new KX_ObstacleSimulationTOI_rays((MT_Scalar)scene->gm.levelHeight, showObstacleSimulation); + break; + case OBSTSIMULATION_TOI_cells: + m_obstacleSimulation = new KX_ObstacleSimulationTOI_cells((MT_Scalar)scene->gm.levelHeight, showObstacleSimulation); + break; + default: + m_obstacleSimulation = NULL; + } + #ifdef WITH_PYTHON m_attr_dict = PyDict_New(); /* new ref */ m_draw_call_pre = NULL; @@ -235,6 +250,9 @@ KX_Scene::~KX_Scene() this->RemoveObject(parentobj); } + if (m_obstacleSimulation) + delete m_obstacleSimulation; + if(m_objectlist) m_objectlist->Release(); @@ -253,6 +271,9 @@ KX_Scene::~KX_Scene() if (m_euthanasyobjects) m_euthanasyobjects->Release(); + if (m_animatedlist) + m_animatedlist->Release(); + if (m_logicmgr) delete m_logicmgr; @@ -1502,10 +1523,20 @@ void KX_Scene::LogicBeginFrame(double curtime) m_logicmgr->BeginFrame(curtime, 1.0/KX_KetsjiEngine::GetTicRate()); } +void KX_Scene::AddAnimatedObject(CValue* gameobj) +{ + m_animatedlist->Add(gameobj); +} + +void KX_Scene::RemoveAnimatedObject(CValue* gameobj) +{ + m_animatedlist->RemoveValue(gameobj); +} + void KX_Scene::UpdateAnimations(double curtime) { // Update any animations - for (int i=0; i<GetObjectList()->GetCount(); ++i) + for (int i=0; i<m_animatedlist->GetCount(); ++i) ((KX_GameObject*)GetObjectList()->GetValue(i))->UpdateActionManager(curtime); } @@ -1531,6 +1562,10 @@ void KX_Scene::LogicEndFrame() obj->Release(); RemoveObject(obj); } + + //prepare obstacle simulation for new frame + if (m_obstacleSimulation) + m_obstacleSimulation->UpdateObstacles(); } @@ -1902,7 +1937,7 @@ void KX_Scene::Render2DFilters(RAS_ICanvas* canvas) void KX_Scene::RunDrawingCallbacks(PyObject* cb_list) { - int len; + Py_ssize_t len; if (cb_list && (len=PyList_GET_SIZE(cb_list))) { @@ -1911,7 +1946,7 @@ void KX_Scene::RunDrawingCallbacks(PyObject* cb_list) PyObject* ret; // Iterate the list and run the callbacks - for (int pos=0; pos < len; pos++) + for (Py_ssize_t pos=0; pos < len; pos++) { func= PyList_GET_ITEM(cb_list, pos); ret= PyObject_Call(func, args, NULL); @@ -1963,6 +1998,8 @@ PyMethodDef KX_Scene::Methods[] = { KX_PYMETHODTABLE(KX_Scene, replace), KX_PYMETHODTABLE(KX_Scene, suspend), KX_PYMETHODTABLE(KX_Scene, resume), + KX_PYMETHODTABLE(KX_Scene, drawObstacleSimulation), + /* dict style access */ KX_PYMETHODTABLE(KX_Scene, get), @@ -2287,6 +2324,16 @@ KX_PYMETHODDEF_DOC(KX_Scene, resume, Py_RETURN_NONE; } +KX_PYMETHODDEF_DOC(KX_Scene, drawObstacleSimulation, + "drawObstacleSimulation()\n" + "Draw debug visualization of obstacle simulation.\n") +{ + if (GetObstacleSimulation()) + GetObstacleSimulation()->DrawObstacles(); + + Py_RETURN_NONE; +} + /* Matches python dict.get(key, [default]) */ KX_PYMETHODDEF_DOC(KX_Scene, get, "") { diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index da9cc12c76a..5954d5465ba 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -88,6 +88,7 @@ class SCA_JoystickManager; class btCollisionShape; class KX_BlenderSceneConverter; struct KX_ClientObjectInfo; +class KX_ObstacleSimulation; #ifdef WITH_CXX_GUARDEDALLOC #include "MEM_guardedalloc.h" @@ -130,6 +131,7 @@ protected: CListValue* m_parentlist; // all 'root' parents CListValue* m_lightlist; CListValue* m_inactivelist; // all objects that are not in the active layer + CListValue* m_animatedlist; // all animated objects SG_QList m_sghead; // list of nodes that needs scenegraph update // the Dlist is not object that must be updated @@ -292,6 +294,9 @@ protected: struct Scene* m_blenderScene; RAS_2DFilterManager m_filtermanager; + + KX_ObstacleSimulation* m_obstacleSimulation; + public: KX_Scene(class SCA_IInputDevice* keyboarddevice, class SCA_IInputDevice* mousedevice, @@ -334,6 +339,10 @@ public: int NewRemoveObject(CValue* gameobj); void ReplaceMesh(CValue* gameobj, void* meshob, bool use_gfx, bool use_phys); + + void AddAnimatedObject(CValue* gameobj); + void RemoveAnimatedObject(CValue* gameobj); + /** * @section Logic stuff * Initiate an update of the logic system. @@ -580,6 +589,8 @@ public: void Update2DFilter(vector<STR_String>& propNames, void* gameObj, RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode, int pass, STR_String& text); void Render2DFilters(RAS_ICanvas* canvas); + KX_ObstacleSimulation* GetObstacleSimulation() {return m_obstacleSimulation;}; + #ifdef WITH_PYTHON /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ @@ -592,6 +603,8 @@ public: KX_PYMETHOD_DOC(KX_Scene, suspend); KX_PYMETHOD_DOC(KX_Scene, resume); KX_PYMETHOD_DOC(KX_Scene, get); + KX_PYMETHOD_DOC(KX_Scene, drawObstacleSimulation); + /* attributes */ static PyObject* pyattr_get_name(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index 6c7b515c095..f24243fcdfc 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -108,7 +108,15 @@ void KX_SoundActuator::play() break; } - m_handle = AUD_getDevice()->play(sound, 0); + try + { + m_handle = AUD_getDevice()->play(sound, 0); + } + catch(AUD_Exception&) + { + // cannot play back, ignore + return; + } AUD_Reference<AUD_I3DHandle> handle3d = AUD_Reference<AUD_I3DHandle>(m_handle); diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.cpp b/source/gameengine/Ketsji/KX_SteeringActuator.cpp new file mode 100644 index 00000000000..a0a2e148c1e --- /dev/null +++ b/source/gameengine/Ketsji/KX_SteeringActuator.cpp @@ -0,0 +1,630 @@ +/** +* Add steering behaviors +* +* $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. The Blender +* Foundation also sells licenses for use in proprietary software under +* the Blender License. See http://www.blender.org/BL/ for information +* about this. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#include "BLI_math.h" +#include "KX_SteeringActuator.h" +#include "KX_GameObject.h" +#include "KX_NavMeshObject.h" +#include "KX_ObstacleSimulation.h" +#include "KX_PythonInit.h" +#include "KX_PyMath.h" +#include "Recast.h" + +/* ------------------------------------------------------------------------- */ +/* Native functions */ +/* ------------------------------------------------------------------------- */ + +KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj, + int mode, + KX_GameObject *target, + KX_GameObject *navmesh, + float distance, + float velocity, + float acceleration, + float turnspeed, + bool isSelfTerminated, + int pathUpdatePeriod, + KX_ObstacleSimulation* simulation, + short facingmode, + bool normalup, + bool enableVisualization) : + SCA_IActuator(gameobj, KX_ACT_STEERING), + m_mode(mode), + m_target(target), + m_distance(distance), + m_velocity(velocity), + m_acceleration(acceleration), + m_turnspeed(turnspeed), + m_isSelfTerminated(isSelfTerminated), + m_pathUpdatePeriod(pathUpdatePeriod), + m_updateTime(0), + m_isActive(false), + m_simulation(simulation), + m_enableVisualization(enableVisualization), + m_facingMode(facingmode), + m_normalUp(normalup), + m_obstacle(NULL), + m_pathLen(0), + m_wayPointIdx(-1), + m_steerVec(MT_Vector3(0, 0, 0)) +{ + m_navmesh = static_cast<KX_NavMeshObject*>(navmesh); + if (m_navmesh) + m_navmesh->RegisterActuator(this); + if (m_target) + m_target->RegisterActuator(this); + + if (m_simulation) + m_obstacle = m_simulation->GetObstacle((KX_GameObject*)gameobj); + KX_GameObject* parent = ((KX_GameObject*)gameobj)->GetParent(); + if (m_facingMode>0 && parent) + { + m_parentlocalmat = parent->GetSGNode()->GetLocalOrientation(); + } + else + m_parentlocalmat.setIdentity(); +} + +KX_SteeringActuator::~KX_SteeringActuator() +{ + if (m_navmesh) + m_navmesh->UnregisterActuator(this); + if (m_target) + m_target->UnregisterActuator(this); +} + +CValue* KX_SteeringActuator::GetReplica() +{ + KX_SteeringActuator* replica = new KX_SteeringActuator(*this); + // replication just copy the m_base pointer => common random generator + replica->ProcessReplica(); + return replica; +} + +void KX_SteeringActuator::ProcessReplica() +{ + if (m_target) + m_target->RegisterActuator(this); + if (m_navmesh) + m_navmesh->RegisterActuator(this); + SCA_IActuator::ProcessReplica(); +} + + +bool KX_SteeringActuator::UnlinkObject(SCA_IObject* clientobj) +{ + if (clientobj == m_target) + { + m_target = NULL; + return true; + } + else if (clientobj == m_navmesh) + { + m_navmesh = NULL; + return true; + } + return false; +} + +void KX_SteeringActuator::Relink(CTR_Map<CTR_HashedPtr, void*> *obj_map) +{ + void **h_obj = (*obj_map)[m_target]; + if (h_obj) { + if (m_target) + m_target->UnregisterActuator(this); + m_target = (KX_GameObject*)(*h_obj); + m_target->RegisterActuator(this); + } + + h_obj = (*obj_map)[m_navmesh]; + if (h_obj) { + if (m_navmesh) + m_navmesh->UnregisterActuator(this); + m_navmesh = (KX_NavMeshObject*)(*h_obj); + m_navmesh->RegisterActuator(this); + } +} + +bool KX_SteeringActuator::Update(double curtime, bool frame) +{ + if (frame) + { + double delta = curtime - m_updateTime; + m_updateTime = curtime; + + if (m_posevent && !m_isActive) + { + delta = 0; + m_pathUpdateTime = -1; + m_updateTime = curtime; + m_isActive = true; + } + bool bNegativeEvent = IsNegativeEvent(); + if (bNegativeEvent) + m_isActive = false; + + RemoveAllEvents(); + + if (!delta) + return true; + + if (bNegativeEvent || !m_target) + return false; // do nothing on negative events + + KX_GameObject *obj = (KX_GameObject*) GetParent(); + const MT_Point3& mypos = obj->NodeGetWorldPosition(); + const MT_Point3& targpos = m_target->NodeGetWorldPosition(); + MT_Vector3 vectotarg = targpos - mypos; + MT_Vector3 vectotarg2d = vectotarg; + vectotarg2d.z() = 0; + m_steerVec = MT_Vector3(0, 0, 0); + bool apply_steerforce = false; + bool terminate = true; + + switch (m_mode) { + case KX_STEERING_SEEK: + if (vectotarg2d.length2()>m_distance*m_distance) + { + terminate = false; + m_steerVec = vectotarg; + m_steerVec.normalize(); + apply_steerforce = true; + } + break; + case KX_STEERING_FLEE: + if (vectotarg2d.length2()<m_distance*m_distance) + { + terminate = false; + m_steerVec = -vectotarg; + m_steerVec.normalize(); + apply_steerforce = true; + } + break; + case KX_STEERING_PATHFOLLOWING: + if (m_navmesh && vectotarg.length2()>m_distance*m_distance) + { + terminate = false; + + static const MT_Scalar WAYPOINT_RADIUS(0.25); + + if (m_pathUpdateTime<0 || (m_pathUpdatePeriod>=0 && + curtime - m_pathUpdateTime>((double)m_pathUpdatePeriod/1000))) + { + m_pathUpdateTime = curtime; + m_pathLen = m_navmesh->FindPath(mypos, targpos, m_path, MAX_PATH_LENGTH); + m_wayPointIdx = m_pathLen > 1 ? 1 : -1; + } + + if (m_wayPointIdx>0) + { + MT_Vector3 waypoint(&m_path[3*m_wayPointIdx]); + if ((waypoint-mypos).length2()<WAYPOINT_RADIUS*WAYPOINT_RADIUS) + { + m_wayPointIdx++; + if (m_wayPointIdx>=m_pathLen) + { + m_wayPointIdx = -1; + terminate = true; + } + else + waypoint.setValue(&m_path[3*m_wayPointIdx]); + } + + m_steerVec = waypoint - mypos; + apply_steerforce = true; + + + if (m_enableVisualization) + { + //debug draw + static const MT_Vector3 PATH_COLOR(1,0,0); + m_navmesh->DrawPath(m_path, m_pathLen, PATH_COLOR); + } + } + + } + break; + } + + if (apply_steerforce) + { + bool isdyna = obj->IsDynamic(); + if (isdyna) + m_steerVec.z() = 0; + if (!m_steerVec.fuzzyZero()) + m_steerVec.normalize(); + MT_Vector3 newvel = m_velocity*m_steerVec; + + //adjust velocity to avoid obstacles + if (m_simulation && m_obstacle /*&& !newvel.fuzzyZero()*/) + { + if (m_enableVisualization) + KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(1.,0.,0.)); + m_simulation->AdjustObstacleVelocity(m_obstacle, m_mode!=KX_STEERING_PATHFOLLOWING ? m_navmesh : NULL, + newvel, m_acceleration*delta, m_turnspeed/180.0f*M_PI*delta); + if (m_enableVisualization) + KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(0.,1.,0.)); + } + + HandleActorFace(newvel); + if (isdyna) + { + //temporary solution: set 2D steering velocity directly to obj + //correct way is to apply physical force + MT_Vector3 curvel = obj->GetLinearVelocity(); + newvel.z() = curvel.z(); + obj->setLinearVelocity(newvel, false); + } + else + { + MT_Vector3 movement = delta*newvel; + obj->ApplyMovement(movement, false); + } + } + else + { + if (m_simulation && m_obstacle) + { + m_obstacle->dvel[0] = 0.f; + m_obstacle->dvel[1] = 0.f; + } + + } + + if (terminate && m_isSelfTerminated) + return false; + } + + return true; +} + +const MT_Vector3& KX_SteeringActuator::GetSteeringVec() +{ + static MT_Vector3 ZERO_VECTOR(0, 0, 0); + if (m_isActive) + return m_steerVec; + else + return ZERO_VECTOR; +} + +inline float vdot2(const float* a, const float* b) +{ + return a[0]*b[0] + a[2]*b[2]; +} +static bool barDistSqPointToTri(const float* p, const float* a, const float* b, const float* c) +{ + float v0[3], v1[3], v2[3]; + vsub(v0, c,a); + vsub(v1, b,a); + vsub(v2, p,a); + + const float dot00 = vdot2(v0, v0); + const float dot01 = vdot2(v0, v1); + const float dot02 = vdot2(v0, v2); + const float dot11 = vdot2(v1, v1); + const float dot12 = vdot2(v1, v2); + + // Compute barycentric coordinates + float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); + float u = (dot11 * dot02 - dot01 * dot12) * invDenom; + float v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + float ud = u<0.f ? -u : (u>1.f ? u-1.f : 0.f); + float vd = v<0.f ? -v : (v>1.f ? v-1.f : 0.f); + return ud*ud+vd*vd ; +} + +inline void flipAxes(float* vec) +{ + std::swap(vec[1],vec[2]); +} + +static bool getNavmeshNormal(dtStatNavMesh* navmesh, const MT_Vector3& pos, MT_Vector3& normal) +{ + static const float polyPickExt[3] = {2, 4, 2}; + float spos[3]; + pos.getValue(spos); + flipAxes(spos); + dtStatPolyRef sPolyRef = navmesh->findNearestPoly(spos, polyPickExt); + if (sPolyRef == 0) + return false; + const dtStatPoly* p = navmesh->getPoly(sPolyRef-1); + const dtStatPolyDetail* pd = navmesh->getPolyDetail(sPolyRef-1); + + float distMin = FLT_MAX; + int idxMin = -1; + for (int i = 0; i < pd->ntris; ++i) + { + const unsigned char* t = navmesh->getDetailTri(pd->tbase+i); + const float* v[3]; + for (int j = 0; j < 3; ++j) + { + if (t[j] < p->nv) + v[j] = navmesh->getVertex(p->v[t[j]]); + else + v[j] = navmesh->getDetailVertex(pd->vbase+(t[j]-p->nv)); + } + float dist = barDistSqPointToTri(spos, v[0], v[1], v[2]); + if (dist<distMin) + { + distMin = dist; + idxMin = i; + } + } + + if (idxMin>=0) + { + const unsigned char* t = navmesh->getDetailTri(pd->tbase+idxMin); + const float* v[3]; + for (int j = 0; j < 3; ++j) + { + if (t[j] < p->nv) + v[j] = navmesh->getVertex(p->v[t[j]]); + else + v[j] = navmesh->getDetailVertex(pd->vbase+(t[j]-p->nv)); + } + MT_Vector3 tri[3]; + for (size_t j=0; j<3; j++) + tri[j].setValue(v[j][0],v[j][2],v[j][1]); + MT_Vector3 a,b; + a = tri[1]-tri[0]; + b = tri[2]-tri[0]; + normal = b.cross(a).safe_normalized(); + return true; + } + + return false; +} + +void KX_SteeringActuator::HandleActorFace(MT_Vector3& velocity) +{ + if (m_facingMode==0 && (!m_navmesh || !m_normalUp)) + return; + KX_GameObject* curobj = (KX_GameObject*) GetParent(); + MT_Vector3 dir = m_facingMode==0 ? curobj->NodeGetLocalOrientation().getColumn(1) : velocity; + if (dir.fuzzyZero()) + return; + dir.normalize(); + MT_Vector3 up(0,0,1); + MT_Vector3 left; + MT_Matrix3x3 mat; + + if (m_navmesh && m_normalUp) + { + dtStatNavMesh* navmesh = m_navmesh->GetNavMesh(); + MT_Vector3 normal; + MT_Vector3 trpos = m_navmesh->TransformToLocalCoords(curobj->NodeGetWorldPosition()); + if (getNavmeshNormal(navmesh, trpos, normal)) + { + + left = (dir.cross(up)).safe_normalized(); + dir = (-left.cross(normal)).safe_normalized(); + up = normal; + } + } + + switch (m_facingMode) + { + case 1: // TRACK X + { + left = dir.safe_normalized(); + dir = -(left.cross(up)).safe_normalized(); + break; + }; + case 2: // TRACK Y + { + left = (dir.cross(up)).safe_normalized(); + break; + } + + case 3: // track Z + { + left = up.safe_normalized(); + up = dir.safe_normalized(); + dir = left; + left = (dir.cross(up)).safe_normalized(); + break; + } + + case 4: // TRACK -X + { + left = -dir.safe_normalized(); + dir = -(left.cross(up)).safe_normalized(); + break; + }; + case 5: // TRACK -Y + { + left = (-dir.cross(up)).safe_normalized(); + dir = -dir; + break; + } + case 6: // track -Z + { + left = up.safe_normalized(); + up = -dir.safe_normalized(); + dir = left; + left = (dir.cross(up)).safe_normalized(); + break; + } + } + + mat.setValue ( + left[0], dir[0],up[0], + left[1], dir[1],up[1], + left[2], dir[2],up[2] + ); + + + + KX_GameObject* parentObject = curobj->GetParent(); + if(parentObject) + { + MT_Point3 localpos; + localpos = curobj->GetSGNode()->GetLocalPosition(); + MT_Matrix3x3 parentmatinv; + parentmatinv = parentObject->NodeGetWorldOrientation ().inverse (); + mat = parentmatinv * mat; + mat = m_parentlocalmat * mat; + curobj->NodeSetLocalOrientation(mat); + curobj->NodeSetLocalPosition(localpos); + } + else + { + curobj->NodeSetLocalOrientation(mat); + } + +} + +#ifndef DISABLE_PYTHON + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ + +/* Integration hooks ------------------------------------------------------- */ +PyTypeObject KX_SteeringActuator::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "KX_SteeringActuator", + 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_SteeringActuator::Methods[] = { + {NULL,NULL} //Sentinel +}; + +PyAttributeDef KX_SteeringActuator::Attributes[] = { + KX_PYATTRIBUTE_INT_RW("behaviour", KX_STEERING_NODEF+1, KX_STEERING_MAX-1, true, KX_SteeringActuator, m_mode), + KX_PYATTRIBUTE_RW_FUNCTION("target", KX_SteeringActuator, pyattr_get_target, pyattr_set_target), + KX_PYATTRIBUTE_RW_FUNCTION("navmesh", KX_SteeringActuator, pyattr_get_navmesh, pyattr_set_navmesh), + KX_PYATTRIBUTE_FLOAT_RW("distance", 0.0f, 1000.0f, KX_SteeringActuator, m_distance), + KX_PYATTRIBUTE_FLOAT_RW("velocity", 0.0f, 1000.0f, KX_SteeringActuator, m_velocity), + KX_PYATTRIBUTE_FLOAT_RW("acceleration", 0.0f, 1000.0f, KX_SteeringActuator, m_acceleration), + KX_PYATTRIBUTE_FLOAT_RW("turnspeed", 0.0f, 720.0f, KX_SteeringActuator, m_turnspeed), + KX_PYATTRIBUTE_BOOL_RW("selfterminated", KX_SteeringActuator, m_isSelfTerminated), + KX_PYATTRIBUTE_BOOL_RW("enableVisualization", KX_SteeringActuator, m_enableVisualization), + KX_PYATTRIBUTE_RO_FUNCTION("steeringVec", KX_SteeringActuator, pyattr_get_steeringVec), + KX_PYATTRIBUTE_SHORT_RW("facingMode", 0, 6, true, KX_SteeringActuator, m_facingMode), + KX_PYATTRIBUTE_INT_RW("pathUpdatePeriod", -1, 100000, true, KX_SteeringActuator, m_pathUpdatePeriod), + { NULL } //Sentinel +}; + +PyObject* KX_SteeringActuator::pyattr_get_target(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_SteeringActuator* actuator = static_cast<KX_SteeringActuator*>(self); + if (!actuator->m_target) + Py_RETURN_NONE; + else + return actuator->m_target->GetProxy(); +} + +int KX_SteeringActuator::pyattr_set_target(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_SteeringActuator* actuator = static_cast<KX_SteeringActuator*>(self); + KX_GameObject *gameobj; + + if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_SteeringActuator")) + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + + if (actuator->m_target != NULL) + actuator->m_target->UnregisterActuator(actuator); + + actuator->m_target = (KX_GameObject*) gameobj; + + if (actuator->m_target) + actuator->m_target->RegisterActuator(actuator); + + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_SteeringActuator::pyattr_get_navmesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_SteeringActuator* actuator = static_cast<KX_SteeringActuator*>(self); + if (!actuator->m_navmesh) + Py_RETURN_NONE; + else + return actuator->m_navmesh->GetProxy(); +} + +int KX_SteeringActuator::pyattr_set_navmesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_SteeringActuator* actuator = static_cast<KX_SteeringActuator*>(self); + KX_GameObject *gameobj; + + if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_SteeringActuator")) + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + + if (!PyObject_TypeCheck(value, &KX_NavMeshObject::Type)) + { + PyErr_Format(PyExc_TypeError, "KX_NavMeshObject is expected"); + return PY_SET_ATTR_FAIL; + } + + if (actuator->m_navmesh != NULL) + actuator->m_navmesh->UnregisterActuator(actuator); + + actuator->m_navmesh = static_cast<KX_NavMeshObject*>(gameobj); + + if (actuator->m_navmesh) + actuator->m_navmesh->RegisterActuator(actuator); + + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_SteeringActuator::pyattr_get_steeringVec(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_SteeringActuator* actuator = static_cast<KX_SteeringActuator*>(self); + const MT_Vector3& steeringVec = actuator->GetSteeringVec(); + return PyObjectFrom(steeringVec); +} + +#endif // DISABLE_PYTHON + +/* eof */ + diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.h b/source/gameengine/Ketsji/KX_SteeringActuator.h new file mode 100644 index 00000000000..4f8303107f7 --- /dev/null +++ b/source/gameengine/Ketsji/KX_SteeringActuator.h @@ -0,0 +1,130 @@ +/** +* Add steering behaviors +* +* +* $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. The Blender +* Foundation also sells licenses for use in proprietary software under +* the Blender License. See http://www.blender.org/BL/ for information +* about this. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#ifndef __KX_STEERINGACTUATOR +#define __KX_STEERINGACTUATOR + +#include "SCA_IActuator.h" +#include "SCA_LogicManager.h" +#include "MT_Matrix3x3.h" + +class KX_GameObject; +class KX_NavMeshObject; +struct KX_Obstacle; +class KX_ObstacleSimulation; +const int MAX_PATH_LENGTH = 128; + +class KX_SteeringActuator : public SCA_IActuator +{ + Py_Header; + + /** Target object */ + KX_GameObject *m_target; + KX_NavMeshObject *m_navmesh; + int m_mode; + float m_distance; + float m_velocity; + float m_acceleration; + float m_turnspeed; + KX_ObstacleSimulation* m_simulation; + + KX_Obstacle* m_obstacle; + double m_updateTime; + bool m_isActive; + bool m_isSelfTerminated; + bool m_enableVisualization; + short m_facingMode; + bool m_normalUp; + float m_path[MAX_PATH_LENGTH*3]; + int m_pathLen; + int m_pathUpdatePeriod; + double m_pathUpdateTime; + int m_wayPointIdx; + MT_Matrix3x3 m_parentlocalmat; + MT_Vector3 m_steerVec; + void HandleActorFace(MT_Vector3& velocity); +public: + enum KX_STEERINGACT_MODE + { + KX_STEERING_NODEF = 0, + KX_STEERING_SEEK, + KX_STEERING_FLEE, + KX_STEERING_PATHFOLLOWING, + KX_STEERING_MAX + }; + + KX_SteeringActuator(class SCA_IObject* gameobj, + int mode, + KX_GameObject *target, + KX_GameObject *navmesh, + float distance, + float velocity, + float acceleration, + float turnspeed, + bool isSelfTerminated, + int pathUpdatePeriod, + KX_ObstacleSimulation* simulation, + short facingmode, + bool normalup, + bool enableVisualization); + virtual ~KX_SteeringActuator(); + virtual bool Update(double curtime, bool frame); + + virtual CValue* GetReplica(); + virtual void ProcessReplica(); + virtual void Relink(CTR_Map<CTR_HashedPtr, void*> *obj_map); + virtual bool UnlinkObject(SCA_IObject* clientobj); + const MT_Vector3& GetSteeringVec(); + +#ifndef DISABLE_PYTHON + + /* --------------------------------------------------------------------- */ + /* Python interface ---------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + + /* These are used to get and set m_target */ + static PyObject* pyattr_get_target(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_target(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_navmesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_navmesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_steeringVec(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + + +#endif // DISABLE_PYTHON + +}; /* end of class KX_SteeringActuator : public SCA_PropertyActuator */ + +#endif + diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.h b/source/gameengine/Ketsji/KX_TrackToActuator.h index c5e96bd7454..bbf0134a859 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.h +++ b/source/gameengine/Ketsji/KX_TrackToActuator.h @@ -57,7 +57,7 @@ class KX_TrackToActuator : public SCA_IActuator public: KX_TrackToActuator(SCA_IObject* gameobj, SCA_IObject *ob, int time, - bool threedee,int trackflag,int upflag); + bool threedee,int trackflag,int upflag); virtual ~KX_TrackToActuator(); virtual CValue* GetReplica() { KX_TrackToActuator* replica = new KX_TrackToActuator(*this); diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript index c5509dd7de8..9b453ed76d5 100644 --- a/source/gameengine/Ketsji/SConscript +++ b/source/gameengine/Ketsji/SConscript @@ -20,6 +20,7 @@ incs += ' #source/gameengine/GameLogic #source/gameengine/Expressions #source/ga incs += ' #source/gameengine/SceneGraph #source/gameengine/Physics/common' incs += ' #source/gameengine/Physics/Dummy' incs += ' #source/blender/misc #source/blender/blenloader #extern/glew/include #source/blender/gpu' +incs += ' #extern/recastnavigation/Recast/Include #extern/recastnavigation/Detour/Include' incs += ' ' + env['BF_BULLET_INC'] incs += ' ' + env['BF_OPENGL_INC'] diff --git a/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.h b/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.h index 67d0e741507..cb7807a86a6 100644 --- a/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.h +++ b/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.h @@ -52,8 +52,8 @@ public: virtual void NextFrame(); bool Connect(char *address, unsigned int port, char *password, - unsigned int localport, unsigned int timeout) { - return true;} + unsigned int localport, unsigned int timeout) { + return true;} bool Disconnect(void) {return true;} virtual void SendNetworkMessage(class NG_NetworkMessage* msg); diff --git a/source/gameengine/Network/NG_NetworkDeviceInterface.h b/source/gameengine/Network/NG_NetworkDeviceInterface.h index 6df228680ec..857b4660327 100644 --- a/source/gameengine/Network/NG_NetworkDeviceInterface.h +++ b/source/gameengine/Network/NG_NetworkDeviceInterface.h @@ -64,7 +64,7 @@ public: bool IsOnline(void) { return m_online; } virtual bool Connect(char *address, unsigned int port, char *password, - unsigned int localport, unsigned int timeout)=0; + unsigned int localport, unsigned int timeout)=0; virtual bool Disconnect(void)=0; virtual void SendNetworkMessage(NG_NetworkMessage* msg)=0; diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 08445654916..82acd64161f 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -216,12 +216,12 @@ struct CcdConstructionInfo ///more advanced collision filtering should be done in btCollisionDispatcher::NeedsCollision enum CollisionFilterGroups { - DefaultFilter = 1, - StaticFilter = 2, - KinematicFilter = 4, - DebrisFilter = 8, - SensorFilter = 16, - AllFilter = DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorFilter, + DefaultFilter = 1, + StaticFilter = 2, + KinematicFilter = 4, + DebrisFilter = 8, + SensorFilter = 16, + AllFilter = DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorFilter, }; diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index 526176481ed..39b2022a1f4 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -2564,8 +2564,8 @@ int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl btPlaneSpace1( axisInA, axis1, axis2 ); frameInA.getBasis().setValue( axisInA.x(), axis1.x(), axis2.x(), - axisInA.y(), axis1.y(), axis2.y(), - axisInA.z(), axis1.z(), axis2.z() ); + axisInA.y(), axis1.y(), axis2.y(), + axisInA.z(), axis1.z(), axis2.z() ); frameInA.setOrigin( pivotInA ); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h index 18e1282b111..c34a00513bf 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h @@ -164,7 +164,7 @@ protected: virtual float getConstraintParam(int constraintId,int param); - virtual void removeConstraint(int constraintid); + virtual void removeConstraint(int constraintid); virtual float getAppliedImpulse(int constraintid); diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp index ed18ff0329e..725d00aa5cd 100644 --- a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp @@ -306,8 +306,8 @@ void RAS_2DFilterManager::SetupTextures(bool depth, bool luminance) if(depth){ glGenTextures(1, (GLuint*)&texname[1]); glBindTexture(GL_TEXTURE_2D, texname[1]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, texturewidth,textureheight, - 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, texturewidth,textureheight, + 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -433,6 +433,9 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, 0, 0, texturewidth,textureheight, 0); } + // reverting to texunit 0, without this we get bug [#28462] + glActiveTextureARB(GL_TEXTURE0); + glViewport(0,0, texturewidth, textureheight); glDisable(GL_DEPTH_TEST); diff --git a/source/gameengine/Rasterizer/RAS_CameraData.h b/source/gameengine/Rasterizer/RAS_CameraData.h index e6254f72511..5657fda4f3c 100644 --- a/source/gameengine/Rasterizer/RAS_CameraData.h +++ b/source/gameengine/Rasterizer/RAS_CameraData.h @@ -49,19 +49,19 @@ struct RAS_CameraData float m_focallength; RAS_CameraData(float lens = 35.0, float scale = 6.0, float clipstart = 0.1, float clipend = 5000.0, bool perspective = true, - float focallength = 3.0, 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), - m_viewport(viewport), - m_viewportleft(viewportleft), - m_viewportbottom(viewportbottom), - m_viewportright(viewportright), - m_viewporttop(viewporttop), - m_focallength(focallength) + float focallength = 3.0, 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), + m_viewport(viewport), + m_viewportleft(viewportleft), + m_viewportbottom(viewportbottom), + m_viewportright(viewportright), + m_viewporttop(viewporttop), + m_focallength(focallength) { } }; diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h index c46ebf742a0..877a7219a1c 100644 --- a/source/gameengine/Rasterizer/RAS_IRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h @@ -393,7 +393,9 @@ 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 DrawDebugCircle(const MT_Vector3& center, const MT_Scalar radius, const MT_Vector3& color, + const MT_Vector3& normal, int nsector)=0; + virtual void FlushDebugShapes()=0; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.h index a277d9835d8..3a3ea57d67b 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.h @@ -38,17 +38,17 @@ uniform vec2 bgl_TextureCoordinateOffset[9]; void main(void) { - vec4 sample[9]; + vec4 sample[9]; - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - } + for (int i = 0; i < 9; i++) + { + sample[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + } - gl_FragColor = (sample[0] + (2.0*sample[1]) + sample[2] + - (2.0*sample[3]) + sample[4] + (2.0*sample[5]) + - sample[6] + (2.0*sample[7]) + sample[8]) / 13.0; + gl_FragColor = (sample[0] + (2.0*sample[1]) + sample[2] + + (2.0*sample[3]) + sample[4] + (2.0*sample[5]) + + sample[6] + (2.0*sample[7]) + sample[8]) / 13.0; } ); #endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.h index 6aeff254f77..f486be47f9f 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.h @@ -38,17 +38,17 @@ uniform vec2 bgl_TextureCoordinateOffset[9]; void main(void) { - vec4 sample[9]; - vec4 maxValue = vec4(0.0); + vec4 sample[9]; + vec4 maxValue = vec4(0.0); - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - maxValue = max(sample[i], maxValue); - } + for (int i = 0; i < 9; i++) + { + sample[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + maxValue = max(sample[i], maxValue); + } - gl_FragColor = maxValue; + gl_FragColor = maxValue; } ); #endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.h index 1e9dccaec87..a1755dc0eeb 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.h @@ -33,22 +33,22 @@ #define __RAS_EROSION2DFILTER const char * ErosionFragmentShader=STRINGIFY( -uniform sampler2D bgl_RenderedTexture; -uniform vec2 bgl_TextureCoordinateOffset[9]; + uniform sampler2D bgl_RenderedTexture; + uniform vec2 bgl_TextureCoordinateOffset[9]; void main(void) { - vec4 sample[9]; - vec4 minValue = vec4(1.0); + vec4 sample[9]; + vec4 minValue = vec4(1.0); - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - minValue = min(sample[i], minValue); - } + for (int i = 0; i < 9; i++) + { + sample[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + minValue = min(sample[i], minValue); + } - gl_FragColor = minValue; + gl_FragColor = minValue; } ); #endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.h index c7cfa83a11f..45c94d358ba 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.h @@ -38,18 +38,18 @@ uniform vec2 bgl_TextureCoordinateOffset[9]; void main(void) { - vec4 sample[9]; + vec4 sample[9]; - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - } + for (int i = 0; i < 9; i++) + { + sample[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + } - gl_FragColor = (sample[4] * 8.0) - - (sample[0] + sample[1] + sample[2] + - sample[3] + sample[5] + - sample[6] + sample[7] + sample[8]); + gl_FragColor = (sample[4] * 8.0) - + (sample[0] + sample[1] + sample[2] + + sample[3] + sample[5] + + sample[6] + sample[7] + sample[8]); gl_FragColor = vec4(gl_FragColor.rgb, 1.0); } ); diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.h index ada53cd751d..8d08d9077cb 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.h @@ -38,23 +38,23 @@ uniform vec2 bgl_TextureCoordinateOffset[9]; void main(void) { - vec4 sample[9]; + vec4 sample[9]; - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - } + for (int i = 0; i < 9; i++) + { + sample[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + } - vec4 horizEdge = sample[2] + sample[5] + sample[8] - - (sample[0] + sample[3] + sample[6]); + vec4 horizEdge = sample[2] + sample[5] + sample[8] - + (sample[0] + sample[3] + sample[6]); - vec4 vertEdge = sample[0] + sample[1] + sample[2] - - (sample[6] + sample[7] + sample[8]); + vec4 vertEdge = sample[0] + sample[1] + sample[2] - + (sample[6] + sample[7] + sample[8]); - gl_FragColor.rgb = sqrt((horizEdge.rgb * horizEdge.rgb) + - (vertEdge.rgb * vertEdge.rgb)); - gl_FragColor.a = 1.0; + gl_FragColor.rgb = sqrt((horizEdge.rgb * horizEdge.rgb) + + (vertEdge.rgb * vertEdge.rgb)); + gl_FragColor.a = 1.0; } ); diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.h index 0d68bc09c70..a9c827fa9e1 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.h @@ -38,18 +38,18 @@ uniform vec2 bgl_TextureCoordinateOffset[9]; void main(void) { - vec4 sample[9]; + vec4 sample[9]; - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - } + for (int i = 0; i < 9; i++) + { + sample[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + } - gl_FragColor = (sample[4] * 9.0) - - (sample[0] + sample[1] + sample[2] + - sample[3] + sample[5] + - sample[6] + sample[7] + sample[8]); + gl_FragColor = (sample[4] * 9.0) - + (sample[0] + sample[1] + sample[2] + + sample[3] + sample[5] + + sample[6] + sample[7] + sample[8]); } ); #endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.h index 0f80f0f22b4..350ce19fafd 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.h @@ -38,23 +38,23 @@ uniform vec2 bgl_TextureCoordinateOffset[9]; void main(void) { - vec4 sample[9]; + vec4 sample[9]; - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - } + for (int i = 0; i < 9; i++) + { + sample[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + } - vec4 horizEdge = sample[2] + (2.0*sample[5]) + sample[8] - - (sample[0] + (2.0*sample[3]) + sample[6]); + vec4 horizEdge = sample[2] + (2.0*sample[5]) + sample[8] - + (sample[0] + (2.0*sample[3]) + sample[6]); - vec4 vertEdge = sample[0] + (2.0*sample[1]) + sample[2] - - (sample[6] + (2.0*sample[7]) + sample[8]); + vec4 vertEdge = sample[0] + (2.0*sample[1]) + sample[2] - + (sample[6] + (2.0*sample[7]) + sample[8]); - gl_FragColor.rgb = sqrt((horizEdge.rgb * horizEdge.rgb) + - (vertEdge.rgb * vertEdge.rgb)); - gl_FragColor.a = 1.0; + gl_FragColor.rgb = sqrt((horizEdge.rgb * horizEdge.rgb) + + (vertEdge.rgb * vertEdge.rgb)); + gl_FragColor.a = 1.0; } ); #endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp index 50d034a5a5a..6ad9e591474 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp @@ -55,6 +55,10 @@ #include "BKE_DerivedMesh.h" +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + /** * 32x32 bit masks for vinterlace stereo mode */ @@ -354,9 +358,9 @@ void RAS_OpenGLRasterizer::ClearCachingInfo(void) m_materialCachingInfo = 0; } -void RAS_OpenGLRasterizer::FlushDebugLines() +void RAS_OpenGLRasterizer::FlushDebugShapes() { - if(!m_debugLines.size()) + if(!m_debugShapes.size()) return; // DrawDebugLines @@ -368,29 +372,67 @@ void RAS_OpenGLRasterizer::FlushDebugLines() if(light) glDisable(GL_LIGHTING); if(tex) glDisable(GL_TEXTURE_2D); + //draw lines glBegin(GL_LINES); - for (unsigned int i=0;i<m_debugLines.size();i++) + for (unsigned int i=0;i<m_debugShapes.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(); - + if (m_debugShapes[i].m_type != OglDebugShape::LINE) + continue; + glColor4f(m_debugShapes[i].m_color[0],m_debugShapes[i].m_color[1],m_debugShapes[i].m_color[2],1.f); + const MT_Scalar* fromPtr = &m_debugShapes[i].m_pos.x(); + const MT_Scalar* toPtr= &m_debugShapes[i].m_param.x(); glVertex3dv(fromPtr); glVertex3dv(toPtr); } glEnd(); + //draw circles + for (unsigned int i=0;i<m_debugShapes.size();i++) + { + if (m_debugShapes[i].m_type != OglDebugShape::CIRCLE) + continue; + glBegin(GL_LINE_LOOP); + glColor4f(m_debugShapes[i].m_color[0],m_debugShapes[i].m_color[1],m_debugShapes[i].m_color[2],1.f); + + static const MT_Vector3 worldUp(0.,0.,1.); + MT_Vector3 norm = m_debugShapes[i].m_param; + MT_Matrix3x3 tr; + if (norm.fuzzyZero() || norm == worldUp) + { + tr.setIdentity(); + } + else + { + MT_Vector3 xaxis, yaxis; + xaxis = MT_cross(norm, worldUp); + yaxis = MT_cross(xaxis, norm); + tr.setValue(xaxis.x(), xaxis.y(), xaxis.z(), + yaxis.x(), yaxis.y(), yaxis.z(), + norm.x(), norm.y(), norm.z()); + } + MT_Scalar rad = m_debugShapes[i].m_param2.x(); + int n = (int) m_debugShapes[i].m_param2.y(); + for (int j = 0; j<n; j++) + { + MT_Scalar theta = j*M_PI*2/n; + MT_Vector3 pos(cos(theta)*rad, sin(theta)*rad, 0.); + pos = pos*tr; + pos += m_debugShapes[i].m_pos; + const MT_Scalar* posPtr = &pos.x(); + glVertex3dv(posPtr); + } + glEnd(); + } + if(light) glEnable(GL_LIGHTING); if(tex) glEnable(GL_TEXTURE_2D); - m_debugLines.clear(); + m_debugShapes.clear(); } void RAS_OpenGLRasterizer::EndFrame() { - - - FlushDebugLines(); + FlushDebugShapes(); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h index 61568df91eb..c0e02f6df77 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h @@ -49,10 +49,15 @@ using namespace std; #define RAS_MAX_TEXCO 8 // match in BL_Material #define RAS_MAX_ATTRIB 16 // match in BL_BlenderShader -struct OglDebugLine +struct OglDebugShape { - MT_Vector3 m_from; - MT_Vector3 m_to; + enum SHAPE_TYPE{ + LINE, CIRCLE + }; + SHAPE_TYPE m_type; + MT_Vector3 m_pos; + MT_Vector3 m_param; + MT_Vector3 m_param2; MT_Vector3 m_color; }; @@ -256,18 +261,32 @@ public: virtual void SetPolygonOffset(float mult, float add); - virtual void FlushDebugLines(); + virtual void FlushDebugShapes(); - virtual void DrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color) + virtual void DrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color) { - OglDebugLine line; - line.m_from = from; - line.m_to = to; + OglDebugShape line; + line.m_type = OglDebugShape::LINE; + line.m_pos= from; + line.m_param = to; line.m_color = color; - m_debugLines.push_back(line); + m_debugShapes.push_back(line); + } + + virtual void DrawDebugCircle(const MT_Vector3& center, const MT_Scalar radius, const MT_Vector3& color, + const MT_Vector3& normal, int nsector) + { + OglDebugShape line; + line.m_type = OglDebugShape::CIRCLE; + line.m_pos= center; + line.m_param = normal; + line.m_color = color; + line.m_param2.x() = radius; + line.m_param2.y() = (float) nsector; + m_debugShapes.push_back(line); } - std::vector <OglDebugLine> m_debugLines; + std::vector <OglDebugShape> m_debugShapes; virtual void SetTexCoordNum(int num); virtual void SetAttribNum(int num); diff --git a/source/gameengine/SceneGraph/SG_DList.h b/source/gameengine/SceneGraph/SG_DList.h index b82e51e0d2f..9e7e514b27a 100644 --- a/source/gameengine/SceneGraph/SG_DList.h +++ b/source/gameengine/SceneGraph/SG_DList.h @@ -134,88 +134,88 @@ public: } }; - SG_DList() - { - m_flink = m_blink = this; - } + SG_DList() + { + m_flink = m_blink = this; + } SG_DList(const SG_DList& other) { - m_flink = m_blink = this; + m_flink = m_blink = this; } - virtual ~SG_DList() - { + virtual ~SG_DList() + { Delink(); - } + } - inline bool Empty() // Check for empty queue - { - return ( m_flink == this ); - } - bool AddBack( SG_DList *item ) // Add to the back - { + 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; + 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 - { + } + 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; + 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 - { + } + 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; - } - inline const SG_DList *Peek() const // Look at front without removing - { - return (const SG_DList*)m_flink; - } - inline const SG_DList *Back() const // Look at front without removing - { - return (const SG_DList*)m_blink; - } - inline const SG_DList *Self() const - { - return this; - } + } + 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; + } + inline const SG_DList *Peek() const // Look at front without removing + { + return (const SG_DList*)m_flink; + } + inline const SG_DList *Back() const // Look at front without removing + { + return (const SG_DList*)m_blink; + } + inline const SG_DList *Self() const + { + return this; + } #ifdef WITH_CXX_GUARDEDALLOC diff --git a/source/gameengine/SceneGraph/SG_IObject.h b/source/gameengine/SceneGraph/SG_IObject.h index c42935bc487..8c0159fe8d4 100644 --- a/source/gameengine/SceneGraph/SG_IObject.h +++ b/source/gameengine/SceneGraph/SG_IObject.h @@ -194,7 +194,7 @@ public: /** * Clear the array of pointers to controllers associated with * this node. This does not delete the controllers themselves! - * This should be used very carefully to avoid memory + * This should be used very carefully to avoid memory * leaks. */ diff --git a/source/gameengine/SceneGraph/SG_QList.h b/source/gameengine/SceneGraph/SG_QList.h index de79c35821e..eb404b1a5a5 100644 --- a/source/gameengine/SceneGraph/SG_QList.h +++ b/source/gameengine/SceneGraph/SG_QList.h @@ -91,73 +91,73 @@ public: }; SG_QList() : SG_DList() - { - m_fqlink = m_bqlink = this; - } + { + m_fqlink = m_bqlink = this; + } SG_QList(const SG_QList& other) : SG_DList() { - m_fqlink = m_bqlink = this; + m_fqlink = m_bqlink = this; } - virtual ~SG_QList() - { + virtual ~SG_QList() + { QDelink(); - } + } - inline bool QEmpty() // Check for empty queue - { - return ( m_fqlink == this ); - } - bool QAddBack( SG_QList *item ) // Add to the back - { + 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; + 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 - { + } + 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; + 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 - { + } + 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; - } - - + } + 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(size_t num_bytes) { return MEM_mallocN(num_bytes, "GE:SG_QList"); } diff --git a/source/gameengine/SceneGraph/SG_Spatial.cpp b/source/gameengine/SceneGraph/SG_Spatial.cpp index 94b8584051e..09fb7278bfa 100644 --- a/source/gameengine/SceneGraph/SG_Spatial.cpp +++ b/source/gameengine/SceneGraph/SG_Spatial.cpp @@ -115,7 +115,7 @@ UpdateSpatialData( const SG_Spatial *parent, double time, bool& parentUpdated -){ + ){ bool bComputesWorldTransform = false; // update spatial controllers diff --git a/source/gameengine/VideoTexture/CMakeLists.txt b/source/gameengine/VideoTexture/CMakeLists.txt index 04683a5f99b..448fb307d2d 100644 --- a/source/gameengine/VideoTexture/CMakeLists.txt +++ b/source/gameengine/VideoTexture/CMakeLists.txt @@ -95,7 +95,6 @@ if(WITH_CODEC_FFMPEG) ${PTHREADS_INCLUDE_DIRS} ) add_definitions(-DWITH_FFMPEG) - add_definitions(-D__STDC_CONSTANT_MACROS) endif() blender_add_lib(ge_videotex "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/VideoTexture/Exception.h b/source/gameengine/VideoTexture/Exception.h index 16248186108..11e617cf4ce 100644 --- a/source/gameengine/VideoTexture/Exception.h +++ b/source/gameengine/VideoTexture/Exception.h @@ -122,11 +122,11 @@ public: desc = m_description; } - void registerDesc(void) - { - if (std::find(m_expDescs.begin(), m_expDescs.end(), this) == m_expDescs.end()) - m_expDescs.push_back(this); - } + 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; diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp index 86de214e2d3..65509ab9424 100644 --- a/source/gameengine/VideoTexture/ImageBase.cpp +++ b/source/gameengine/VideoTexture/ImageBase.cpp @@ -375,7 +375,7 @@ void Image_dealloc (PyImage * self) if (self->m_image->m_exports > 0) { PyErr_SetString(PyExc_SystemError, - "deallocated Image object has exported buffers"); + "deallocated Image object has exported buffers"); PyErr_Print(); } // if release requires deleting of object, do it diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp index 24833ace08f..f7546d876b2 100644 --- a/source/gameengine/VideoTexture/ImageRender.cpp +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -328,11 +328,11 @@ static int ImageRender_init (PyObject * pySelf, PyObject * args, PyObject * kwds // 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)); + return Py_BuildValue("[BBBB]", + getImageRender(self)->getBackground(0), + getImageRender(self)->getBackground(1), + getImageRender(self)->getBackground(2), + getImageRender(self)->getBackground(3)); } // set color diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp index 2cb3831de52..e7244265fc4 100644 --- a/source/gameengine/VideoTexture/blendVideoTex.cpp +++ b/source/gameengine/VideoTexture/blendVideoTex.cpp @@ -112,7 +112,7 @@ static PyMethodDef moduleMethods[] = {NULL} /* Sentinel */ }; -#if WITH_FFMPEG +#ifdef WITH_FFMPEG extern PyTypeObject VideoFFmpegType; extern PyTypeObject ImageFFmpegType; #endif @@ -134,7 +134,7 @@ extern PyTypeObject ImageViewportType; static void registerAllTypes(void) { -#if WITH_FFMPEG +#ifdef WITH_FFMPEG pyImageTypes.add(&VideoFFmpegType, "VideoFFmpeg"); pyImageTypes.add(&ImageFFmpegType, "ImageFFmpeg"); #endif |