diff options
author | Martin Poirier <theeth@yahoo.com> | 2008-10-03 00:39:57 +0400 |
---|---|---|
committer | Martin Poirier <theeth@yahoo.com> | 2008-10-03 00:39:57 +0400 |
commit | c35a2d6ea9dc5226911bd90848e96a59233bdaf8 (patch) | |
tree | be895ae3982a72a5b1cfd4ff9b1766037c07a6d0 /source/gameengine | |
parent | 39e66e4d6f48b7a54a510ec5504fd500cc07174f (diff) | |
parent | 06c43148a19ad7e8cddf9ba51549b51bdb1f6f0c (diff) |
merge trunk 16118 -> 116886
Diffstat (limited to 'source/gameengine')
227 files changed, 9694 insertions, 6154 deletions
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index 7de3056e382..0d58810e156 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -79,6 +79,8 @@ #include "DNA_scene_types.h" /***/ +#include "GPU_extensions.h" + #ifdef __cplusplus extern "C" { #endif @@ -90,33 +92,10 @@ void update_for_newframe(); static BlendFileData *load_game_data(char *filename) { BlendReadError error; - //this doesn't work anymore for relative paths, so use BLO_read_from_memory instead - //BlendFileData *bfd= BLO_read_from_file(filename, &error); - FILE* file = fopen(filename,"rb"); - BlendFileData *bfd = 0; - if (file) - { - fseek(file, 0L, SEEK_END); - int len= ftell(file); - fseek(file, 0L, SEEK_SET); - char* filebuffer= new char[len];//MEM_mallocN(len, "text_buffer"); - int sizeread = fread(filebuffer,len,1,file); - if (sizeread==1){ - bfd = BLO_read_from_memory(filebuffer, len, &error); - } else { - error = BRE_UNABLE_TO_READ; - } - fclose(file); - // the memory is not released in BLO_read_from_memory, must do it here - delete filebuffer; - } else { - error = BRE_UNABLE_TO_OPEN; - } - + BlendFileData *bfd= BLO_read_from_file(filename, &error); if (!bfd) { printf("Loading %s failed: %s\n", filename, BLO_bre_as_string(error)); } - return bfd; } @@ -139,7 +118,9 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, // Acquire Python's GIL (global interpreter lock) // so we can safely run Python code and API calls PyGILState_STATE gilstate = PyGILState_Ensure(); - + + PyObject *pyGlobalDict = PyDict_New(); /* python utility storage, spans blend file loading */ + bgl::InitExtensions(true); do @@ -157,7 +138,12 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, bool usemat = false, useglslmat = false; if(GLEW_ARB_multitexture && GLEW_VERSION_1_1) - usemat = (SYS_GetCommandLineInt(syshandle, "blender_material", 0) != 0); + usemat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0); + + if(GPU_extensions_minimum_support()) + useglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0); + else if(G.fileflags & G_FILE_GAME_MAT_GLSL) + usemat = false; // create the canvas, rasterizer and rendertools RAS_ICanvas* canvas = new KX_BlenderCanvas(area); @@ -184,6 +170,13 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, NG_NetworkDeviceInterface* networkdevice = new NG_LoopBackNetworkDeviceInterface(); + // + SYS_SystemHandle hSystem = SYS_GetSystem(); + bool noaudio = SYS_GetCommandLineInt(hSystem,"noaudio",0); + + if (noaudio)/*(noaudio) intrr: disable game engine audio (openal) */ + SND_DeviceManager::SetDeviceType(snd_e_dummydevice); + // get an audiodevice SND_DeviceManager::Subscribe(); SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance(); @@ -212,6 +205,7 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, // some blender stuff MT_CmMatrix4x4 projmat; MT_CmMatrix4x4 viewmat; + float camzoom; int i; for (i = 0; i < 16; i++) @@ -225,8 +219,13 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, projmat.setElem(i, projmat_linear[i]); } - float camzoom = (1.41421 + (v3d->camzoom / 50.0)); - camzoom *= camzoom; + if(v3d->persp==V3D_CAMOB) { + camzoom = (1.41421 + (v3d->camzoom / 50.0)); + camzoom *= camzoom; + } + else + camzoom = 2.0; + camzoom = 4.0 / camzoom; ketsjiengine->SetDrawType(v3d->drawtype); @@ -307,6 +306,7 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, ketsjiengine->SetCameraOverrideUseOrtho((v3d->persp == V3D_ORTHO)); ketsjiengine->SetCameraOverrideProjectionMatrix(projmat); ketsjiengine->SetCameraOverrideViewMatrix(viewmat); + ketsjiengine->SetCameraOverrideClipping(v3d->near, v3d->far); } // create a scene converter, create and convert the startingscene @@ -315,24 +315,28 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, sceneconverter->addInitFromFrame=false; if (always_use_expand_framing) sceneconverter->SetAlwaysUseExpandFraming(true); - - if(usemat) + + if(usemat && (G.fileflags & G_FILE_GAME_MAT)) sceneconverter->SetMaterials(true); - if(useglslmat) + if(useglslmat && (G.fileflags & G_FILE_GAME_MAT_GLSL)) sceneconverter->SetGLSLMaterials(true); KX_Scene* startscene = new KX_Scene(keyboarddevice, mousedevice, networkdevice, audiodevice, - startscenename); + startscenename, + blscene); // some python things PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest); ketsjiengine->SetPythonDictionary(dictionaryobject); initRasterizer(rasterizer, canvas); - PyObject *gameLogic = initGameLogic(startscene); + PyObject *gameLogic = initGameLogic(ketsjiengine, startscene); + PyDict_SetItemString(PyModule_GetDict(gameLogic), "globalDict", pyGlobalDict); // Same as importing the module. + PyObject *gameLogic_keys = PyDict_Keys(PyModule_GetDict(gameLogic)); PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module. + initGameKeys(); initPythonConstraintBinding(); initMathutils(); @@ -362,6 +366,7 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, ketsjiengine->SetAnimFrameRate( (((double) blscene->r.frs_sec) / blscene->r.frs_sec_base) ); // the mainloop + printf("\nBlender Game Engine Started\n\n"); while (!exitrequested) { // first check if we want to exit @@ -397,6 +402,7 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, mousedevice->ConvertBlenderEvent(event,val); } } + printf("\nBlender Game Engine Finished\n\n"); exitstring = ketsjiengine->GetExitString(); // when exiting the mainloop @@ -406,7 +412,20 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, // inside the GameLogic dictionary when the python interpreter is finalized. // which allows the scene to safely delete them :) // see: (space.c)->start_game - PyDict_Clear(PyModule_GetDict(gameLogic)); + + //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++) { + PyObject* item = PyList_GET_ITEM(gameLogic_keys_new, listIndex); + if (!PySequence_Contains(gameLogic_keys, item)) { + PyDict_DelItem( PyModule_GetDict(gameLogic), item); + } + } + Py_DECREF(gameLogic_keys_new); + gameLogic_keys_new = NULL; ketsjiengine->StopEngine(); exitGamePythonScripting(); @@ -417,6 +436,9 @@ extern "C" void StartKetsjiShell(struct ScrArea *area, delete sceneconverter; sceneconverter = NULL; } + + Py_DECREF(gameLogic_keys); + gameLogic_keys = NULL; } // set the cursor back to normal canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); @@ -545,8 +567,6 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, // create the ketsjiengine KX_KetsjiEngine* ketsjiengine = new KX_KetsjiEngine(kxsystem); - int i; - Scene *blscene = NULL; if (!bfd) { @@ -562,7 +582,7 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, } else { blscene = bfd->curscene; } - int cframe,startFrame; + int cframe = 1, startFrame; if (blscene) { cframe=blscene->r.cfra; @@ -593,12 +613,14 @@ extern "C" void StartKetsjiShellSimulation(struct ScrArea *area, mousedevice, networkdevice, audiodevice, - startscenename); + startscenename, + blscene); + // some python things PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest); ketsjiengine->SetPythonDictionary(dictionaryobject); initRasterizer(rasterizer, canvas); - PyObject *gameLogic = initGameLogic(startscene); + PyObject *gameLogic = initGameLogic(ketsjiengine, startscene); PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module initGameKeys(); initPythonConstraintBinding(); diff --git a/source/gameengine/BlenderRoutines/CMakeLists.txt b/source/gameengine/BlenderRoutines/CMakeLists.txt index 1d72fb9cde1..340a1ae310b 100644 --- a/source/gameengine/BlenderRoutines/CMakeLists.txt +++ b/source/gameengine/BlenderRoutines/CMakeLists.txt @@ -31,6 +31,7 @@ SET(INC ../../../intern/SoundSystem ../../../source/blender/misc ../../../source/blender/blenloader + ../../../source/blender/gpu ../../../extern/bullet2/src ../../../extern/solid ../../../extern/glew/include diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp index da52be56d1b..669e7bd1b3f 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp @@ -26,7 +26,6 @@ * ***** END GPL LICENSE BLOCK ***** */ -#include "GL/glew.h" #include "KX_BlenderGL.h" #ifdef HAVE_CONFIG_H @@ -93,80 +92,6 @@ void BL_SwapBuffers() myswapbuffers(); } -void BL_RenderText(int mode,const char* textstr,int textlen,struct MTFace* tface, - unsigned int *col,float v1[3],float v2[3],float v3[3],float v4[3]) -{ - Image* ima; - - if(mode & TF_BMFONT) { - //char string[MAX_PROPSTRING]; - int characters, index, character; - float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance; - -// bProperty *prop; - - // string = "Frank van Beek"; - - characters = textlen; - - ima = (struct Image*) tface->tpage; - if (ima == NULL) { - characters = 0; - } - - /* When OBCOL flag is on the color is set in IndexPrimitives_3DText */ - if (tface->mode & TF_OBCOL) { /* Color has been set */ - col= NULL; - } else { - if(!col) glColor3f(1.0f, 1.0f, 1.0f); - } - - glPushMatrix(); - for (index = 0; index < characters; index++) { - // lets calculate offset stuff - character = textstr[index]; - - // space starts at offset 1 - // character = character - ' ' + 1; - - matrixGlyph((ImBuf *)ima->ibufs.first, character, & centerx, ¢ery, &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); - - glBegin(GL_POLYGON); - // printf(" %c %f %f %f %f\n", character, tface->uv[0][0], tface->uv[0][1], ); - // glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy); - glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy); - - if(col) spack(col[0]); - // glVertex3fv(v1); - glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]); - - glTexCoord2f((tface->uv[1][0] - centerx) * sizex + transx, (tface->uv[1][1] - centery) * sizey + transy); - if(col) spack(col[1]); - // glVertex3fv(v2); - glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]); - - glTexCoord2f((tface->uv[2][0] - centerx) * sizex + transx, (tface->uv[2][1] - centery) * sizey + transy); - if(col) spack(col[2]); - // glVertex3fv(v3); - glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]); - - if(v4) { - // glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, 1.0 - (1.0 - tface->uv[3][1]) * sizey - transy); - glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, (tface->uv[3][1] - centery) * sizey + transy); - if(col) spack(col[3]); - // glVertex3fv(v4); - glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]); - } - glEnd(); - - glTranslatef(advance, 0.0, 0.0); - } - glPopMatrix(); - - } -} - - void DisableForText() { if(glIsEnabled(GL_BLEND)) glDisable(GL_BLEND); diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.h b/source/gameengine/BlenderRoutines/KX_BlenderGL.h index c8e0d47afb6..b891a7343c2 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderGL.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.h @@ -46,9 +46,6 @@ void BL_HideMouse(); void BL_NormalMouse(); void BL_WaitMouse(); -void BL_RenderText(int mode,const char* textstr,int textlen,struct MTFace* tface, - unsigned int *col,float v1[3],float v2[3],float v3[3],float v4[3]); - void BL_print_gamedebug_line(char* text, int xco, int yco, int width, int height); void BL_print_gamedebug_line_padded(char* text, int xco, int yco, int width, int height); diff --git a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp index e4eff163d5b..1797d6c1a0f 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp @@ -26,8 +26,6 @@ * ***** END GPL LICENSE BLOCK ***** */ -#include "KX_BlenderRenderTools.h" - #include "GL/glew.h" #include "RAS_IRenderTools.h" @@ -36,23 +34,22 @@ #include "RAS_ICanvas.h" #include "RAS_GLExtensionManager.h" -// next two includes/dependencies come from the shadow feature -// it needs the gameobject and the sumo physics scene for a raycast #include "KX_GameObject.h" - #include "KX_PolygonMaterial.h" #include "KX_BlenderMaterial.h" +#include "KX_RayCast.h" +#include "KX_IPhysicsController.h" -#include "Value.h" +#include "PHY_IPhysicsEnvironment.h" -#include "KX_BlenderGL.h" // for text printing #include "STR_String.h" -#include "RAS_BucketManager.h" // for polymaterial (needed for textprinting) -#include "KX_RayCast.h" -#include "KX_IPhysicsController.h" -#include "PHY_IPhysicsEnvironment.h" -#include "KX_Scene.h" +#include "GPU_draw.h" + +#include "KX_BlenderGL.h" // for text printing +#include "KX_BlenderRenderTools.h" + +unsigned int KX_BlenderRenderTools::m_numgllights; KX_BlenderRenderTools::KX_BlenderRenderTools() { @@ -61,81 +58,98 @@ KX_BlenderRenderTools::KX_BlenderRenderTools() m_numgllights = 8; } -/** -ProcessLighting performs lighting on objects. the layer is a bitfield that contains layer information. -There are 20 'official' layers in blender. -A light is applied on an object only when they are in the same layer. -OpenGL has a maximum of 8 lights (simultaneous), so 20 * 8 lights are possible in a scene. -*/ +KX_BlenderRenderTools::~KX_BlenderRenderTools() +{ +} -int KX_BlenderRenderTools::ProcessLighting(int layer) +void KX_BlenderRenderTools::BeginFrame(RAS_IRasterizer* rasty) { - - int result = false; + m_clientobject = NULL; + m_lastlightlayer = -1; + m_lastlighting = false; + DisableOpenGLLights(); +} - if (layer < 0) - { - DisableOpenGLLights(); - result = false; - } else +void KX_BlenderRenderTools::EndFrame(RAS_IRasterizer* rasty) +{ +} + +/* ProcessLighting performs lighting on objects. the layer is a bitfield that + * contains layer information. There are 20 'official' layers in blender. A + * light is applied on an object only when they are in the same layer. OpenGL + * has a maximum of 8 lights (simultaneous), so 20 * 8 lights are possible in + * a scene. */ + +void KX_BlenderRenderTools::ProcessLighting(int layer, const MT_Transform& viewmat) +{ + if(m_lastlightlayer == layer) + return; + + m_lastlightlayer = layer; + + bool enable = false; + + if (layer >= 0) { if (m_clientobject) { if (layer == RAS_LIGHT_OBJECT_LAYER) - { layer = static_cast<KX_GameObject*>(m_clientobject)->GetLayer(); - } - if (applyLights(layer)) - { - EnableOpenGLLights(); - result = true; - } else - { - DisableOpenGLLights(); - result = false; - } + + enable = applyLights(layer, viewmat); } } - return result; - - + + if(enable) + EnableOpenGLLights(); + else + DisableOpenGLLights(); } +void KX_BlenderRenderTools::EnableOpenGLLights() +{ + if(m_lastlighting == true) + return; -void KX_BlenderRenderTools::BeginFrame(RAS_IRasterizer* rasty) + glEnable(GL_LIGHTING); + glEnable(GL_COLOR_MATERIAL); + + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, true); + if (GLEW_EXT_separate_specular_color || GLEW_VERSION_1_2) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); + + m_lastlighting = true; +} + +void KX_BlenderRenderTools::DisableOpenGLLights() { - m_clientobject = NULL; - m_lastblenderobject = NULL; - m_lastblenderlights = false; - m_lastlayer = -1; - m_lastlighting = false; - m_modified = true; - DisableOpenGLLights(); + if(m_lastlighting == false) + return; + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + m_lastlighting = false; } -void KX_BlenderRenderTools::SetClientObject(void* obj) + +void KX_BlenderRenderTools::SetClientObject(RAS_IRasterizer *rasty, void* obj) { if (m_clientobject != obj) { - if (obj == NULL || !((KX_GameObject*)obj)->IsNegativeScaling()) - { - glFrontFace(GL_CCW); - } else - { - glFrontFace(GL_CW); - } + bool ccw = (obj == NULL || !((KX_GameObject*)obj)->IsNegativeScaling()); + rasty->SetFrontFace(ccw); + m_clientobject = obj; - m_modified = true; } } -bool KX_BlenderRenderTools::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_BlenderRenderTools::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { double* const oglmatrix = (double* const) data; - MT_Point3 resultpoint(hit_point); - MT_Vector3 resultnormal(hit_normal); + MT_Point3 resultpoint(result->m_hitPoint); + MT_Vector3 resultnormal(result->m_hitNormal); MT_Vector3 left(oglmatrix[0],oglmatrix[1],oglmatrix[2]); MT_Vector3 dir = -(left.cross(resultnormal)).safe_normalized(); left = (dir.cross(resultnormal)).safe_normalized(); @@ -182,7 +196,7 @@ void KX_BlenderRenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmat MT_Vector3 dir = (campos - objpos).safe_normalized(); MT_Vector3 up(0,0,1.0); - KX_GameObject* gameobj = (KX_GameObject*) this->m_clientobject; + KX_GameObject* gameobj = (KX_GameObject*)m_clientobject; // get scaling of halo object MT_Vector3 size = gameobj->GetSGNode()->GetLocalScale(); @@ -218,7 +232,7 @@ void KX_BlenderRenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmat { // shadow must be cast to the ground, physics system needed here! MT_Point3 frompoint(oglmatrix[12],oglmatrix[13],oglmatrix[14]); - KX_GameObject *gameobj = (KX_GameObject*) this->m_clientobject; + KX_GameObject *gameobj = (KX_GameObject*)m_clientobject; MT_Vector3 direction = MT_Vector3(0,0,-1); direction.normalize(); @@ -236,9 +250,8 @@ void KX_BlenderRenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmat if (parent) parent->Release(); - MT_Point3 resultpoint; - MT_Vector3 resultnormal; - if (!KX_RayCast::RayTest(physics_controller, physics_environment, frompoint, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_BlenderRenderTools>(this, oglmatrix))) + KX_RayCast::Callback<KX_BlenderRenderTools> callback(this, physics_controller, oglmatrix); + if (!KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback)) { // couldn't find something to cast the shadow on... glMultMatrixd(oglmatrix); @@ -253,13 +266,29 @@ void KX_BlenderRenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmat } -/** -Render Text renders text into a (series of) polygon, using a texture font, -Each character consists of one polygon (one quad or two triangles) -*/ -void KX_BlenderRenderTools::RenderText(int mode,RAS_IPolyMaterial* polymat,float v1[3],float v2[3],float v3[3],float v4[3]) +void KX_BlenderRenderTools::RenderText2D(RAS_TEXT_RENDER_MODE mode, + const char* text, + int xco, + int yco, + int width, + int height) +{ + STR_String tmpstr(text); + + if(mode == RAS_IRenderTools::RAS_TEXT_PADDED) + BL_print_gamedebug_line_padded(tmpstr.Ptr(), xco, yco, width, height); + else + BL_print_gamedebug_line(tmpstr.Ptr(), xco, yco, width, height); +} + +/* Render Text renders text into a (series of) polygon, using a texture font, + * Each character consists of one polygon (one quad or two triangles) */ + +void KX_BlenderRenderTools::RenderText( + int mode, + RAS_IPolyMaterial* polymat, + float v1[3], float v2[3], float v3[3], float v4[3], int glattrib) { - STR_String mytext = ((CValue*)m_clientobject)->GetPropertyText("Text"); const unsigned int flag = polymat->GetFlag(); @@ -276,67 +305,9 @@ void KX_BlenderRenderTools::RenderText(int mode,RAS_IPolyMaterial* polymat,float col = blenderpoly->GetMCol(); } - BL_RenderText( mode,mytext,mytext.Length(),tface,col,v1,v2,v3,v4); - -} - - - -KX_BlenderRenderTools::~KX_BlenderRenderTools() -{ -}; - - -void KX_BlenderRenderTools::EndFrame(RAS_IRasterizer* rasty) -{ + GPU_render_text(tface, mode, mytext, mytext.Length(), col, v1, v2, v3, v4, glattrib); } - - -void KX_BlenderRenderTools::DisableOpenGLLights() -{ - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); -} - - -void KX_BlenderRenderTools::EnableOpenGLLights() -{ - glEnable(GL_LIGHTING); - - glEnable(GL_COLOR_MATERIAL); - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, true); - if (GLEW_EXT_separate_specular_color || GLEW_VERSION_1_2) - glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); - -} - - -/** - * Rendering text using 2D bitmap functionality. - */ -void KX_BlenderRenderTools::RenderText2D(RAS_TEXT_RENDER_MODE mode, - const char* text, - int xco, - int yco, - int width, - int height) -{ - switch (mode) { - case RAS_IRenderTools::RAS_TEXT_PADDED: { - STR_String tmpstr(text); - BL_print_gamedebug_line_padded(tmpstr.Ptr(),xco,yco,width,height); - break; - } - default: { - STR_String tmpstr(text); - BL_print_gamedebug_line(tmpstr.Ptr(),xco,yco,width,height); - } - } -} - - void KX_BlenderRenderTools::PushMatrix() { @@ -349,14 +320,13 @@ void KX_BlenderRenderTools::PopMatrix() } - -int KX_BlenderRenderTools::applyLights(int objectlayer) +int KX_BlenderRenderTools::applyLights(int objectlayer, const MT_Transform& viewmat) { -// taken from blender source, incompatibility between Blender Object / GameObject - + // taken from blender source, incompatibility between Blender Object / GameObject + float glviewmat[16]; unsigned int count; float vec[4]; - + vec[3]= 1.0; for(count=0; count<m_numgllights; count++) @@ -364,9 +334,11 @@ int KX_BlenderRenderTools::applyLights(int objectlayer) //std::vector<struct RAS_LightObject*> m_lights; std::vector<struct RAS_LightObject*>::iterator lit = m_lights.begin(); + + viewmat.getValue(glviewmat); glPushMatrix(); - glLoadMatrixf(m_viewmat); + glLoadMatrixf(glviewmat); for (lit = m_lights.begin(), count = 0; !(lit==m_lights.end()) && count < m_numgllights; ++lit) { RAS_LightObject* lightdata = (*lit); @@ -434,7 +406,6 @@ int KX_BlenderRenderTools::applyLights(int objectlayer) glEnable((GLenum)(GL_LIGHT0+count)); count++; - } } glPopMatrix(); @@ -443,22 +414,6 @@ int KX_BlenderRenderTools::applyLights(int objectlayer) } - - -RAS_IPolyMaterial* KX_BlenderRenderTools::CreateBlenderPolyMaterial( - const STR_String &texname, - bool ba,const STR_String& matname,int tile,int tilexrep,int tileyrep,int mode,bool transparant,bool zsort, int lightlayer - ,bool bIsTriangle,void* clientobject,void* tface) -{ - assert(!"Deprecated"); -/* return new KX_BlenderPolyMaterial( - - texname, - ba,matname,tile,tilexrep,tileyrep,mode,transparant,zsort, lightlayer - ,bIsTriangle,clientobject,(struct MTFace*)tface);*/ - return NULL; -} - void KX_BlenderRenderTools::MotionBlur(RAS_IRasterizer* rasterizer) { int state = rasterizer->GetMotionBlurState(); @@ -492,4 +447,3 @@ void KX_BlenderRenderTools::Render2DFilters(RAS_ICanvas* canvas) m_filtermanager.RenderFilters(canvas); } -unsigned int KX_BlenderRenderTools::m_numgllights; diff --git a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h index 8abce1b8c3e..a7618462c9b 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.h @@ -26,6 +26,7 @@ * * ***** END GPL LICENSE BLOCK ***** */ + #ifndef __KX_BLENDERRENDERTOOLS #define __KX_BLENDERRENDERTOOLS @@ -37,67 +38,54 @@ #include "RAS_IRenderTools.h" struct KX_ClientObjectInfo; +class KX_RayCast; -/** -BlenderRenderTools are a set of tools to apply 2D/3D graphics effects, which are not -part of the (polygon) Rasterizer. -Effects like 2D text, 3D (polygon) text, lighting. -*/ +/* BlenderRenderTools are a set of tools to apply 2D/3D graphics effects, which + * are not part of the (polygon) Rasterizer. Effects like 2D text, 3D (polygon) + * text, lighting. + * + * Most of this code is duplicated in GPC_RenderTools, so this should be + * moved to some common location to avoid duplication. */ class KX_BlenderRenderTools : public RAS_IRenderTools { - bool m_lastblenderlights; - void* m_lastblenderobject; - int m_lastlayer; + int m_lastlightlayer; bool m_lastlighting; static unsigned int m_numgllights; - - + public: - KX_BlenderRenderTools(); virtual ~KX_BlenderRenderTools(); - virtual void EndFrame(class RAS_IRasterizer* rasty); - virtual void BeginFrame(class RAS_IRasterizer* rasty); - void DisableOpenGLLights(); + void EndFrame(RAS_IRasterizer* rasty); + void BeginFrame(RAS_IRasterizer* rasty); + void EnableOpenGLLights(); - int ProcessLighting(int layer); + void DisableOpenGLLights(); + void ProcessLighting(int layer, const MT_Transform& viewmat); - virtual void RenderText2D(RAS_TEXT_RENDER_MODE mode, + void RenderText2D(RAS_TEXT_RENDER_MODE mode, const char* text, int xco, int yco, int width, int height); - virtual void RenderText(int mode, + void RenderText(int mode, class RAS_IPolyMaterial* polymat, float v1[3], float v2[3], float v3[3], - float v4[3]); - void applyTransform(class RAS_IRasterizer* rasty, - double* oglmatrix, - int objectdrawmode ); - int applyLights(int objectlayer); - virtual void PushMatrix(); - virtual void PopMatrix(); - - virtual class RAS_IPolyMaterial* CreateBlenderPolyMaterial(const STR_String &texname, - bool ba, - const STR_String& matname, - int tile, - int tilexrep, - int tileyrep, - int mode, - bool transparant, - bool zsort, - int lightlayer, - bool bIsTriangle, - void* clientobject, - void* tface); - - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + float v4[3], + int glattrib); + + void applyTransform(RAS_IRasterizer* rasty, double* oglmatrix, int objectdrawmode); + int applyLights(int objectlayer, const MT_Transform& viewmat); + + void PushMatrix(); + void PopMatrix(); + + bool RayHit(KX_ClientObjectInfo* client, class KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo*) { return true; } virtual void MotionBlur(RAS_IRasterizer* rasterizer); @@ -105,8 +93,7 @@ public: virtual void Render2DFilters(RAS_ICanvas* canvas); - virtual void SetClientObject(void* obj); - + virtual void SetClientObject(RAS_IRasterizer *rasty, void* obj); }; #endif //__KX_BLENDERRENDERTOOLS diff --git a/source/gameengine/BlenderRoutines/Makefile b/source/gameengine/BlenderRoutines/Makefile index a7394158a20..4b9a2a3af17 100644 --- a/source/gameengine/BlenderRoutines/Makefile +++ b/source/gameengine/BlenderRoutines/Makefile @@ -54,6 +54,7 @@ CPPFLAGS += -I../../blender/blenkernel CPPFLAGS += -I../../blender/render/extern/include CPPFLAGS += -I../../blender/blenloader CPPFLAGS += -I../../blender/blenkernel +CPPFLAGS += -I../../blender/gpu CPPFLAGS += -I../Converter CPPFLAGS += -I../Expressions CPPFLAGS += -I../GameLogic @@ -72,9 +73,5 @@ ifeq ($(OS),windows) CPPFLAGS += -I../../blender endif -ifeq ($(WITH_BF_GLEXT),true) - CPPFLAGS += -DWITH_GLEXT -endif - CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) diff --git a/source/gameengine/BlenderRoutines/SConscript b/source/gameengine/BlenderRoutines/SConscript index 327f4798e04..78adbc83d9b 100644 --- a/source/gameengine/BlenderRoutines/SConscript +++ b/source/gameengine/BlenderRoutines/SConscript @@ -15,7 +15,7 @@ incs += ' #source/gameengine/SceneGraph #source/gameengine/Physics/common' incs += ' #source/gameengine/Physics/Bullet #source/gameengine/Physics/Sumo' incs += ' #source/gameengine/Physics/Sumo/Fuzzics/include #source/gameengine/Network/LoopBackNetwork' incs += ' #intern/SoundSystem #source/blender/misc #source/blender/blenloader' -incs += ' #extern/glew/include' +incs += ' #extern/glew/include #source/blender/gpu' incs += ' ' + env['BF_PYTHON_INC'] incs += ' ' + env['BF_SOLID_INC'] @@ -26,7 +26,4 @@ cxxflags = [] if env['OURPLATFORM']=='win32-vc': cxxflags.append ('/GR') -if env['WITH_BF_GLEXT'] == 1: - env['CPPFLAGS'].append('-DWITH_GLEXT') - env.BlenderLib ( 'bf_bloutines', sources, Split(incs), [], libtype=['game', 'game2', 'player'], priority=[0, 0, 55] , compileflags=cxxflags) diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index d8b2e063a9d..4d748948c27 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -50,6 +50,7 @@ #include "MT_Matrix4x4.h" #include "BKE_utildefines.h" #include "FloatValue.h" +#include "PyObjectPlus.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -58,11 +59,11 @@ BL_ActionActuator::~BL_ActionActuator() { if (m_pose) - free_pose(m_pose); + game_free_pose(m_pose); if (m_userpose) - free_pose(m_userpose); + game_free_pose(m_userpose); if (m_blendpose) - free_pose(m_blendpose); + game_free_pose(m_blendpose); } void BL_ActionActuator::ProcessReplica(){ @@ -151,6 +152,8 @@ bool BL_ActionActuator::Update(double curtime, bool frame) bool apply=true; int priority; float newweight; + + curtime -= KX_KetsjiEngine::GetSuspendedDelta(); // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! @@ -445,28 +448,28 @@ PyParentObject BL_ActionActuator::Parents[] = { }; PyMethodDef BL_ActionActuator::Methods[] = { - {"setAction", (PyCFunction) BL_ActionActuator::sPySetAction, METH_VARARGS, SetAction_doc}, - {"setStart", (PyCFunction) BL_ActionActuator::sPySetStart, METH_VARARGS, SetStart_doc}, - {"setEnd", (PyCFunction) BL_ActionActuator::sPySetEnd, METH_VARARGS, SetEnd_doc}, - {"setBlendin", (PyCFunction) BL_ActionActuator::sPySetBlendin, METH_VARARGS, SetBlendin_doc}, - {"setPriority", (PyCFunction) BL_ActionActuator::sPySetPriority, METH_VARARGS, SetPriority_doc}, - {"setFrame", (PyCFunction) BL_ActionActuator::sPySetFrame, METH_VARARGS, SetFrame_doc}, - {"setProperty", (PyCFunction) BL_ActionActuator::sPySetProperty, METH_VARARGS, SetProperty_doc}, - {"setFrameProperty", (PyCFunction) BL_ActionActuator::sPySetFrameProperty, METH_VARARGS, SetFrameProperty_doc}, - {"setBlendtime", (PyCFunction) BL_ActionActuator::sPySetBlendtime, METH_VARARGS, SetBlendtime_doc}, - - {"getAction", (PyCFunction) BL_ActionActuator::sPyGetAction, METH_VARARGS, GetAction_doc}, - {"getStart", (PyCFunction) BL_ActionActuator::sPyGetStart, METH_VARARGS, GetStart_doc}, - {"getEnd", (PyCFunction) BL_ActionActuator::sPyGetEnd, METH_VARARGS, GetEnd_doc}, - {"getBlendin", (PyCFunction) BL_ActionActuator::sPyGetBlendin, METH_VARARGS, GetBlendin_doc}, - {"getPriority", (PyCFunction) BL_ActionActuator::sPyGetPriority, METH_VARARGS, GetPriority_doc}, - {"getFrame", (PyCFunction) BL_ActionActuator::sPyGetFrame, METH_VARARGS, GetFrame_doc}, - {"getProperty", (PyCFunction) BL_ActionActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc}, - {"getFrameProperty", (PyCFunction) BL_ActionActuator::sPyGetFrameProperty, METH_VARARGS, GetFrameProperty_doc}, - {"setChannel", (PyCFunction) BL_ActionActuator::sPySetChannel, METH_VARARGS, SetChannel_doc}, + {"setAction", (PyCFunction) BL_ActionActuator::sPySetAction, METH_VARARGS, (PY_METHODCHAR)SetAction_doc}, + {"setStart", (PyCFunction) BL_ActionActuator::sPySetStart, METH_VARARGS, (PY_METHODCHAR)SetStart_doc}, + {"setEnd", (PyCFunction) BL_ActionActuator::sPySetEnd, METH_VARARGS, (PY_METHODCHAR)SetEnd_doc}, + {"setBlendin", (PyCFunction) BL_ActionActuator::sPySetBlendin, METH_VARARGS, (PY_METHODCHAR)SetBlendin_doc}, + {"setPriority", (PyCFunction) BL_ActionActuator::sPySetPriority, METH_VARARGS, (PY_METHODCHAR)SetPriority_doc}, + {"setFrame", (PyCFunction) BL_ActionActuator::sPySetFrame, METH_VARARGS, (PY_METHODCHAR)SetFrame_doc}, + {"setProperty", (PyCFunction) BL_ActionActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, + {"setFrameProperty", (PyCFunction) BL_ActionActuator::sPySetFrameProperty, METH_VARARGS, (PY_METHODCHAR)SetFrameProperty_doc}, + {"setBlendtime", (PyCFunction) BL_ActionActuator::sPySetBlendtime, METH_VARARGS, (PY_METHODCHAR)SetBlendtime_doc}, + + {"getAction", (PyCFunction) BL_ActionActuator::sPyGetAction, METH_VARARGS, (PY_METHODCHAR)GetAction_doc}, + {"getStart", (PyCFunction) BL_ActionActuator::sPyGetStart, METH_VARARGS, (PY_METHODCHAR)GetStart_doc}, + {"getEnd", (PyCFunction) BL_ActionActuator::sPyGetEnd, METH_VARARGS, (PY_METHODCHAR)GetEnd_doc}, + {"getBlendin", (PyCFunction) BL_ActionActuator::sPyGetBlendin, METH_VARARGS, (PY_METHODCHAR)GetBlendin_doc}, + {"getPriority", (PyCFunction) BL_ActionActuator::sPyGetPriority, METH_VARARGS, (PY_METHODCHAR)GetPriority_doc}, + {"getFrame", (PyCFunction) BL_ActionActuator::sPyGetFrame, METH_VARARGS, (PY_METHODCHAR)GetFrame_doc}, + {"getProperty", (PyCFunction) BL_ActionActuator::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, + {"getFrameProperty", (PyCFunction) BL_ActionActuator::sPyGetFrameProperty, METH_VARARGS, (PY_METHODCHAR)GetFrameProperty_doc}, + {"setChannel", (PyCFunction) BL_ActionActuator::sPySetChannel, METH_VARARGS, (PY_METHODCHAR)SetChannel_doc}, // {"getChannel", (PyCFunction) BL_ActionActuator::sPyGetChannel, METH_VARARGS}, - {"getType", (PyCFunction) BL_ActionActuator::sPyGetType, METH_VARARGS, GetType_doc}, - {"setType", (PyCFunction) BL_ActionActuator::sPySetType, METH_VARARGS, SetType_doc}, + {"getType", (PyCFunction) BL_ActionActuator::sPyGetType, METH_VARARGS, (PY_METHODCHAR)GetType_doc}, + {"setType", (PyCFunction) BL_ActionActuator::sPySetType, METH_VARARGS, (PY_METHODCHAR)SetType_doc}, {"getContinue", (PyCFunction) BL_ActionActuator::sPyGetContinue, METH_NOARGS, 0}, {"setContinue", (PyCFunction) BL_ActionActuator::sPySetContinue, METH_O, 0}, {NULL,NULL} //Sentinel @@ -477,7 +480,7 @@ PyObject* BL_ActionActuator::_getattr(const STR_String& attr) { } /* setStart */ -char BL_ActionActuator::GetAction_doc[] = +const char BL_ActionActuator::GetAction_doc[] = "getAction()\n" "\tReturns a string containing the name of the current action.\n"; @@ -491,7 +494,7 @@ PyObject* BL_ActionActuator::PyGetAction(PyObject* self, } /* getProperty */ -char BL_ActionActuator::GetProperty_doc[] = +const char BL_ActionActuator::GetProperty_doc[] = "getProperty()\n" "\tReturns the name of the property to be used in FromProp mode.\n"; @@ -506,7 +509,7 @@ PyObject* BL_ActionActuator::PyGetProperty(PyObject* self, } /* getProperty */ -char BL_ActionActuator::GetFrameProperty_doc[] = +const char BL_ActionActuator::GetFrameProperty_doc[] = "getFrameProperty()\n" "\tReturns the name of the property, that is set to the current frame number.\n"; @@ -521,7 +524,7 @@ PyObject* BL_ActionActuator::PyGetFrameProperty(PyObject* self, } /* getFrame */ -char BL_ActionActuator::GetFrame_doc[] = +const char BL_ActionActuator::GetFrame_doc[] = "getFrame()\n" "\tReturns the current frame number.\n"; @@ -536,7 +539,7 @@ PyObject* BL_ActionActuator::PyGetFrame(PyObject* self, } /* getEnd */ -char BL_ActionActuator::GetEnd_doc[] = +const char BL_ActionActuator::GetEnd_doc[] = "getEnd()\n" "\tReturns the last frame of the action.\n"; @@ -551,7 +554,7 @@ PyObject* BL_ActionActuator::PyGetEnd(PyObject* self, } /* getStart */ -char BL_ActionActuator::GetStart_doc[] = +const char BL_ActionActuator::GetStart_doc[] = "getStart()\n" "\tReturns the starting frame of the action.\n"; @@ -566,7 +569,7 @@ PyObject* BL_ActionActuator::PyGetStart(PyObject* self, } /* getBlendin */ -char BL_ActionActuator::GetBlendin_doc[] = +const char BL_ActionActuator::GetBlendin_doc[] = "getBlendin()\n" "\tReturns the number of interpolation animation frames to be\n" "\tgenerated when this actuator is triggered.\n"; @@ -582,7 +585,7 @@ PyObject* BL_ActionActuator::PyGetBlendin(PyObject* self, } /* getPriority */ -char BL_ActionActuator::GetPriority_doc[] = +const char BL_ActionActuator::GetPriority_doc[] = "getPriority()\n" "\tReturns the priority for this actuator. Actuators with lower\n" "\tPriority numbers will override actuators with higher numbers.\n"; @@ -598,7 +601,7 @@ PyObject* BL_ActionActuator::PyGetPriority(PyObject* self, } /* setAction */ -char BL_ActionActuator::SetAction_doc[] = +const char BL_ActionActuator::SetAction_doc[] = "setAction(action, (reset))\n" "\t - action : The name of the action to set as the current action.\n" "\t - reset : Optional parameter indicating whether to reset the\n" @@ -637,7 +640,7 @@ PyObject* BL_ActionActuator::PySetAction(PyObject* self, } /* setStart */ -char BL_ActionActuator::SetStart_doc[] = +const char BL_ActionActuator::SetStart_doc[] = "setStart(start)\n" "\t - start : Specifies the starting frame of the animation.\n"; @@ -658,7 +661,7 @@ PyObject* BL_ActionActuator::PySetStart(PyObject* self, } /* setEnd */ -char BL_ActionActuator::SetEnd_doc[] = +const char BL_ActionActuator::SetEnd_doc[] = "setEnd(end)\n" "\t - end : Specifies the ending frame of the animation.\n"; @@ -679,7 +682,7 @@ PyObject* BL_ActionActuator::PySetEnd(PyObject* self, } /* setBlendin */ -char BL_ActionActuator::SetBlendin_doc[] = +const char BL_ActionActuator::SetBlendin_doc[] = "setBlendin(blendin)\n" "\t - blendin : Specifies the number of frames of animation to generate\n" "\t when making transitions between actions.\n"; @@ -701,7 +704,7 @@ PyObject* BL_ActionActuator::PySetBlendin(PyObject* self, } /* setBlendtime */ -char BL_ActionActuator::SetBlendtime_doc[] = +const char BL_ActionActuator::SetBlendtime_doc[] = "setBlendtime(blendtime)\n" "\t - blendtime : Allows the script to directly modify the internal timer\n" "\t used when generating transitions between actions. This\n" @@ -728,7 +731,7 @@ PyObject* BL_ActionActuator::PySetBlendtime(PyObject* self, } /* setPriority */ -char BL_ActionActuator::SetPriority_doc[] = +const char BL_ActionActuator::SetPriority_doc[] = "setPriority(priority)\n" "\t - priority : Specifies the new priority. Actuators will lower\n" "\t priority numbers will override actuators with higher\n" @@ -751,7 +754,7 @@ PyObject* BL_ActionActuator::PySetPriority(PyObject* self, } /* setFrame */ -char BL_ActionActuator::SetFrame_doc[] = +const char BL_ActionActuator::SetFrame_doc[] = "setFrame(frame)\n" "\t - frame : Specifies the new current frame for the animation\n"; @@ -776,7 +779,7 @@ PyObject* BL_ActionActuator::PySetFrame(PyObject* self, } /* setProperty */ -char BL_ActionActuator::SetProperty_doc[] = +const char BL_ActionActuator::SetProperty_doc[] = "setProperty(prop)\n" "\t - prop : A string specifying the property name to be used in\n" "\t FromProp playback mode.\n"; @@ -798,7 +801,7 @@ PyObject* BL_ActionActuator::PySetProperty(PyObject* self, } /* setFrameProperty */ -char BL_ActionActuator::SetFrameProperty_doc[] = +const char BL_ActionActuator::SetFrameProperty_doc[] = "setFrameProperty(prop)\n" "\t - prop : A string specifying the property of the frame set up update.\n"; @@ -837,7 +840,7 @@ PyObject* BL_ActionActuator::PyGetChannel(PyObject* self, */ /* setChannel */ -char BL_ActionActuator::SetChannel_doc[] = +const char BL_ActionActuator::SetChannel_doc[] = "setChannel(channel, matrix)\n" "\t - channel : A string specifying the name of the bone channel.\n" "\t - matrix : A 4x4 matrix specifying the overriding transformation\n" @@ -921,7 +924,7 @@ PyObject* BL_ActionActuator::PySetChannel(PyObject* self, } /* getType */ -char BL_ActionActuator::GetType_doc[] = +const char BL_ActionActuator::GetType_doc[] = "getType()\n" "\tReturns the operation mode of the actuator.\n"; PyObject* BL_ActionActuator::PyGetType(PyObject* self, @@ -931,7 +934,7 @@ PyObject* BL_ActionActuator::PyGetType(PyObject* self, } /* setType */ -char BL_ActionActuator::SetType_doc[] = +const char BL_ActionActuator::SetType_doc[] = "setType(mode)\n" "\t - mode: Play (0), Flipper (2), LoopStop (3), LoopEnd (4) or Property (6)\n" "\tSet the operation mode of the actuator.\n"; diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index 09f1d9d4d87..d2001212f7d 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -45,7 +45,6 @@ #include <config.h> #endif - BL_ArmatureObject::BL_ArmatureObject( void* sgReplicationInfo, SG_Callbacks callbacks, @@ -53,15 +52,20 @@ BL_ArmatureObject::BL_ArmatureObject( : KX_GameObject(sgReplicationInfo,callbacks), m_objArma(armature), - m_mrdPose(NULL), - m_lastframe(0.), + m_framePose(NULL), + m_lastframe(0.0), m_activeAct(NULL), - m_activePriority(999) + m_activePriority(999), + m_lastapplyframe(0.0) { m_armature = get_armature(m_objArma); - m_pose = m_objArma->pose; -} + /* we make a copy of blender object's pose, and then always swap it with + * the original pose before calling into blender functions, to deal with + * replica's or other objects using the same blender object */ + m_pose = NULL; + game_copy_pose(&m_pose, m_objArma->pose); +} CValue* BL_ArmatureObject::GetReplica() { @@ -78,34 +82,37 @@ void BL_ArmatureObject::ProcessReplica(BL_ArmatureObject *replica) { KX_GameObject::ProcessReplica(replica); + replica->m_pose = NULL; + game_copy_pose(&replica->m_pose, m_pose); } BL_ArmatureObject::~BL_ArmatureObject() { - if (m_mrdPose) - free_pose(m_mrdPose); + if (m_pose) + game_free_pose(m_pose); } -/* note, you can only call this for exisiting Armature objects, and not mix it with other Armatures */ -/* there is only 1 unique Pose per Armature */ void BL_ArmatureObject::ApplyPose() { - if (m_pose) { - // copy to armature object - if (m_objArma->pose != m_pose)/* This should never happen but it does - Campbell */ - extract_pose_from_pose(m_objArma->pose, m_pose); - - // is this needed anymore? - //if (!m_mrdPose) - // copy_pose (&m_mrdPose, m_pose, 0); - //else - // extract_pose_from_pose(m_mrdPose, m_pose); + m_armpose = m_objArma->pose; + m_objArma->pose = m_pose; + + if(m_lastapplyframe != m_lastframe) { + where_is_pose(m_objArma); + m_lastapplyframe = m_lastframe; } } +void BL_ArmatureObject::RestorePose() +{ + m_objArma->pose = m_armpose; + m_armpose = NULL; +} + void BL_ArmatureObject::SetPose(bPose *pose) { - m_pose = pose; + extract_pose_from_pose(m_pose, pose); + m_lastapplyframe = -1.0; } bool BL_ArmatureObject::SetActiveAction(BL_ActionActuator *act, short priority, double curtime) @@ -114,10 +121,15 @@ bool BL_ArmatureObject::SetActiveAction(BL_ActionActuator *act, short priority, m_activePriority = 9999; m_lastframe= curtime; m_activeAct = NULL; + // remember the pose at the start of the frame + m_framePose = m_pose; } if (priority<=m_activePriority) { + if (priority<m_activePriority) + // this action overwrites the previous ones, start from initial pose to cancel their effects + m_pose = m_framePose; if (m_activeAct && (m_activeAct!=act)) m_activeAct->SetBlendTime(0.0); /* Reset the blend timer */ m_activeAct = act; @@ -149,13 +161,13 @@ void BL_ArmatureObject::GetPose(bPose **pose) a crash and memory leakage when &BL_ActionActuator::m_pose is freed */ - int copy_constraint_channels_hack = 1; - copy_pose(pose, m_pose, copy_constraint_channels_hack); + game_copy_pose(pose, m_pose); } else { if (*pose == m_pose) // no need to copy if the pointers are the same return; + extract_pose_from_pose(*pose, m_pose); } } @@ -165,21 +177,10 @@ void BL_ArmatureObject::GetMRDPose(bPose **pose) /* If the caller supplies a null pose, create a new one. */ /* Otherwise, copy the armature's pose channels into the caller-supplied pose */ - // is this needed anymore? - //if (!m_mrdPose){ - // copy_pose (&m_mrdPose, m_pose, 0); - //} - - if (!*pose) { - // must duplicate the constraints too otherwise we have corruption in free_pose_channels() - // because it will free the blender constraints. - // Ideally, blender should rememeber that the constraints were not copied so that - // free_pose_channels() would not free them. - copy_pose(pose, m_objArma->pose, 1); - } + if (!*pose) + game_copy_pose(pose, m_pose); else - extract_pose_from_pose(*pose, m_objArma->pose); - + extract_pose_from_pose(*pose, m_pose); } short BL_ArmatureObject::GetActivePriority() @@ -192,17 +193,17 @@ double BL_ArmatureObject::GetLastFrame() return m_lastframe; } -bool BL_ArmatureObject::GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix) const +bool BL_ArmatureObject::GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix) { - Object* par_arma = m_objArma; - where_is_pose(par_arma); - bPoseChannel *pchan= get_pose_channel(par_arma->pose, bone->name); + bPoseChannel *pchan; - if(pchan) { + ApplyPose(); + pchan = get_pose_channel(m_objArma->pose, bone->name); + if(pchan) matrix.setValue(&pchan->pose_mat[0][0]); - return true; - } - return false; + RestorePose(); + + return (pchan != NULL); } float BL_ArmatureObject::GetBoneLength(Bone* bone) const diff --git a/source/gameengine/Converter/BL_ArmatureObject.h b/source/gameengine/Converter/BL_ArmatureObject.h index 752bd5eb365..d68e37d9e37 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.h +++ b/source/gameengine/Converter/BL_ArmatureObject.h @@ -59,7 +59,10 @@ public: void GetMRDPose(struct bPose **pose); void GetPose(struct bPose **pose); void SetPose (struct bPose *pose); + void ApplyPose(); + void RestorePose(); + bool SetActiveAction(class BL_ActionActuator *act, short priority, double curtime); struct bArmature * GetArmature() { return m_armature; } @@ -69,7 +72,7 @@ public: /// Retrieve the pose matrix for the specified bone. /// Returns true on success. - bool GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix) const; + bool GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix); /// Returns the bone length. The end of the bone is in the local y direction. float GetBoneLength(Bone* bone) const; @@ -79,10 +82,13 @@ protected: Object *m_objArma; struct bArmature *m_armature; struct bPose *m_pose; - struct bPose *m_mrdPose; + struct bPose *m_armpose; + struct bPose *m_framePose; double m_lastframe; class BL_ActionActuator *m_activeAct; short m_activePriority; + + double m_lastapplyframe; }; #endif diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index a6337403cd1..97ed6f4002a 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -129,6 +129,7 @@ #include "DNA_sound_types.h" #include "DNA_key_types.h" #include "DNA_armature_types.h" +#include "DNA_object_force.h" #include "MEM_guardedalloc.h" #include "BKE_utildefines.h" @@ -308,7 +309,7 @@ static void GetRGB(short type, typedef struct MTF_localLayer { MTFace *face; - char *name; + const char *name; }MTF_localLayer; // ------------------------------------ @@ -377,6 +378,7 @@ BL_Material* ConvertMaterial( material->texname[i] = material->img[i]->id.name; material->flag[i] |= ( tface->transp &TF_ALPHA )?USEALPHA:0; material->flag[i] |= ( tface->transp &TF_ADD )?CALCALPHA:0; + material->flag[i] |= MIPMAP; if(material->img[i]->flag & IMA_REFLECT) material->mapping[i].mapping |= USEREFL; @@ -601,7 +603,6 @@ BL_Material* ConvertMaterial( (tface->mode & TF_INVISIBLE) )?POLY_VIS:0; - material->ras_mode |= ( (tface->mode & TF_DYNAMIC)!= 0 )?COLLIDER:0; material->transp = tface->transp; material->tile = tface->tile; material->mode = tface->mode; @@ -617,7 +618,7 @@ BL_Material* ConvertMaterial( } else { // nothing at all - material->ras_mode |= (COLLIDER|POLY_VIS| (validmat?0:USE_LIGHT)); + material->ras_mode |= (POLY_VIS| (validmat?0:USE_LIGHT)); material->mode = default_face_mode; material->transp = TF_SOLID; material->tile = 0; @@ -627,13 +628,19 @@ BL_Material* ConvertMaterial( if(validmat && (mat->mode & MA_ZTRA) && (material->transp == TF_SOLID)) material->transp = TF_ALPHA; - // always zsort alpha + add - if((material->transp == TF_ALPHA || material->transp == TF_ADD || texalpha) - && (material->transp != TF_CLIP)) { + // always zsort alpha + add + if((material->transp == TF_ALPHA || material->transp == TF_ADD || texalpha) && (material->transp != TF_CLIP)) { material->ras_mode |= ALPHA; material->ras_mode |= (material->mode & TF_ALPHASORT)? ZSORT: 0; } + // collider or not? + material->ras_mode |= (material->mode & TF_DYNAMIC)? COLLIDER: 0; + + // these flags are irrelevant at this point, remove so they + // don't hurt material bucketing + material->mode &= ~(TF_DYNAMIC|TF_ALPHASORT|TF_TEX); + // get uv sets if(validmat) { @@ -644,6 +651,7 @@ BL_Material* ConvertMaterial( for (int vind = 0; vind<material->num_enabled; vind++) { BL_Mapping &map = material->mapping[vind]; + if (map.uvCoName.IsEmpty()) isFirstSet = false; else @@ -673,7 +681,7 @@ BL_Material* ConvertMaterial( isFirstSet = false; uvName = layer.name; } - else + else if(strcmp(layer.name, uvName) != 0) { uv2[0] = uvSet[0]; uv2[1] = uvSet[1]; uv2[2] = uvSet[2]; uv2[3] = uvSet[3]; @@ -702,7 +710,6 @@ BL_Material* ConvertMaterial( material->SetConversionUV(uvName, uv); material->SetConversionUV2(uv2Name, uv2); - material->ras_mode |= (mface->v4==0)?TRIANGLE:0; if(validmat) material->matname =(mat->id.name); @@ -737,7 +744,8 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* } // Determine if we need to make a skinned mesh - if (mesh->dvert || mesh->key) { + if (mesh->dvert || mesh->key || ((blenderobj->gameflag & OB_SOFT_BODY) != 0)) + { meshobj = new BL_SkinMeshObject(mesh, lightlayer); skinMesh = true; } @@ -767,7 +775,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* } meshobj->SetName(mesh->id.name); - meshobj->m_xyz_index_to_vertex_index_mapping.resize(totvert); + meshobj->m_sharedvertex_map.resize(totvert); for (int f=0;f<totface;f++,mface++) { @@ -777,9 +785,9 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* MT_Point2 uv20(0.0,0.0),uv21(0.0,0.0),uv22(0.0,0.0),uv23(0.0,0.0); unsigned int rgb0,rgb1,rgb2,rgb3 = 0; - MT_Vector3 no0, no1, no2, no3; MT_Point3 pt0, pt1, pt2, pt3; - MT_Vector4 tan0, tan1, tan2, tan3; + MT_Vector3 no0(0,0,0), no1(0,0,0), no2(0,0,0), no3(0,0,0); + MT_Vector4 tan0(0,0,0,0), tan1(0,0,0,0), tan2(0,0,0,0), tan3(0,0,0,0); /* get coordinates, normals and tangents */ pt0 = MT_Point3(mvert[mface->v1].co); @@ -801,8 +809,6 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* NormalShortToFloat(n3, mvert[mface->v4].no); no3 = n3; } - else - no3 = MT_Vector3(0.0, 0.0, 0.0); } else { float fno[3]; @@ -830,7 +836,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* ma = give_current_material(blenderobj, mface->mat_nr+1); { - bool polyvisible = true; + bool visible = true; RAS_IPolyMaterial* polymat = NULL; BL_Material *bl_mat = NULL; @@ -845,7 +851,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* bl_mat->material_index = (int)mface->mat_nr; - polyvisible = ((bl_mat->ras_mode & POLY_VIS)!=0); + visible = ((bl_mat->ras_mode & POLY_VIS)!=0); collider = ((bl_mat->ras_mode & COLLIDER)!=0); /* vertex colors and uv's were stored in bl_mat temporarily */ @@ -862,7 +868,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* uv22 = uv[2]; uv23 = uv[3]; /* then the KX_BlenderMaterial */ - polymat = new KX_BlenderMaterial(scene, bl_mat, skinMesh, lightlayer, blenderobj ); + polymat = new KX_BlenderMaterial(scene, bl_mat, skinMesh, lightlayer); } else { /* do Texture Face materials */ @@ -886,7 +892,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* tile = tface->tile; mode = tface->mode; - polyvisible = !((mface->flag & ME_HIDE)||(tface->mode & TF_INVISIBLE)); + visible = !((mface->flag & ME_HIDE)||(tface->mode & TF_INVISIBLE)); uv0 = MT_Point2(tface->uv[0]); uv1 = MT_Point2(tface->uv[1]); @@ -940,15 +946,13 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* rgb3 = KX_rgbaint2uint_new(color); } - bool istriangle = (mface->v4==0); - // only zsort alpha + add bool alpha = (transp == TF_ALPHA || transp == TF_ADD); bool zsort = (mode & TF_ALPHASORT)? alpha: 0; polymat = new KX_PolygonMaterial(imastr, ma, tile, tilexrep, tileyrep, - mode, transp, alpha, zsort, lightlayer, istriangle, blenderobj, tface, (unsigned int*)mcol); + mode, transp, alpha, zsort, lightlayer, tface, (unsigned int*)mcol); if (ma) { polymat->m_specular = MT_Vector3(ma->specr, ma->specg, ma->specb)*ma->spec; @@ -961,6 +965,9 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* } } + /* mark face as flat, so vertices are split */ + bool flat = (mface->flag & ME_SMOOTH) == 0; + // see if a bucket was reused or a new one was created // this way only one KX_BlenderMaterial object has to exist per bucket bool bucketCreated; @@ -981,49 +988,19 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* polymat = bucket->GetPolyMaterial(); } - int nverts = mface->v4?4:3; - int vtxarray = meshobj->FindVertexArray(nverts,polymat); - RAS_Polygon* poly = new RAS_Polygon(bucket,polyvisible,nverts,vtxarray); - - bool flat; - - if (skinMesh) { - /* If the face is set to solid, all fnors are the same */ - if (mface->flag & ME_SMOOTH) - flat = false; - else - flat = true; - } - else - flat = false; - - poly->SetVertex(0,meshobj->FindOrAddVertex(vtxarray,pt0,uv0,uv20,tan0,rgb0,no0,flat,polymat,mface->v1)); - poly->SetVertex(1,meshobj->FindOrAddVertex(vtxarray,pt1,uv1,uv21,tan1,rgb1,no1,flat,polymat,mface->v2)); - poly->SetVertex(2,meshobj->FindOrAddVertex(vtxarray,pt2,uv2,uv22,tan2,rgb2,no2,flat,polymat,mface->v3)); - if (nverts==4) - poly->SetVertex(3,meshobj->FindOrAddVertex(vtxarray,pt3,uv3,uv23,tan3,rgb3,no3,flat,polymat,mface->v4)); + int nverts = (mface->v4)? 4: 3; + RAS_Polygon *poly = meshobj->AddPolygon(bucket, nverts); - meshobj->AddPolygon(poly); - if (poly->IsCollider()) - { - RAS_TriangleIndex idx; - idx.m_index[0] = mface->v1; - idx.m_index[1] = mface->v2; - idx.m_index[2] = mface->v3; - idx.m_collider = collider; - meshobj->m_triangle_indices.push_back(idx); - if (nverts==4) - { - idx.m_index[0] = mface->v1; - idx.m_index[1] = mface->v3; - idx.m_index[2] = mface->v4; - idx.m_collider = collider; - meshobj->m_triangle_indices.push_back(idx); - } - } - -// poly->SetVisibleWireframeEdges(mface->edcode); + poly->SetVisible(visible); poly->SetCollider(collider); + //poly->SetEdgeCode(mface->edcode); + + meshobj->AddVertex(poly,0,pt0,uv0,uv20,tan0,rgb0,no0,flat,mface->v1); + meshobj->AddVertex(poly,1,pt1,uv1,uv21,tan1,rgb1,no1,flat,mface->v2); + meshobj->AddVertex(poly,2,pt2,uv2,uv22,tan2,rgb2,no2,flat,mface->v3); + + if (nverts==4) + meshobj->AddVertex(poly,3,pt3,uv3,uv23,tan3,rgb3,no3,flat,mface->v4); } if (tface) @@ -1039,13 +1016,12 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* layer.face++; } } - meshobj->m_xyz_index_to_vertex_index_mapping.clear(); - meshobj->UpdateMaterialList(); + meshobj->m_sharedvertex_map.clear(); // pre calculate texture generation - for(RAS_MaterialBucket::Set::iterator mit = meshobj->GetFirstMaterial(); + for(list<RAS_MeshMaterial>::iterator mit = meshobj->GetFirstMaterial(); mit != meshobj->GetLastMaterial(); ++ mit) { - (*mit)->GetPolyMaterial()->OnConstruction(); + mit->m_bucket->GetPolyMaterial()->OnConstruction(); } if (layers) @@ -1305,6 +1281,10 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, //int userigidbody = SYS_GetCommandLineInt(syshandle,"norigidbody",0); //bool bRigidBody = (userigidbody == 0); + // object has physics representation? + if (!(blenderobject->gameflag & OB_COLLISION)) + return; + // get Root Parent of blenderobject struct Object* parent= blenderobject->parent; while(parent && parent->parent) { @@ -1336,19 +1316,97 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, objprop.m_isCompoundChild = isCompoundChild; objprop.m_hasCompoundChildren = (blenderobject->gameflag & OB_CHILD) != 0; - - if ((objprop.m_isactor = (blenderobject->gameflag & OB_ACTOR)!=0)) + objprop.m_margin = blenderobject->margin; + // ACTOR is now a separate feature + objprop.m_isactor = (blenderobject->gameflag & OB_ACTOR)!=0; + objprop.m_dyna = (blenderobject->gameflag & OB_DYNAMIC) != 0; + objprop.m_softbody = (blenderobject->gameflag & OB_SOFT_BODY) != 0; + objprop.m_angular_rigidbody = (blenderobject->gameflag & OB_RIGID_BODY) != 0; + + if (objprop.m_softbody) { - objprop.m_dyna = (blenderobject->gameflag & OB_DYNAMIC) != 0; - objprop.m_angular_rigidbody = (blenderobject->gameflag & OB_RIGID_BODY) != 0; - objprop.m_ghost = (blenderobject->gameflag & OB_GHOST) != 0; - objprop.m_disableSleeping = (blenderobject->gameflag & OB_COLLISION_RESPONSE) != 0;//abuse the OB_COLLISION_RESPONSE flag - } else { - objprop.m_dyna = false; - objprop.m_angular_rigidbody = false; - objprop.m_ghost = false; - objprop.m_disableSleeping = false; + ///for game soft bodies + if (blenderobject->bsoft) + { + objprop.m_gamesoftFlag = blenderobject->bsoft->flag; + /////////////////// + objprop.m_soft_linStiff = blenderobject->bsoft->linStiff; + objprop.m_soft_angStiff = blenderobject->bsoft->angStiff; /* angular stiffness 0..1 */ + objprop.m_soft_volume= blenderobject->bsoft->volume; /* volume preservation 0..1 */ + + objprop.m_soft_viterations= blenderobject->bsoft->viterations; /* Velocities solver iterations */ + objprop.m_soft_piterations= blenderobject->bsoft->piterations; /* Positions solver iterations */ + objprop.m_soft_diterations= blenderobject->bsoft->diterations; /* Drift solver iterations */ + objprop.m_soft_citerations= blenderobject->bsoft->citerations; /* Cluster solver iterations */ + + objprop.m_soft_kSRHR_CL= blenderobject->bsoft->kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */ + objprop.m_soft_kSKHR_CL= blenderobject->bsoft->kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */ + objprop.m_soft_kSSHR_CL= blenderobject->bsoft->kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */ + objprop.m_soft_kSR_SPLT_CL= blenderobject->bsoft->kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + + objprop.m_soft_kSK_SPLT_CL= blenderobject->bsoft->kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + objprop.m_soft_kSS_SPLT_CL= blenderobject->bsoft->kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + objprop.m_soft_kVCF= blenderobject->bsoft->kVCF; /* Velocities correction factor (Baumgarte) */ + objprop.m_soft_kDP= blenderobject->bsoft->kDP; /* Damping coefficient [0,1] */ + + objprop.m_soft_kDG= blenderobject->bsoft->kDG; /* Drag coefficient [0,+inf] */ + objprop.m_soft_kLF= blenderobject->bsoft->kLF; /* Lift coefficient [0,+inf] */ + objprop.m_soft_kPR= blenderobject->bsoft->kPR; /* Pressure coefficient [-inf,+inf] */ + objprop.m_soft_kVC= blenderobject->bsoft->kVC; /* Volume conversation coefficient [0,+inf] */ + + objprop.m_soft_kDF= blenderobject->bsoft->kDF; /* Dynamic friction coefficient [0,1] */ + objprop.m_soft_kMT= blenderobject->bsoft->kMT; /* Pose matching coefficient [0,1] */ + objprop.m_soft_kCHR= blenderobject->bsoft->kCHR; /* Rigid contacts hardness [0,1] */ + objprop.m_soft_kKHR= blenderobject->bsoft->kKHR; /* Kinetic contacts hardness [0,1] */ + + objprop.m_soft_kSHR= blenderobject->bsoft->kSHR; /* Soft contacts hardness [0,1] */ + objprop.m_soft_kAHR= blenderobject->bsoft->kAHR; /* Anchors hardness [0,1] */ + objprop.m_soft_collisionflags= blenderobject->bsoft->collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */ + objprop.m_soft_numclusteriterations= blenderobject->bsoft->numclusteriterations; /* number of iterations to refine collision clusters*/ + + } else + { + objprop.m_gamesoftFlag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT; + + objprop.m_soft_linStiff = 0.5;; + objprop.m_soft_angStiff = 1.f; /* angular stiffness 0..1 */ + objprop.m_soft_volume= 1.f; /* volume preservation 0..1 */ + + + objprop.m_soft_viterations= 0; + objprop.m_soft_piterations= 1; + objprop.m_soft_diterations= 0; + objprop.m_soft_citerations= 4; + + objprop.m_soft_kSRHR_CL= 0.1f; + objprop.m_soft_kSKHR_CL= 1.f; + objprop.m_soft_kSSHR_CL= 0.5; + objprop.m_soft_kSR_SPLT_CL= 0.5f; + + objprop.m_soft_kSK_SPLT_CL= 0.5f; + objprop.m_soft_kSS_SPLT_CL= 0.5f; + objprop.m_soft_kVCF= 1; + objprop.m_soft_kDP= 0; + + objprop.m_soft_kDG= 0; + objprop.m_soft_kLF= 0; + objprop.m_soft_kPR= 0; + objprop.m_soft_kVC= 0; + + objprop.m_soft_kDF= 0.2f; + objprop.m_soft_kMT= 0.05f; + objprop.m_soft_kCHR= 1.0f; + objprop.m_soft_kKHR= 0.1f; + + objprop.m_soft_kSHR= 1.f; + objprop.m_soft_kAHR= 0.7f; + objprop.m_soft_collisionflags= OB_BSB_COL_SDF_RS + OB_BSB_COL_VF_SS; + objprop.m_soft_numclusteriterations= 16; + } } + + objprop.m_ghost = (blenderobject->gameflag & OB_GHOST) != 0; + objprop.m_disableSleeping = (blenderobject->gameflag & OB_COLLISION_RESPONSE) != 0;//abuse the OB_COLLISION_RESPONSE flag //mmm, for now, taks this for the size of the dynamicobject // Blender uses inertia for radius of dynamic object objprop.m_radius = blenderobject->inertia; @@ -1356,6 +1414,12 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, objprop.m_dynamic_parent=NULL; objprop.m_isdeformable = ((blenderobject->gameflag2 & 2)) != 0; objprop.m_boundclass = objprop.m_dyna?KX_BOUNDSPHERE:KX_BOUNDMESH; + + if ((blenderobject->gameflag & OB_SOFT_BODY) && !(blenderobject->gameflag & OB_BOUNDS)) + { + objprop.m_boundclass = KX_BOUNDMESH; + } + KX_BoxBounds bb; my_get_local_bounds(blenderobject,objprop.m_boundobject.box.m_center,bb.m_extends); if (blenderobject->gameflag & OB_BOUNDS) @@ -1490,14 +1554,9 @@ static KX_LightObject *gamelight_from_blamp(Object *ob, Lamp *la, unsigned int l lightobj.m_type = RAS_LightObject::LIGHT_NORMAL; } -#ifdef BLENDER_GLSL - if(converter->GetGLSLMaterials()) - GPU_lamp_from_blender(ob, la); - - gamelight = new KX_LightObject(kxscene, KX_Scene::m_callbacks, rendertools, lightobj, ob->gpulamp); -#else - gamelight = new KX_LightObject(kxscene, KX_Scene::m_callbacks, rendertools, lightobj, NULL); -#endif + gamelight = new KX_LightObject(kxscene, KX_Scene::m_callbacks, rendertools, + lightobj, converter->GetGLSLMaterials()); + BL_ConvertLampIpos(la, gamelight, converter); return gamelight; @@ -1534,7 +1593,7 @@ static KX_GameObject *gameobject_from_blenderobject( gamelight->AddRef(); kxscene->GetLightList()->Add(gamelight); - + break; } @@ -1586,20 +1645,20 @@ static KX_GameObject *gameobject_from_blenderobject( // not that we can have shape keys without dvert! BL_ShapeDeformer *dcont = new BL_ShapeDeformer((BL_DeformableGameObject*)gameobj, ob, (BL_SkinMeshObject*)meshobj); - ((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont; + ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont); if (bHasArmature) dcont->LoadShapeDrivers(ob->parent); } else if (bHasArmature) { BL_SkinDeformer *dcont = new BL_SkinDeformer((BL_DeformableGameObject*)gameobj, ob, (BL_SkinMeshObject*)meshobj); - ((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont; + ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont); } else if (bHasDvert) { // this case correspond to a mesh that can potentially deform but not with the // object to which it is attached for the moment. A skin mesh was created in // BL_ConvertMesh() so must create a deformer too! BL_MeshDeformer *dcont = new BL_MeshDeformer((BL_DeformableGameObject*)gameobj, ob, (BL_SkinMeshObject*)meshobj); - ((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont; + ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont); } MT_Point3 min = MT_Point3(center) - MT_Vector3(extents); @@ -1634,6 +1693,8 @@ static KX_GameObject *gameobject_from_blenderobject( gameobj->SetPhysicsEnvironment(kxscene->GetPhysicsEnvironment()); gameobj->SetLayer(ob->lay); gameobj->SetBlenderObject(ob); + /* set the visibility state based on the objects render option in the outliner */ + if(ob->restrictflag & OB_RESTRICT_RENDER) gameobj->SetVisible(0, 0); } return gameobj; } @@ -1643,20 +1704,6 @@ struct parentChildLink { SG_Node* m_gamechildnode; }; - /** - * Find the specified scene by name, or the first - * scene if nothing matches (shouldn't happen). - */ -static struct Scene *GetSceneForName(struct Main *maggie, const STR_String& scenename) { - Scene *sce; - - for (sce= (Scene*) maggie->scene.first; sce; sce= (Scene*) sce->id.next) - if (scenename == (sce->id.name+2)) - return sce; - - return (Scene*) maggie->scene.first; -} - #include "DNA_constraint_types.h" #include "BIF_editconstraint.h" @@ -1755,7 +1802,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, ) { - Scene *blenderscene = GetSceneForName(maggie, scenename); + Scene *blenderscene = converter->GetBlenderSceneForName(scenename); // for SETLOOPER Scene *sce; Base *base; @@ -1946,10 +1993,22 @@ void BL_ConvertBlenderObjects(struct Main* maggie, //parentinversenode->SetLocalOrientation(parinvtrans.getBasis()); // Extract the rotation and the scaling from the basis - MT_Matrix3x3 inverseOrientation(parinvtrans.getRotation()); - parentinversenode->SetLocalOrientation(inverseOrientation); - MT_Matrix3x3 scale(inverseOrientation.transposed()*parinvtrans.getBasis()); - parentinversenode->SetLocalScale(MT_Vector3(scale[0][0], scale[1][1], scale[2][2])); + MT_Matrix3x3 ori(parinvtrans.getBasis()); + MT_Vector3 x(ori.getColumn(0)); + MT_Vector3 y(ori.getColumn(1)); + MT_Vector3 z(ori.getColumn(2)); + MT_Vector3 scale(x.length(), y.length(), z.length()); + if (!MT_fuzzyZero(scale[0])) + x /= scale[0]; + if (!MT_fuzzyZero(scale[1])) + y /= scale[1]; + if (!MT_fuzzyZero(scale[2])) + z /= scale[2]; + ori.setColumn(0, x); + ori.setColumn(1, y); + ori.setColumn(2, z); + parentinversenode->SetLocalOrientation(ori); + parentinversenode->SetLocalScale(scale); parentinversenode->AddChild(gameobj->GetSGNode()); } @@ -1978,7 +2037,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, //tf.Add(gameobj->GetSGNode()); gameobj->NodeUpdateGS(0,true); - gameobj->Bucketize(); + gameobj->AddMeshUser(); } else @@ -2129,7 +2188,24 @@ void BL_ConvertBlenderObjects(struct Main* maggie, float* fl = (float*) blenderobject->parentinv; MT_Transform parinvtrans(fl); parentinversenode->SetLocalPosition(parinvtrans.getOrigin()); - parentinversenode->SetLocalOrientation(parinvtrans.getBasis()); + + // Extract the rotation and the scaling from the basis + MT_Matrix3x3 ori(parinvtrans.getBasis()); + MT_Vector3 x(ori.getColumn(0)); + MT_Vector3 y(ori.getColumn(1)); + MT_Vector3 z(ori.getColumn(2)); + MT_Vector3 scale(x.length(), y.length(), z.length()); + if (!MT_fuzzyZero(scale[0])) + x /= scale[0]; + if (!MT_fuzzyZero(scale[1])) + y /= scale[1]; + if (!MT_fuzzyZero(scale[2])) + z /= scale[2]; + ori.setColumn(0, x); + ori.setColumn(1, y); + ori.setColumn(2, z); + parentinversenode->SetLocalOrientation(ori); + parentinversenode->SetLocalScale(scale); parentinversenode->AddChild(gameobj->GetSGNode()); } @@ -2158,8 +2234,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, //tf.Add(gameobj->GetSGNode()); gameobj->NodeUpdateGS(0,true); - gameobj->Bucketize(); - + gameobj->AddMeshUser(); } else { @@ -2201,16 +2276,16 @@ void BL_ConvertBlenderObjects(struct Main* maggie, for(oit=allblobj.begin(); oit!=allblobj.end(); oit++) { Object* blenderobj = *oit; - if (blenderobj->type==OB_MESH){ + if (blenderobj->type==OB_MESH) { Mesh *me = (Mesh*)blenderobj->data; if (me->dvert){ - KX_GameObject *obj = converter->FindGameObject(blenderobj); + BL_DeformableGameObject *obj = (BL_DeformableGameObject*)converter->FindGameObject(blenderobj); if (obj && blenderobj->parent && blenderobj->parent->type==OB_ARMATURE && blenderobj->partype==PARSKEL){ KX_GameObject *par = converter->FindGameObject(blenderobj->parent); - if (par) - ((BL_SkinDeformer*)(((BL_DeformableGameObject*)obj)->m_pDeformer))->SetArmature((BL_ArmatureObject*) par); + if (par && obj->GetDeformer()) + ((BL_SkinDeformer*)obj->GetDeformer())->SetArmature((BL_ArmatureObject*) par); } } } @@ -2224,6 +2299,41 @@ void BL_ConvertBlenderObjects(struct Main* maggie, { struct Object* blenderchild = pcit->m_blenderchild; + struct Object* blenderparent = blenderchild->parent; + KX_GameObject* parentobj = converter->FindGameObject(blenderparent); + KX_GameObject* childobj = converter->FindGameObject(blenderchild); + + assert(childobj); + + if (!parentobj || objectlist->SearchValue(childobj) != objectlist->SearchValue(parentobj)) + { + // special case: the parent and child object are not in the same layer. + // This weird situation is used in Apricot for test purposes. + // Resolve it by not converting the child + childobj->GetSGNode()->DisconnectFromParent(); + delete pcit->m_gamechildnode; + // Now destroy the child object but also all its descendent that may already be linked + // Remove the child reference in the local list! + // Note: there may be descendents already if the children of the child were processed + // by this loop before the child. In that case, we must remove the children also + CListValue* childrenlist = (CListValue*)childobj->PyGetChildrenRecursive(childobj); + childrenlist->Add(childobj->AddRef()); + for ( i=0;i<childrenlist->GetCount();i++) + { + KX_GameObject* obj = static_cast<KX_GameObject*>(childrenlist->GetValue(i)); + if (templist->RemoveValue(obj)) + obj->Release(); + if (sumolist->RemoveValue(obj)) + obj->Release(); + if (logicbrick_conversionlist->RemoveValue(obj)) + obj->Release(); + } + childrenlist->Release(); + // now destroy recursively + kxscene->RemoveObject(childobj); + continue; + } + switch (blenderchild->partype) { case PARVERT1: @@ -2244,8 +2354,11 @@ void BL_ConvertBlenderObjects(struct Main* maggie, { // parent this to a bone Bone *parent_bone = get_named_bone(get_armature(blenderchild->parent), blenderchild->parsubstr); - KX_BoneParentRelation *bone_parent_relation = KX_BoneParentRelation::New(parent_bone); - pcit->m_gamechildnode->SetParentRelation(bone_parent_relation); + + if(parent_bone) { + KX_BoneParentRelation *bone_parent_relation = KX_BoneParentRelation::New(parent_bone); + pcit->m_gamechildnode->SetParentRelation(bone_parent_relation); + } break; } @@ -2260,12 +2373,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, break; } - struct Object* blenderparent = blenderchild->parent; - KX_GameObject* parentobj = converter->FindGameObject(blenderparent); - if (parentobj) - { - parentobj-> GetSGNode()->AddChild(pcit->m_gamechildnode); - } + parentobj-> GetSGNode()->AddChild(pcit->m_gamechildnode); } vec_parent_child.clear(); @@ -2450,7 +2558,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, struct Object* blenderobj = converter->FindBlenderObject(gameobj); int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; - BL_ConvertSensors(blenderobj,gameobj,logicmgr,kxscene,keydev,executePriority,layerMask,isInActiveLayer,canvas,converter); + BL_ConvertSensors(blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,keydev,executePriority,layerMask,isInActiveLayer,canvas,converter); // set the init state to all objects gameobj->SetInitState((blenderobj->init_state)?blenderobj->init_state:blenderobj->state); } @@ -2482,5 +2590,10 @@ void BL_ConvertBlenderObjects(struct Main* maggie, kxscene->DupliGroupRecurse(gameobj, 0); } } + + KX_Camera *activecam = kxscene->GetActiveCamera(); + MT_Scalar distance = (activecam)? activecam->GetCameraFar() - activecam->GetCameraNear(): 100.0f; + RAS_BucketManager *bucketmanager = kxscene->GetBucketManager(); + bucketmanager->OptimizeBuckets(distance); } diff --git a/source/gameengine/Converter/BL_DeformableGameObject.cpp b/source/gameengine/Converter/BL_DeformableGameObject.cpp index d23274324ee..e2610d2b405 100644 --- a/source/gameengine/Converter/BL_DeformableGameObject.cpp +++ b/source/gameengine/Converter/BL_DeformableGameObject.cpp @@ -41,12 +41,14 @@ BL_DeformableGameObject::~BL_DeformableGameObject() delete m_pDeformer; // __NLA : Temporary until we decide where to put this } -void BL_DeformableGameObject::ProcessReplica(KX_GameObject* replica) +void BL_DeformableGameObject::ProcessReplica(KX_GameObject* replica) { + BL_MeshDeformer *deformer; KX_GameObject::ProcessReplica(replica); - if (m_pDeformer){ - ((BL_DeformableGameObject*)replica)->m_pDeformer = m_pDeformer->GetReplica(); + if (m_pDeformer) { + deformer = (BL_MeshDeformer*)m_pDeformer->GetReplica(replica); + ((BL_DeformableGameObject*)replica)->m_pDeformer = deformer; } } diff --git a/source/gameengine/Converter/BL_DeformableGameObject.h b/source/gameengine/Converter/BL_DeformableGameObject.h index 315ad18c42c..126a1fcb1e7 100644 --- a/source/gameengine/Converter/BL_DeformableGameObject.h +++ b/source/gameengine/Converter/BL_DeformableGameObject.h @@ -83,9 +83,21 @@ public: return (m_pDeformer) ? ((BL_MeshDeformer*)m_pDeformer)->GetMesh()->key : NULL; } + virtual void SetDeformer(class RAS_Deformer* deformer) + { + m_pDeformer = deformer; + } + virtual class RAS_Deformer* GetDeformer() + { + return m_pDeformer; + } + public: - RAS_Deformer *m_pDeformer; + protected: + + RAS_Deformer *m_pDeformer; + class BL_ShapeActionActuator *m_activeAct; double m_lastframe; Object* m_blendobj; diff --git a/source/gameengine/Converter/BL_MeshDeformer.cpp b/source/gameengine/Converter/BL_MeshDeformer.cpp index 39d66a90e92..fa3b8185fe2 100644 --- a/source/gameengine/Converter/BL_MeshDeformer.cpp +++ b/source/gameengine/Converter/BL_MeshDeformer.cpp @@ -50,26 +50,26 @@ bool BL_MeshDeformer::Apply(RAS_IPolyMaterial*) { - size_t i, j; + size_t i; float *co; // only apply once per frame if the mesh is actually modified if(m_pMeshObject->MeshModified() && m_lastDeformUpdate != m_gameobj->GetLastFrame()) { // For each material - for(RAS_MaterialBucket::Set::iterator mit = m_pMeshObject->GetFirstMaterial(); + for(list<RAS_MeshMaterial>::iterator mit= m_pMeshObject->GetFirstMaterial(); mit != m_pMeshObject->GetLastMaterial(); ++ mit) { - RAS_IPolyMaterial *mat = (*mit)->GetPolyMaterial(); + if(!mit->m_slots[(void*)m_gameobj]) + continue; - vecVertexArray& vertexarrays = m_pMeshObject->GetVertexCache(mat); - - // For each array - for (i=0; i<vertexarrays.size(); i++){ - KX_VertexArray& vertexarray = (*vertexarrays[i]); + RAS_MeshSlot *slot = *mit->m_slots[(void*)m_gameobj]; + RAS_MeshSlot::iterator it; + // for each array + for(slot->begin(it); !slot->end(it); slot->next(it)) { // For each vertex - for (j=0; j<vertexarray.size(); j++){ - RAS_TexVert& v = vertexarray[j]; + for(i=it.startvertex; i<it.endvertex; i++) { + RAS_TexVert& v = it.vertex[i]; co = m_bmesh->mvert[v.getOrigIndex()].co; v.SetXYZ(MT_Point3(co)); } @@ -90,7 +90,17 @@ BL_MeshDeformer::~BL_MeshDeformer() delete [] m_transverts; if (m_transnors) delete [] m_transnors; -}; +} + +void BL_MeshDeformer::Relink(GEN_Map<class GEN_HashedPtr, void*>*map) +{ + void **h_obj = (*map)[m_gameobj]; + + if (h_obj) + m_gameobj = (BL_DeformableGameObject*)(*h_obj); + else + m_gameobj = NULL; +} /** * @warning This function is expensive! @@ -101,41 +111,41 @@ void BL_MeshDeformer::RecalcNormals() * gives area-weight normals which often look better anyway, and use * GL_NORMALIZE so we don't have to do per vertex normalization either * since the GPU can do it faster */ - size_t i, j; + list<RAS_MeshMaterial>::iterator mit; + RAS_MeshSlot::iterator it; + size_t i; /* set vertex normals to zero */ memset(m_transnors, 0, sizeof(float)*3*m_bmesh->totvert); /* add face normals to vertices. */ - for(RAS_MaterialBucket::Set::iterator mit = m_pMeshObject->GetFirstMaterial(); + for(mit = m_pMeshObject->GetFirstMaterial(); mit != m_pMeshObject->GetLastMaterial(); ++ mit) { - RAS_IPolyMaterial *mat = (*mit)->GetPolyMaterial(); + if(!mit->m_slots[(void*)m_gameobj]) + continue; - const vecIndexArrays& indexarrays = m_pMeshObject->GetIndexCache(mat); - vecVertexArray& vertexarrays = m_pMeshObject->GetVertexCache(mat); + RAS_MeshSlot *slot = *mit->m_slots[(void*)m_gameobj]; - for (i=0; i<indexarrays.size(); i++) { - KX_VertexArray& vertexarray = (*vertexarrays[i]); - const KX_IndexArray& indexarray = (*indexarrays[i]); - int nvert = mat->UsesTriangles()? 3: 4; + for(slot->begin(it); !slot->end(it); slot->next(it)) { + int nvert = (int)it.array->m_type; - for(j=0; j<indexarray.size(); j+=nvert) { - RAS_TexVert& v1 = vertexarray[indexarray[j]]; - RAS_TexVert& v2 = vertexarray[indexarray[j+1]]; - RAS_TexVert& v3 = vertexarray[indexarray[j+2]]; + for(i=0; i<it.totindex; i+=nvert) { + RAS_TexVert& v1 = it.vertex[it.index[i]]; + RAS_TexVert& v2 = it.vertex[it.index[i+1]]; + RAS_TexVert& v3 = it.vertex[it.index[i+2]]; RAS_TexVert *v4 = NULL; - const float *co1 = v1.getLocalXYZ(); - const float *co2 = v2.getLocalXYZ(); - const float *co3 = v3.getLocalXYZ(); + const float *co1 = v1.getXYZ(); + const float *co2 = v2.getXYZ(); + const float *co3 = v3.getXYZ(); const float *co4 = NULL; /* compute face normal */ float fnor[3], n1[3], n2[3]; if(nvert == 4) { - v4 = &vertexarray[indexarray[j+3]]; - co4 = v4->getLocalXYZ(); + v4 = &it.vertex[it.index[i+3]]; + co4 = v4->getXYZ(); n1[0]= co1[0]-co3[0]; n1[1]= co1[1]-co3[1]; @@ -174,7 +184,7 @@ void BL_MeshDeformer::RecalcNormals() } /* in case of flat - just assign, the vertices are split */ - if(v1.getFlag() & TV_CALCFACENORMAL) { + if(v1.getFlag() & RAS_TexVert::FLAT) { v1.SetNormal(fnor); v2.SetNormal(fnor); v3.SetNormal(fnor); @@ -186,19 +196,18 @@ void BL_MeshDeformer::RecalcNormals() } /* assign smooth vertex normals */ - for(RAS_MaterialBucket::Set::iterator mit = m_pMeshObject->GetFirstMaterial(); + for(mit = m_pMeshObject->GetFirstMaterial(); mit != m_pMeshObject->GetLastMaterial(); ++ mit) { - RAS_IPolyMaterial *mat = (*mit)->GetPolyMaterial(); + if(!mit->m_slots[(void*)m_gameobj]) + continue; - vecVertexArray& vertexarrays = m_pMeshObject->GetVertexCache(mat); + RAS_MeshSlot *slot = *mit->m_slots[(void*)m_gameobj]; - for (i=0; i<vertexarrays.size(); i++) { - KX_VertexArray& vertexarray = (*vertexarrays[i]); - - for(j=0; j<vertexarray.size(); j++) { - RAS_TexVert& v = vertexarray[j]; + for(slot->begin(it); !slot->end(it); slot->next(it)) { + for(i=it.startvertex; i<it.endvertex; i++) { + RAS_TexVert& v = it.vertex[i]; - if(!(v.getFlag() & TV_CALCFACENORMAL)) + if(!(v.getFlag() & RAS_TexVert::FLAT)) v.SetNormal(m_transnors[v.getOrigIndex()]); //.safe_normalized() } } @@ -219,4 +228,4 @@ void BL_MeshDeformer::VerifyStorage() m_tvtot = m_bmesh->totvert; } } - + diff --git a/source/gameengine/Converter/BL_MeshDeformer.h b/source/gameengine/Converter/BL_MeshDeformer.h index e9f7f0b192f..8de59c1cdf3 100644 --- a/source/gameengine/Converter/BL_MeshDeformer.h +++ b/source/gameengine/Converter/BL_MeshDeformer.h @@ -47,7 +47,7 @@ class BL_MeshDeformer : public RAS_Deformer public: void VerifyStorage(); void RecalcNormals(); - virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map){}; + virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map); BL_MeshDeformer(BL_DeformableGameObject *gameobj, struct Object* obj, class BL_SkinMeshObject *meshobj ): @@ -64,9 +64,10 @@ public: virtual void SetSimulatedTime(double time){}; virtual bool Apply(class RAS_IPolyMaterial *mat); virtual bool Update(void){ return false; }; - virtual RAS_Deformer* GetReplica(){return NULL;}; + virtual RAS_Deformer* GetReplica(class KX_GameObject* replica){return NULL;}; struct Mesh* GetMesh() { return m_bmesh; }; // virtual void InitDeform(double time){}; + protected: class BL_SkinMeshObject* m_pMeshObject; struct Mesh* m_bmesh; diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.cpp b/source/gameengine/Converter/BL_ShapeActionActuator.cpp index 0f976bfb842..cbaa8668b26 100644 --- a/source/gameengine/Converter/BL_ShapeActionActuator.cpp +++ b/source/gameengine/Converter/BL_ShapeActionActuator.cpp @@ -1,3 +1,4 @@ +<<<<<<< .working /** * $Id:BL_ShapeActionActuator.cpp 15330 2008-06-23 16:37:51Z theeth $ * @@ -91,6 +92,102 @@ bool BL_ShapeActionActuator::ClampLocalTime() { m_localtime = m_endframe; return true; +======= +/** +* $Id$ +* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** +*/ + +#if defined (__sgi) +#include <math.h> +#else +#include <cmath> +#endif + +#include "SCA_LogicManager.h" +#include "BL_ShapeActionActuator.h" +#include "BL_ActionActuator.h" +#include "BL_ShapeDeformer.h" +#include "KX_GameObject.h" +#include "STR_HashedString.h" +#include "DNA_action_types.h" +#include "DNA_nla_types.h" +#include "DNA_actuator_types.h" +#include "BKE_action.h" +#include "DNA_armature_types.h" +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "MT_Matrix4x4.h" +#include "BKE_utildefines.h" +#include "FloatValue.h" +#include "PyObjectPlus.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +BL_ShapeActionActuator::~BL_ShapeActionActuator() +{ +} + +void BL_ShapeActionActuator::ProcessReplica() +{ + m_localtime=m_startframe; + m_lastUpdate=-1; +} + +void BL_ShapeActionActuator::SetBlendTime (float newtime) +{ + m_blendframe = newtime; +} + +CValue* BL_ShapeActionActuator::GetReplica() +{ + BL_ShapeActionActuator* replica = new BL_ShapeActionActuator(*this);//m_float,GetName()); + replica->ProcessReplica(); + + // this will copy properties and so on... + CValue::AddDataToReplica(replica); + return replica; +} + +bool BL_ShapeActionActuator::ClampLocalTime() +{ + if (m_startframe < m_endframe) { + if (m_localtime < m_startframe) + { + m_localtime = m_startframe; + return true; + } + else if (m_localtime > m_endframe) + { + m_localtime = m_endframe; + return true; } } else { if (m_localtime > m_startframe) @@ -134,7 +231,6 @@ void BL_ShapeActionActuator::BlendShape(Key* key, float srcweight) { vector<float>::const_iterator it; float dstweight; - int i; KeyBlock *kb; dstweight = 1.0F - srcweight; @@ -155,6 +251,8 @@ bool BL_ShapeActionActuator::Update(double curtime, bool frame) bool apply=true; int priority; float newweight; + + curtime -= KX_KetsjiEngine::GetSuspendedDelta(); // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! @@ -340,6 +438,19 @@ bool BL_ShapeActionActuator::Update(double curtime, bool frame) break; } + /* Set the property if its defined */ + if (m_framepropname[0] != '\0') { + CValue* propowner = GetParent(); + CValue* oldprop = propowner->GetProperty(m_framepropname); + CValue* newval = new CFloatValue(m_localtime); + if (oldprop) { + oldprop->SetValue(newval); + } else { + propowner->SetProperty(m_framepropname, newval); +>>>>>>> .merge-right.r16886 + } + newval->Release(); + } if (bNegativeEvent) m_blendframe=0.0f; @@ -433,24 +544,26 @@ PyParentObject BL_ShapeActionActuator::Parents[] = { }; PyMethodDef BL_ShapeActionActuator::Methods[] = { - {"setAction", (PyCFunction) BL_ShapeActionActuator::sPySetAction, METH_VARARGS, SetAction_doc}, - {"setStart", (PyCFunction) BL_ShapeActionActuator::sPySetStart, METH_VARARGS, SetStart_doc}, - {"setEnd", (PyCFunction) BL_ShapeActionActuator::sPySetEnd, METH_VARARGS, SetEnd_doc}, - {"setBlendin", (PyCFunction) BL_ShapeActionActuator::sPySetBlendin, METH_VARARGS, SetBlendin_doc}, - {"setPriority", (PyCFunction) BL_ShapeActionActuator::sPySetPriority, METH_VARARGS, SetPriority_doc}, - {"setFrame", (PyCFunction) BL_ShapeActionActuator::sPySetFrame, METH_VARARGS, SetFrame_doc}, - {"setProperty", (PyCFunction) BL_ShapeActionActuator::sPySetProperty, METH_VARARGS, SetProperty_doc}, - {"setBlendtime", (PyCFunction) BL_ShapeActionActuator::sPySetBlendtime, METH_VARARGS, SetBlendtime_doc}, - - {"getAction", (PyCFunction) BL_ShapeActionActuator::sPyGetAction, METH_NOARGS, GetAction_doc}, - {"getStart", (PyCFunction) BL_ShapeActionActuator::sPyGetStart, METH_NOARGS, GetStart_doc}, - {"getEnd", (PyCFunction) BL_ShapeActionActuator::sPyGetEnd, METH_NOARGS, GetEnd_doc}, - {"getBlendin", (PyCFunction) BL_ShapeActionActuator::sPyGetBlendin, METH_NOARGS, GetBlendin_doc}, - {"getPriority", (PyCFunction) BL_ShapeActionActuator::sPyGetPriority, METH_NOARGS, GetPriority_doc}, - {"getFrame", (PyCFunction) BL_ShapeActionActuator::sPyGetFrame, METH_NOARGS, GetFrame_doc}, - {"getProperty", (PyCFunction) BL_ShapeActionActuator::sPyGetProperty, METH_NOARGS, GetProperty_doc}, - {"getType", (PyCFunction) BL_ShapeActionActuator::sPyGetType, METH_NOARGS, GetType_doc}, - {"setType", (PyCFunction) BL_ShapeActionActuator::sPySetType, METH_NOARGS, SetType_doc}, + {"setAction", (PyCFunction) BL_ShapeActionActuator::sPySetAction, METH_VARARGS, (PY_METHODCHAR)SetAction_doc}, + {"setStart", (PyCFunction) BL_ShapeActionActuator::sPySetStart, METH_VARARGS, (PY_METHODCHAR)SetStart_doc}, + {"setEnd", (PyCFunction) BL_ShapeActionActuator::sPySetEnd, METH_VARARGS, (PY_METHODCHAR)SetEnd_doc}, + {"setBlendin", (PyCFunction) BL_ShapeActionActuator::sPySetBlendin, METH_VARARGS, (PY_METHODCHAR)SetBlendin_doc}, + {"setPriority", (PyCFunction) BL_ShapeActionActuator::sPySetPriority, METH_VARARGS, (PY_METHODCHAR)SetPriority_doc}, + {"setFrame", (PyCFunction) BL_ShapeActionActuator::sPySetFrame, METH_VARARGS, (PY_METHODCHAR)SetFrame_doc}, + {"setProperty", (PyCFunction) BL_ShapeActionActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, + {"setFrameProperty", (PyCFunction) BL_ShapeActionActuator::sPySetFrameProperty, METH_VARARGS, (PY_METHODCHAR)SetFrameProperty_doc}, + {"setBlendtime", (PyCFunction) BL_ShapeActionActuator::sPySetBlendtime, METH_VARARGS, (PY_METHODCHAR)SetBlendtime_doc}, + + {"getAction", (PyCFunction) BL_ShapeActionActuator::sPyGetAction, METH_NOARGS, (PY_METHODCHAR)GetAction_doc}, + {"getStart", (PyCFunction) BL_ShapeActionActuator::sPyGetStart, METH_NOARGS, (PY_METHODCHAR)GetStart_doc}, + {"getEnd", (PyCFunction) BL_ShapeActionActuator::sPyGetEnd, METH_NOARGS, (PY_METHODCHAR)GetEnd_doc}, + {"getBlendin", (PyCFunction) BL_ShapeActionActuator::sPyGetBlendin, METH_NOARGS, (PY_METHODCHAR)GetBlendin_doc}, + {"getPriority", (PyCFunction) BL_ShapeActionActuator::sPyGetPriority, METH_NOARGS, (PY_METHODCHAR)GetPriority_doc}, + {"getFrame", (PyCFunction) BL_ShapeActionActuator::sPyGetFrame, METH_NOARGS, (PY_METHODCHAR)GetFrame_doc}, + {"getProperty", (PyCFunction) BL_ShapeActionActuator::sPyGetProperty, METH_NOARGS, (PY_METHODCHAR)GetProperty_doc}, + {"getFrameProperty", (PyCFunction) BL_ShapeActionActuator::sPyGetFrameProperty, METH_NOARGS, (PY_METHODCHAR)GetFrameProperty_doc}, + {"getType", (PyCFunction) BL_ShapeActionActuator::sPyGetType, METH_NOARGS, (PY_METHODCHAR)GetType_doc}, + {"setType", (PyCFunction) BL_ShapeActionActuator::sPySetType, METH_NOARGS, (PY_METHODCHAR)SetType_doc}, {NULL,NULL} //Sentinel }; @@ -459,7 +572,7 @@ PyObject* BL_ShapeActionActuator::_getattr(const STR_String& attr) { } /* setStart */ -char BL_ShapeActionActuator::GetAction_doc[] = +const char BL_ShapeActionActuator::GetAction_doc[] = "getAction()\n" "\tReturns a string containing the name of the current action.\n"; @@ -471,7 +584,7 @@ PyObject* BL_ShapeActionActuator::PyGetAction(PyObject* self) { } /* getProperty */ -char BL_ShapeActionActuator::GetProperty_doc[] = +const char BL_ShapeActionActuator::GetProperty_doc[] = "getProperty()\n" "\tReturns the name of the property to be used in FromProp mode.\n"; @@ -484,7 +597,7 @@ PyObject* BL_ShapeActionActuator::PyGetProperty(PyObject* self) { } /* getFrame */ -char BL_ShapeActionActuator::GetFrame_doc[] = +const char BL_ShapeActionActuator::GetFrame_doc[] = "getFrame()\n" "\tReturns the current frame number.\n"; @@ -497,7 +610,7 @@ PyObject* BL_ShapeActionActuator::PyGetFrame(PyObject* self) { } /* getEnd */ -char BL_ShapeActionActuator::GetEnd_doc[] = +const char BL_ShapeActionActuator::GetEnd_doc[] = "getEnd()\n" "\tReturns the last frame of the action.\n"; @@ -510,7 +623,7 @@ PyObject* BL_ShapeActionActuator::PyGetEnd(PyObject* self) { } /* getStart */ -char BL_ShapeActionActuator::GetStart_doc[] = +const char BL_ShapeActionActuator::GetStart_doc[] = "getStart()\n" "\tReturns the starting frame of the action.\n"; @@ -523,7 +636,7 @@ PyObject* BL_ShapeActionActuator::PyGetStart(PyObject* self) { } /* getBlendin */ -char BL_ShapeActionActuator::GetBlendin_doc[] = +const char BL_ShapeActionActuator::GetBlendin_doc[] = "getBlendin()\n" "\tReturns the number of interpolation animation frames to be\n" "\tgenerated when this actuator is triggered.\n"; @@ -537,7 +650,7 @@ PyObject* BL_ShapeActionActuator::PyGetBlendin(PyObject* self) { } /* getPriority */ -char BL_ShapeActionActuator::GetPriority_doc[] = +const char BL_ShapeActionActuator::GetPriority_doc[] = "getPriority()\n" "\tReturns the priority for this actuator. Actuators with lower\n" "\tPriority numbers will override actuators with higher numbers.\n"; @@ -551,7 +664,7 @@ PyObject* BL_ShapeActionActuator::PyGetPriority(PyObject* self) { } /* setAction */ -char BL_ShapeActionActuator::SetAction_doc[] = +const char BL_ShapeActionActuator::SetAction_doc[] = "setAction(action, (reset))\n" "\t - action : The name of the action to set as the current action.\n" "\t Should be an action with Shape channels.\n" @@ -591,7 +704,7 @@ PyObject* BL_ShapeActionActuator::PySetAction(PyObject* self, } /* setStart */ -char BL_ShapeActionActuator::SetStart_doc[] = +const char BL_ShapeActionActuator::SetStart_doc[] = "setStart(start)\n" "\t - start : Specifies the starting frame of the animation.\n"; @@ -612,7 +725,7 @@ PyObject* BL_ShapeActionActuator::PySetStart(PyObject* self, } /* setEnd */ -char BL_ShapeActionActuator::SetEnd_doc[] = +const char BL_ShapeActionActuator::SetEnd_doc[] = "setEnd(end)\n" "\t - end : Specifies the ending frame of the animation.\n"; @@ -633,7 +746,7 @@ PyObject* BL_ShapeActionActuator::PySetEnd(PyObject* self, } /* setBlendin */ -char BL_ShapeActionActuator::SetBlendin_doc[] = +const char BL_ShapeActionActuator::SetBlendin_doc[] = "setBlendin(blendin)\n" "\t - blendin : Specifies the number of frames of animation to generate\n" "\t when making transitions between actions.\n"; @@ -655,7 +768,7 @@ PyObject* BL_ShapeActionActuator::PySetBlendin(PyObject* self, } /* setBlendtime */ -char BL_ShapeActionActuator::SetBlendtime_doc[] = +const char BL_ShapeActionActuator::SetBlendtime_doc[] = "setBlendtime(blendtime)\n" "\t - blendtime : Allows the script to directly modify the internal timer\n" "\t used when generating transitions between actions. This\n" @@ -682,7 +795,7 @@ PyObject* BL_ShapeActionActuator::PySetBlendtime(PyObject* self, } /* setPriority */ -char BL_ShapeActionActuator::SetPriority_doc[] = +const char BL_ShapeActionActuator::SetPriority_doc[] = "setPriority(priority)\n" "\t - priority : Specifies the new priority. Actuators will lower\n" "\t priority numbers will override actuators with higher\n" @@ -704,8 +817,22 @@ PyObject* BL_ShapeActionActuator::PySetPriority(PyObject* self, Py_RETURN_NONE; } +/* getProperty */ +const char BL_ShapeActionActuator::GetFrameProperty_doc[] = +"getFrameProperty()\n" +"\tReturns the name of the property, that is set to the current frame number.\n"; + +PyObject* BL_ShapeActionActuator::PyGetFrameProperty(PyObject* self) { + PyObject *result; + + result = Py_BuildValue("s", (const char *)m_framepropname); + + return result; +} + + /* setFrame */ -char BL_ShapeActionActuator::SetFrame_doc[] = +const char BL_ShapeActionActuator::SetFrame_doc[] = "setFrame(frame)\n" "\t - frame : Specifies the new current frame for the animation\n"; @@ -730,7 +857,7 @@ PyObject* BL_ShapeActionActuator::PySetFrame(PyObject* self, } /* setProperty */ -char BL_ShapeActionActuator::SetProperty_doc[] = +const char BL_ShapeActionActuator::SetProperty_doc[] = "setProperty(prop)\n" "\t - prop : A string specifying the property name to be used in\n" "\t FromProp playback mode.\n"; @@ -751,8 +878,29 @@ PyObject* BL_ShapeActionActuator::PySetProperty(PyObject* self, Py_RETURN_NONE; } +/* setFrameProperty */ +const char BL_ShapeActionActuator::SetFrameProperty_doc[] = +"setFrameProperty(prop)\n" +"\t - prop : A string specifying the property of the frame set up update.\n"; + +PyObject* BL_ShapeActionActuator::PySetFrameProperty(PyObject* self, + PyObject* args, + PyObject* kwds) { + char *string; + + if (PyArg_ParseTuple(args,"s",&string)) + { + m_framepropname = string; + } + else { + return NULL; + } + + Py_RETURN_NONE; +} + /* getType */ -char BL_ShapeActionActuator::GetType_doc[] = +const char BL_ShapeActionActuator::GetType_doc[] = "getType()\n" "\tReturns the operation mode of the actuator.\n"; PyObject* BL_ShapeActionActuator::PyGetType(PyObject* self) { @@ -760,7 +908,7 @@ PyObject* BL_ShapeActionActuator::PyGetType(PyObject* self) { } /* setType */ -char BL_ShapeActionActuator::SetType_doc[] = +const char BL_ShapeActionActuator::SetType_doc[] = "setType(mode)\n" "\t - mode: Play (0), Flipper (2), LoopStop (3), LoopEnd (4) or Property (6)\n" "\tSet the operation mode of the actuator.\n"; diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.h b/source/gameengine/Converter/BL_ShapeActionActuator.h index 10cbe9f1ac3..92f75d12764 100644 --- a/source/gameengine/Converter/BL_ShapeActionActuator.h +++ b/source/gameengine/Converter/BL_ShapeActionActuator.h @@ -42,6 +42,7 @@ public: Py_Header; BL_ShapeActionActuator(SCA_IObject* gameobj, const STR_String& propname, + const STR_String& framepropname, float starttime, float endtime, struct bAction *action, @@ -66,6 +67,7 @@ public: m_playtype(playtype), m_priority(priority), m_action(action), + m_framepropname(framepropname), m_propname(propname) { }; @@ -84,6 +86,7 @@ public: KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetEnd); KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetFrame); KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetProperty); + KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetFrameProperty); KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetBlendtime); KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetChannel); @@ -94,6 +97,7 @@ public: KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetEnd); KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetFrame); KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetProperty); + KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetFrameProperty); // KX_PYMETHOD(BL_ActionActuator,GetChannel); KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetType); KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetType); @@ -126,6 +130,7 @@ protected: short m_priority; struct bAction *m_action; STR_String m_propname; + STR_String m_framepropname; vector<float> m_blendshape; }; diff --git a/source/gameengine/Converter/BL_ShapeDeformer.cpp b/source/gameengine/Converter/BL_ShapeDeformer.cpp index d3fbb795b23..264deb26eb0 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.cpp +++ b/source/gameengine/Converter/BL_ShapeDeformer.cpp @@ -68,7 +68,7 @@ BL_ShapeDeformer::~BL_ShapeDeformer() { }; -RAS_Deformer *BL_ShapeDeformer::GetReplica() +RAS_Deformer *BL_ShapeDeformer::GetReplica(class KX_GameObject* replica) { BL_ShapeDeformer *result; @@ -109,12 +109,10 @@ bool BL_ShapeDeformer::ExecuteShapeDrivers(void) vector<IpoCurve*>::iterator it; void *poin; int type; + // the shape drivers use the bone matrix as input. Must // update the matrix now - Object* par_arma = m_armobj->GetArmatureObject(); m_armobj->ApplyPose(); - where_is_pose( par_arma ); - PoseApplied(true); for (it=m_shapeDrivers.begin(); it!=m_shapeDrivers.end(); it++) { // no need to set a specific time: this curve has a driver @@ -124,7 +122,10 @@ bool BL_ShapeDeformer::ExecuteShapeDrivers(void) if (poin) write_ipo_poin(poin, type, icu->curval); } + ForceUpdate(); + m_armobj->RestorePose(); + return true; } return false; diff --git a/source/gameengine/Converter/BL_ShapeDeformer.h b/source/gameengine/Converter/BL_ShapeDeformer.h index d3d699b8ddc..b5443ae4dd1 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.h +++ b/source/gameengine/Converter/BL_ShapeDeformer.h @@ -43,17 +43,6 @@ struct IpoCurve; class BL_ShapeDeformer : public BL_SkinDeformer { public: - virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map) - { - void **h_obj = (*map)[m_gameobj]; - if (h_obj){ - m_gameobj = (BL_DeformableGameObject*)(*h_obj); - } - else - m_gameobj=NULL; - // relink the underlying skin deformer - BL_SkinDeformer::Relink(map); - }; BL_ShapeDeformer(BL_DeformableGameObject *gameobj, Object *bmeshobj, BL_SkinMeshObject *mesh) @@ -77,7 +66,7 @@ public: }; virtual void ProcessReplica(); - virtual RAS_Deformer *GetReplica(); + virtual RAS_Deformer *GetReplica(class KX_GameObject* replica); virtual ~BL_ShapeDeformer(); bool Update (void); diff --git a/source/gameengine/Converter/BL_SkinDeformer.cpp b/source/gameengine/Converter/BL_SkinDeformer.cpp index f96c40c098f..d8563763954 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.cpp +++ b/source/gameengine/Converter/BL_SkinDeformer.cpp @@ -99,9 +99,26 @@ BL_SkinDeformer::~BL_SkinDeformer() m_armobj->Release(); } +void BL_SkinDeformer::Relink(GEN_Map<class GEN_HashedPtr, void*>*map) +{ + if (m_armobj) { + void **h_obj = (*map)[m_armobj]; + + if (h_obj) + SetArmature( (BL_ArmatureObject*)(*h_obj) ); + else + m_armobj=NULL; + } + + BL_MeshDeformer::Relink(map); +} + bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat) { - size_t i, j; + RAS_MeshSlot::iterator it; + RAS_MeshMaterial *mmat; + RAS_MeshSlot *slot; + size_t i; // update the vertex in m_transverts Update(); @@ -110,16 +127,18 @@ bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat) // Duplicated objects with more than one ploymaterial (=multiple mesh slot per object) // share the same mesh (=the same cache). As the rendering is done per polymaterial // cycling through the objects, the entire mesh cache cannot be updated in one shot. - vecVertexArray& vertexarrays = m_pMeshObject->GetVertexCache(mat); + mmat = m_pMeshObject->GetMeshMaterial(mat); + if(!mmat->m_slots[(void*)m_gameobj]) + return true; - // For each array - for (i=0; i<vertexarrays.size(); i++) { - KX_VertexArray& vertexarray = (*vertexarrays[i]); + slot = *mmat->m_slots[(void*)m_gameobj]; - // For each vertex + // for each array + for(slot->begin(it); !slot->end(it); slot->next(it)) { + // for each vertex // copy the untransformed data from the original mvert - for (j=0; j<vertexarray.size(); j++) { - RAS_TexVert& v = vertexarray[j]; + for(i=it.startvertex; i<it.endvertex; i++) { + RAS_TexVert& v = it.vertex[i]; v.SetXYZ(m_transverts[v.getOrigIndex()]); } } @@ -127,7 +146,7 @@ bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat) return true; } -RAS_Deformer *BL_SkinDeformer::GetReplica() +RAS_Deformer *BL_SkinDeformer::GetReplica(class KX_GameObject* replica) { BL_SkinDeformer *result; @@ -147,14 +166,10 @@ bool BL_SkinDeformer::Update(void) /* See if the armature has been updated for this frame */ if (PoseUpdated()){ float obmat[4][4]; // the original object matrice - + /* XXX note: where_is_pose() (from BKE_armature.h) calculates all matrices needed to start deforming */ /* but it requires the blender object pointer... */ Object* par_arma = m_armobj->GetArmatureObject(); - if (!PoseApplied()){ - m_armobj->ApplyPose(); - where_is_pose( par_arma ); - } /* store verts locally */ VerifyStorage(); @@ -163,6 +178,8 @@ bool BL_SkinDeformer::Update(void) for (int v =0; v<m_bmesh->totvert; v++) VECCOPY(m_transverts[v], m_bmesh->mvert[v].co); + m_armobj->ApplyPose(); + // save matrix first Mat4CpyMat4(obmat, m_objMesh->obmat); // set reference matrix @@ -179,11 +196,13 @@ bool BL_SkinDeformer::Update(void) /* Update the current frame */ m_lastArmaUpdate=m_armobj->GetLastFrame(); - /* reset for next frame */ - PoseApplied(false); + + m_armobj->RestorePose(); + /* indicate that the m_transverts and normals are up to date */ return true; } + return false; } diff --git a/source/gameengine/Converter/BL_SkinDeformer.h b/source/gameengine/Converter/BL_SkinDeformer.h index d3fc5ae2a81..f87860021c6 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.h +++ b/source/gameengine/Converter/BL_SkinDeformer.h @@ -50,17 +50,7 @@ class BL_SkinDeformer : public BL_MeshDeformer { public: // void SetArmatureController (BL_ArmatureController *cont); - virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map) - { - if (m_armobj){ - void **h_obj = (*map)[m_armobj]; - if (h_obj){ - SetArmature( (BL_ArmatureObject*)(*h_obj) ); - } - else - m_armobj=NULL; - } - } + virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map); void SetArmature (class BL_ArmatureObject *armobj); BL_SkinDeformer(BL_DeformableGameObject *gameobj, @@ -77,14 +67,10 @@ public: BL_ArmatureObject* arma = NULL); virtual void ProcessReplica(); - virtual RAS_Deformer *GetReplica(); + virtual RAS_Deformer *GetReplica(class KX_GameObject* replica); virtual ~BL_SkinDeformer(); bool Update (void); bool Apply (class RAS_IPolyMaterial *polymat); - bool PoseApplied() - { return m_poseApplied; } - void PoseApplied(bool applied) - { m_poseApplied = applied; } bool PoseUpdated(void) { if (m_armobj && m_lastArmaUpdate!=m_armobj->GetLastFrame()) { diff --git a/source/gameengine/Converter/BL_SkinMeshObject.cpp b/source/gameengine/Converter/BL_SkinMeshObject.cpp index fa215df1e1c..eb3f9d0588d 100644 --- a/source/gameengine/Converter/BL_SkinMeshObject.cpp +++ b/source/gameengine/Converter/BL_SkinMeshObject.cpp @@ -28,42 +28,69 @@ * Deformer that supports armature skinning */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #ifdef WIN32 #pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning #endif //WIN32 -#include "RAS_IPolygonMaterial.h" -#include "BL_SkinMeshObject.h" -#include "BL_DeformableGameObject.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_key_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "KX_GameObject.h" + #include "RAS_BucketManager.h" +#include "RAS_IPolygonMaterial.h" -//void BL_SkinMeshObject::Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec,RAS_BucketManager* bucketmgr) -void BL_SkinMeshObject::Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec) -{ +#include "KX_GameObject.h" + +#include "BL_SkinMeshObject.h" +#include "BL_DeformableGameObject.h" - KX_MeshSlot ms; - ms.m_clientObj = clientobj; - ms.m_mesh = this; - ms.m_OpenGLMatrix = oglmatrix; - ms.m_bObjectColor = useObjectColor; - ms.m_RGBAcolor = rgbavec; - ms.m_pDeformer = ((BL_DeformableGameObject*)clientobj)->m_pDeformer; - - for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();it++) +BL_SkinMeshObject::BL_SkinMeshObject(Mesh* mesh, int lightlayer) + : RAS_MeshObject (mesh, lightlayer) +{ + m_bDeformed = true; + + if (m_mesh && m_mesh->key) { + KeyBlock *kb; + int count=0; + // initialize weight cache for shape objects + // count how many keys in this mesh + for(kb= (KeyBlock*)m_mesh->key->block.first; kb; kb= (KeyBlock*)kb->next) + count++; + m_cacheWeightIndex.resize(count,-1); + } +} - RAS_MaterialBucket* materialbucket = (*it); +BL_SkinMeshObject::~BL_SkinMeshObject() +{ + if (m_mesh && m_mesh->key) + { + KeyBlock *kb; + // remove the weight cache to avoid memory leak + for(kb= (KeyBlock*)m_mesh->key->block.first; kb; kb= (KeyBlock*)kb->next) { + if(kb->weights) + MEM_freeN(kb->weights); + kb->weights= NULL; + } + } +} + +void BL_SkinMeshObject::UpdateBuckets(void* clientobj,double* oglmatrix,bool useObjectColor,const MT_Vector4& rgbavec, bool visible, bool culled) +{ + list<RAS_MeshMaterial>::iterator it; + list<RAS_MeshSlot*>::iterator sit; + + for(it = m_materials.begin();it!=m_materials.end();++it) { + if(!it->m_slots[clientobj]) + continue; -// KX_ArrayOptimizer* oa = GetArrayOptimizer(materialbucket->GetPolyMaterial()); - materialbucket->SetMeshSlot(ms); + RAS_MeshSlot *slot = *it->m_slots[clientobj]; + slot->m_pDeformer = ((BL_DeformableGameObject*)clientobj)->GetDeformer(); } + RAS_MeshObject::UpdateBuckets(clientobj, oglmatrix, useObjectColor, rgbavec, visible, culled); } static int get_def_index(Object* ob, const char* vgroup) @@ -74,6 +101,7 @@ static int get_def_index(Object* ob, const char* vgroup) for (curdef = (bDeformGroup*)ob->defbase.first; curdef; curdef=(bDeformGroup*)curdef->next, index++) if (!strcmp(curdef->name, vgroup)) return index; + return -1; } diff --git a/source/gameengine/Converter/BL_SkinMeshObject.h b/source/gameengine/Converter/BL_SkinMeshObject.h index c21fb64204b..8544a2b958c 100644 --- a/source/gameengine/Converter/BL_SkinMeshObject.h +++ b/source/gameengine/Converter/BL_SkinMeshObject.h @@ -33,62 +33,27 @@ #ifdef WIN32 #pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning #endif //WIN32 -#include "MEM_guardedalloc.h" + #include "RAS_MeshObject.h" #include "RAS_Deformer.h" #include "RAS_IPolygonMaterial.h" #include "BL_MeshDeformer.h" -#include "DNA_mesh_types.h" -#include "DNA_key_types.h" -#include "DNA_meshdata_types.h" - class BL_SkinMeshObject : public RAS_MeshObject { - -// enum { BUCKET_MAX_INDICES = 16384};//2048};//8192}; -// enum { BUCKET_MAX_TRIANGLES = 4096}; - protected: vector<int> m_cacheWeightIndex; public: - void Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec); -// void Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec,class RAS_BucketManager* bucketmgr); - - BL_SkinMeshObject(Mesh* mesh, int lightlayer) : RAS_MeshObject (mesh, lightlayer) - { - m_class = 1; - if (m_mesh && m_mesh->key) - { - KeyBlock *kb; - int count=0; - // initialize weight cache for shape objects - // count how many keys in this mesh - for(kb= (KeyBlock*)m_mesh->key->block.first; kb; kb= (KeyBlock*)kb->next) - count++; - m_cacheWeightIndex.resize(count,-1); - } - }; + BL_SkinMeshObject(Mesh* mesh, int lightlayer); + ~BL_SkinMeshObject(); - virtual ~BL_SkinMeshObject() - { - if (m_mesh && m_mesh->key) - { - KeyBlock *kb; - // remove the weight cache to avoid memory leak - for(kb= (KeyBlock*)m_mesh->key->block.first; kb; kb= (KeyBlock*)kb->next) { - if(kb->weights) - MEM_freeN(kb->weights); - kb->weights= NULL; - } - } - }; + void UpdateBuckets(void* clientobj, double* oglmatrix, + bool useObjectColor, const MT_Vector4& rgbavec, bool visible, bool culled); // for shape keys, void CheckWeightCache(struct Object* obj); - }; #endif diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt index adb7304b10e..217bdb30907 100644 --- a/source/gameengine/Converter/CMakeLists.txt +++ b/source/gameengine/Converter/CMakeLists.txt @@ -64,6 +64,7 @@ SET(INC ../../../source/gameengine/Network/LoopBackNetwork ../../../source/blender/misc ../../../source/blender/blenloader + ../../../source/blender/gpu ../../../extern/bullet2/src ../../../extern/solid ${PYTHON_INC} diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index de91bce2ab1..7eec93dc402 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -184,20 +184,21 @@ bool KX_BlenderSceneConverter::TryAndLoadNewFile() return result; } - +Scene *KX_BlenderSceneConverter::GetBlenderSceneForName(const STR_String& name) +{ + Scene *sce; /** * Find the specified scene by name, or the first * scene if nothing matches (shouldn't happen). */ -static struct Scene *GetSceneForName2(struct Main *maggie, const STR_String& scenename) { - Scene *sce; - for (sce= (Scene*) maggie->scene.first; sce; sce= (Scene*) sce->id.next) - if (scenename == (sce->id.name+2)) + for (sce= (Scene*) m_maggie->scene.first; sce; sce= (Scene*) sce->id.next) + if (name == (sce->id.name+2)) return sce; - return (Scene*) maggie->scene.first; + return (Scene*)m_maggie->scene.first; + } #include "KX_PythonInit.h" @@ -245,6 +246,11 @@ struct BlenderDebugDraw : public btIDebugDraw { return m_debugMode; } + ///todo: find out if Blender can do this + virtual void draw3dText(const btVector3& location,const char* textString) + { + + } }; @@ -258,7 +264,7 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename, class RAS_ICanvas* canvas) { //find out which physics engine - Scene *blenderscene = GetSceneForName2(m_maggie, scenename); + Scene *blenderscene = GetBlenderSceneForName(scenename); e_PhysicsEngine physics_engine = UseBullet; // hook for registration function during conversion. @@ -495,7 +501,17 @@ void KX_BlenderSceneConverter::RegisterGameObject( void KX_BlenderSceneConverter::UnregisterGameObject( KX_GameObject *gameobject) { - m_map_gameobject_to_blender.remove(CHashedPtr(gameobject)); + CHashedPtr gptr(gameobject); + struct Object **bobp= m_map_gameobject_to_blender[gptr]; + if (bobp) { + CHashedPtr bptr(*bobp); + KX_GameObject **gobp= m_map_blender_to_gameobject[bptr]; + if (gobp && *gobp == gameobject) + // also maintain m_map_blender_to_gameobject if the gameobject + // being removed is matching the blender object + m_map_blender_to_gameobject.remove(bptr); + m_map_gameobject_to_blender.remove(gptr); + } } @@ -644,13 +660,13 @@ extern "C" { Ipo *add_ipo( char *name, int idcode ); char *getIpoCurveName( IpoCurve * icu ); - struct IpoCurve *verify_ipocurve(struct ID *, short, char *, char *, char *, int); + struct IpoCurve *verify_ipocurve(struct ID *, short, char *, char *, char *, int, short); void testhandles_ipocurve(struct IpoCurve *icu); + void insert_vert_icu(struct IpoCurve *, float, float, short); void Mat3ToEul(float tmat[][3], float *eul); - } -IpoCurve* findIpoCurve(IpoCurve* first,char* searchName) +IpoCurve* findIpoCurve(IpoCurve* first, const char* searchName) { IpoCurve* icu1; for( icu1 = first; icu1; icu1 = icu1->next ) @@ -818,7 +834,7 @@ void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber) KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g); if (gameObj->IsDynamic()) { - KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); + //KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); Object* blenderObject = FindBlenderObject(gameObj); if (blenderObject) @@ -846,7 +862,7 @@ void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber) - const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); + //const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); const MT_Point3& position = gameObj->NodeGetWorldPosition(); Ipo* ipo = blenderObject->ipo; @@ -857,27 +873,27 @@ void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber) IpoCurve *icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z, 1); @@ -974,7 +990,7 @@ void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo() KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g); if (gameObj->IsDynamic()) { - KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); + //KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); Object* blenderObject = FindBlenderObject(gameObj); if (blenderObject) @@ -1002,8 +1018,8 @@ void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo() - const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); - const MT_Point3& position = gameObj->NodeGetWorldPosition(); + //const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); + //const MT_Point3& position = gameObj->NodeGetWorldPosition(); Ipo* ipo = blenderObject->ipo; if (ipo) @@ -1013,27 +1029,27 @@ void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo() IpoCurve *icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z, 1); diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.h b/source/gameengine/Converter/KX_BlenderSceneConverter.h index e5d6ccc5caf..2317e952a0a 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.h +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.h @@ -45,6 +45,7 @@ class BL_Material; struct IpoCurve; struct Main; struct SpaceIpo; +struct Scene; class KX_BlenderSceneConverter : public KX_ISceneConverter { @@ -151,6 +152,7 @@ public: virtual void SetGLSLMaterials(bool val); virtual bool GetGLSLMaterials(); + struct Scene* GetBlenderSceneForName(const STR_String& name); }; #endif //__KX_BLENDERSCENECONVERTER_H diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index cb2521de9a4..d5f304c38e7 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -74,6 +74,8 @@ #include "BKE_text.h" #include "BLI_blenlib.h" +#define FILE_MAX 240 // repeated here to avoid dependency from BKE_utildefines.h + #include "KX_NetworkMessageActuator.h" #ifdef WIN32 @@ -208,10 +210,12 @@ void BL_ConvertActuators(char* maggiename, if (blenderobject->type==OB_MESH){ bActionActuator* actact = (bActionActuator*) bact->data; STR_String propname = (actact->name ? actact->name : ""); + STR_String propframe = (actact->frameProp ? actact->frameProp : ""); BL_ShapeActionActuator* tmpbaseact = new BL_ShapeActionActuator( gameobj, propname, + propframe, actact->sta, actact->end, actact->act, @@ -231,7 +235,8 @@ void BL_ConvertActuators(char* maggiename, { bIpoActuator* ipoact = (bIpoActuator*) bact->data; bool ipochild = (ipoact->flag & ACT_IPOCHILD) !=0; - STR_String propname = ( ipoact->name ? ipoact->name : ""); + STR_String propname = ipoact->name; + STR_String frameProp = ipoact->frameProp; // first bit? bool ipo_as_force = (ipoact->flag & ACT_IPOFORCE); bool local = (ipoact->flag & ACT_IPOLOCAL); @@ -240,6 +245,7 @@ void BL_ConvertActuators(char* maggiename, KX_IpoActuator* tmpbaseact = new KX_IpoActuator( gameobj, propname , + frameProp, ipoact->sta, ipoact->end, ipochild, @@ -355,22 +361,26 @@ void BL_ConvertActuators(char* maggiename, if (soundActuatorType != KX_SoundActuator::KX_SOUNDACT_NODEF) { - SND_SoundObject* sndobj = NULL; + SND_Scene* soundscene = scene->GetSoundScene(); + STR_String samplename = ""; + bool sampleisloaded = false; - if (soundact->sound) - { - SND_Scene* soundscene = scene->GetSoundScene(); - STR_String samplename = soundact->sound->name; + if (soundact->sound) { + /* Need to convert the samplename into absolute path + * before checking if its loaded */ + char fullpath[FILE_MAX]; - bool sampleisloaded = false; + /* dont modify soundact->sound->name, only change a copy */ + BLI_strncpy(fullpath, soundact->sound->name, sizeof(fullpath)); + BLI_convertstringcode(fullpath, maggiename); + samplename = fullpath; /* let's see if the sample was already loaded */ if (soundscene->IsSampleLoaded(samplename)) { sampleisloaded = true; } - else - { + else { /* if not, make it so */ PackedFile* pf = soundact->sound->newpackedfile; @@ -383,21 +393,33 @@ void BL_ConvertActuators(char* maggiename, /* or else load it from disk */ else { - /* but we need to convert the samplename into absolute pathname first */ - BLI_convertstringcode(soundact->sound->name, maggiename); - samplename = soundact->sound->name; - - /* and now we can load it */ - if (soundscene->LoadSample(samplename, NULL, 0) > -1) + if (soundscene->LoadSample(samplename, NULL, 0) > -1) { sampleisloaded = true; + } + else { + std::cout << "WARNING: Sound actuator \"" << bact->name << + "\" from object \"" << blenderobject->id.name+2 << + "\" failed to load sample." << std::endl; + } } } - - if (sampleisloaded) - { - sndobj = new SND_SoundObject(); - sndobj->SetSampleName(samplename.Ptr()); - sndobj->SetObjectName(bact->name); + } else { + std::cout << "WARNING: Sound actuator \"" << bact->name << + "\" from object \"" << blenderobject->id.name+2 << + "\" has no sound datablock." << std::endl; + } + + /* Note, allowing actuators for sounds that are not there was added since 2.47 + * This is because python may expect the actuator and raise an exception if it dosnt find it + * better just to add a dummy sound actuator. */ + SND_SoundObject* sndobj = NULL; + if (sampleisloaded) + { + /* setup the SND_SoundObject */ + sndobj = new SND_SoundObject(); + sndobj->SetSampleName(samplename.Ptr()); + sndobj->SetObjectName(bact->name); + if (soundact->sound) { sndobj->SetRollOffFactor(soundact->sound->attenuation); sndobj->SetGain(soundact->sound->volume); sndobj->SetPitch(exp((soundact->sound->pitch / 12.0) * log(2.0))); @@ -410,8 +432,9 @@ void BL_ConvertActuators(char* maggiename, else sndobj->SetLoopMode(SND_LOOP_NORMAL); } - else + else { sndobj->SetLoopMode(SND_LOOP_OFF); + } if (soundact->sound->flags & SOUND_FLAGS_PRIORITY) sndobj->SetHighPriority(true); @@ -422,22 +445,30 @@ void BL_ConvertActuators(char* maggiename, sndobj->Set3D(true); else sndobj->Set3D(false); - - KX_SoundActuator* tmpsoundact = - new KX_SoundActuator(gameobj, - sndobj, - scene->GetSoundScene(), // needed for replication! - soundActuatorType, - startFrame, - stopFrame); - - tmpsoundact->SetName(bact->name); - baseact = tmpsoundact; - soundscene->AddObject(sndobj); - } else { - std::cout << "WARNING: Sound actuator " << bact->name << " failed to load sample." << std::endl; + } + else { + /* dummy values for a NULL sound + * see editsound.c - defaults are unlikely to change soon */ + sndobj->SetRollOffFactor(1.0); + sndobj->SetGain(1.0); + sndobj->SetPitch(1.0); + sndobj->SetLoopMode(SND_LOOP_OFF); + sndobj->SetHighPriority(false); + sndobj->Set3D(false); } } + KX_SoundActuator* tmpsoundact = + new KX_SoundActuator(gameobj, + sndobj, + scene->GetSoundScene(), // needed for replication! + soundActuatorType, + startFrame, + stopFrame); + + tmpsoundact->SetName(bact->name); + baseact = tmpsoundact; + if (sndobj) + soundscene->AddObject(sndobj); } break; } @@ -550,10 +581,16 @@ void BL_ConvertActuators(char* maggiename, originalval = converter->FindGameObject(editobact->ob); } } - MT_Vector3 linvelvec ( KX_BLENDERTRUNC(editobact->linVelocity[0]), + MT_Vector3 linvelvec ( + KX_BLENDERTRUNC(editobact->linVelocity[0]), KX_BLENDERTRUNC(editobact->linVelocity[1]), KX_BLENDERTRUNC(editobact->linVelocity[2])); - + + MT_Vector3 angvelvec ( + KX_BLENDERTRUNC(editobact->angVelocity[0]), + KX_BLENDERTRUNC(editobact->angVelocity[1]), + KX_BLENDERTRUNC(editobact->angVelocity[2])); + KX_SCA_AddObjectActuator* tmpaddact = new KX_SCA_AddObjectActuator( gameobj, @@ -561,7 +598,9 @@ void BL_ConvertActuators(char* maggiename, editobact->time, scene, linvelvec.getValue(), - editobact->localflag!=0 + (editobact->localflag & ACT_EDOB_LOCAL_LINV)!=0, + angvelvec.getValue(), + (editobact->localflag & ACT_EDOB_LOCAL_ANGV)!=0 ); //editobact->ob to gameobj @@ -682,6 +721,40 @@ void BL_ConvertActuators(char* maggiename, break; } prop = conact->matprop; + } else if (conact->type == ACT_CONST_TYPE_FH) { + switch (conact->mode) { + case ACT_CONST_DIRPX: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + case ACT_CONST_DIRPY: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + case ACT_CONST_DIRPZ: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + case ACT_CONST_DIRNX: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + case ACT_CONST_DIRNY: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + case ACT_CONST_DIRNZ: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + } + prop = conact->matprop; } else { switch (conact->flag) { case ACT_CONST_LOCX: @@ -843,6 +916,16 @@ void BL_ConvertActuators(char* maggiename, mode = KX_GameActuator::KX_GAME_QUIT; break; } + case ACT_GAME_SAVECFG: + { + mode = KX_GameActuator::KX_GAME_SAVECFG; + break; + } + case ACT_GAME_LOADCFG: + { + mode = KX_GameActuator::KX_GAME_LOADCFG; + break; + } default: ; /* flag error */ } @@ -929,10 +1012,9 @@ void BL_ConvertActuators(char* maggiename, bVisibilityActuator *vis_act = (bVisibilityActuator *) bact->data; KX_VisibilityActuator * tmp_vis_act = NULL; bool v = ((vis_act->flag & ACT_VISIBILITY_INVISIBLE) != 0); + bool recursive = ((vis_act->flag & ACT_VISIBILITY_RECURSIVE) != 0); - tmp_vis_act = - new KX_VisibilityActuator(gameobj, - !v); + tmp_vis_act = new KX_VisibilityActuator(gameobj, !v, recursive); baseact = tmp_vis_act; } @@ -1031,7 +1113,7 @@ void BL_ConvertActuators(char* maggiename, { bParentActuator *parAct = (bParentActuator *) bact->data; int mode = KX_ParentActuator::KX_PARENT_NODEF; - KX_GameObject *tmpgob; + KX_GameObject *tmpgob = NULL; switch(parAct->type) { diff --git a/source/gameengine/Converter/KX_ConvertProperties.cpp b/source/gameengine/Converter/KX_ConvertProperties.cpp index aae8752671f..dfbc6f0c48d 100644 --- a/source/gameengine/Converter/KX_ConvertProperties.cpp +++ b/source/gameengine/Converter/KX_ConvertProperties.cpp @@ -132,6 +132,10 @@ void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventMan prop = prop->next; } - - + // check if state needs to be debugged + if (object->scaflag & OB_DEBUGSTATE) + { + // reserve name for object state + scene->AddDebugProperty(gameobj,STR_String("__state__")); + } } diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp index 5e433bb821b..be0bb8103c0 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.cpp +++ b/source/gameengine/Converter/KX_ConvertSensors.cpp @@ -65,6 +65,7 @@ probably misplaced */ #include "SCA_JoystickSensor.h" #include "KX_NetworkMessageSensor.h" #include "SCA_ActuatorSensor.h" +#include "SCA_DelaySensor.h" #include "SCA_PropertySensor.h" @@ -91,6 +92,7 @@ void BL_ConvertSensors(struct Object* blenderobject, class KX_GameObject* gameobj, SCA_LogicManager* logicmgr, KX_Scene* kxscene, + KX_KetsjiEngine* kxengine, SCA_IInputDevice* keydev, int & executePriority, int activeLayerBitInfo, @@ -281,6 +283,22 @@ void BL_ConvertSensors(struct Object* blenderobject, break; } + case SENS_DELAY: + { + // we can reuse the Always event manager for the delay sensor + SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::ALWAYS_EVENTMGR); + if (eventmgr) + { + bDelaySensor* delaysensor = (bDelaySensor*)sens->data; + gamesensor = new SCA_DelaySensor(eventmgr, + gameobj, + delaysensor->delay, + delaysensor->duration, + (delaysensor->flag & SENS_DELAY_REPEAT) != 0); + } + break; + } + case SENS_COLLISION: { SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR); @@ -491,6 +509,7 @@ void BL_ConvertSensors(struct Object* blenderobject, trackfocus, canvas, kxscene, + kxengine, gameobj); } } else { @@ -616,6 +635,7 @@ void BL_ConvertSensors(struct Object* blenderobject, if (eventmgr) { bool bFindMaterial = (blenderraysensor->mode & SENS_COLLISION_MATERIAL); + bool bXRay = (blenderraysensor->mode & SENS_RAY_XRAY); STR_String checkname = (bFindMaterial? blenderraysensor->matname : blenderraysensor->propname); @@ -628,6 +648,7 @@ void BL_ConvertSensors(struct Object* blenderobject, gameobj, checkname, bFindMaterial, + bXRay, distance, axis, kxscene); @@ -694,6 +715,7 @@ void BL_ConvertSensors(struct Object* blenderobject, gamesensor = new SCA_JoystickSensor( eventmgr, gameobj, + bjoy->joyindex, joysticktype, axis,axisf, prec, @@ -741,12 +763,33 @@ void BL_ConvertSensors(struct Object* blenderobject, for (int i=0;i<sens->totlinks;i++) { bController* linkedcont = (bController*) sens->links[i]; - SCA_IController* gamecont = converter->FindGameController(linkedcont); + if (linkedcont) { + SCA_IController* gamecont = converter->FindGameController(linkedcont); - if (gamecont) { - logicmgr->RegisterToSensor(gamecont,gamesensor); + if (gamecont) { + logicmgr->RegisterToSensor(gamecont,gamesensor); + } else { + printf( + "Warning, sensor \"%s\" could not find its controller " + "(link %d of %d) from object \"%s\"\n" + "\tthere has been an error converting the blender controller for the game engine," + "logic may be incorrect\n", sens->name, i+1, sens->totlinks, blenderobject->id.name+2); + } + } else { + printf( + "Warning, sensor \"%s\" has lost a link to a controller " + "(link %d of %d) from object \"%s\"\n" + "\tpossible causes are partially appended objects or an error reading the file," + "logic may be incorrect\n", sens->name, i+1, sens->totlinks, blenderobject->id.name+2); } } + // special case: Keyboard sensor with no link + // this combination is usually used for key logging. + if (sens->type == SENS_KEYBOARD && sens->totlinks == 0) { + // Force the registration so that the sensor runs + gamesensor->IncLink(); + } + // done with gamesensor gamesensor->Release(); diff --git a/source/gameengine/Converter/KX_ConvertSensors.h b/source/gameengine/Converter/KX_ConvertSensors.h index 73da51f47f0..b18ffc10a2a 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.h +++ b/source/gameengine/Converter/KX_ConvertSensors.h @@ -33,6 +33,7 @@ void BL_ConvertSensors(struct Object* blenderobject, class KX_GameObject* gameobj, class SCA_LogicManager* logicmgr, class KX_Scene* kxscene, + class KX_KetsjiEngine* kxengine, class SCA_IInputDevice* keydev, int & executePriority , int activeLayerBitInfo, diff --git a/source/gameengine/Converter/Makefile b/source/gameengine/Converter/Makefile index f312fc13221..4dd63e428bd 100644 --- a/source/gameengine/Converter/Makefile +++ b/source/gameengine/Converter/Makefile @@ -51,6 +51,7 @@ CPPFLAGS += -I../../blender/include CPPFLAGS += -I../../blender/blenlib CPPFLAGS += -I../../blender/blenkernel CPPFLAGS += -I../../blender/render/extern/include +CPPFLAGS += -I../../blender/gpu CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I../Expressions -I../Rasterizer -I../GameLogic CPPFLAGS += -I../Ketsji -I../BlenderRoutines -I../SceneGraph diff --git a/source/gameengine/Converter/SConscript b/source/gameengine/Converter/SConscript index f5e382b471e..3be352c568b 100644 --- a/source/gameengine/Converter/SConscript +++ b/source/gameengine/Converter/SConscript @@ -16,7 +16,7 @@ incs += ' #source/gameengine/Expressions #source/gameengine/Network #source/game incs += ' #source/gameengine/Physics/common #source/gameengine/Physics/Bullet #source/gameengine/Physics/BlOde' incs += ' #source/gameengine/Physics/Dummy #source/gameengine/Physics/Sumo' incs += ' #source/gameengine/Physics/Sumo/Fuzzics/include #source/gameengine/Network/LoopBackNetwork' -incs += ' #source/blender/misc #source/blender/blenloader' +incs += ' #source/blender/misc #source/blender/blenloader #source/blender/gpu' incs += ' ' + env['BF_PYTHON_INC'] incs += ' ' + env['BF_SOLID_INC'] diff --git a/source/gameengine/Expressions/Makefile b/source/gameengine/Expressions/Makefile index e9c02eedcf2..6736149bbcd 100644 --- a/source/gameengine/Expressions/Makefile +++ b/source/gameengine/Expressions/Makefile @@ -36,6 +36,7 @@ include nan_compile.mk CCFLAGS += $(LEVEL_1_CPP_WARNINGS) CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) +CPPFLAGS += -I../../blender/makesdna CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index 8937f481922..1eca527151a 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -119,6 +119,7 @@ PyObject *PyObjectPlus::_getattr(const STR_String& attr) int PyObjectPlus::_delattr(const STR_String& attr) { + PyErr_SetString(PyExc_AttributeError, "attribute cant be deleted"); return 1; } @@ -126,7 +127,8 @@ int PyObjectPlus::_setattr(const STR_String& attr, PyObject *value) { //return PyObject::_setattr(attr,value); //cerr << "Unknown attribute" << endl; - return 1; + PyErr_SetString(PyExc_AttributeError, "attribute cant be set"); + return 1; } /*------------------------------ diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index f433a08faba..3a054454a0b 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -43,10 +43,39 @@ * Python defines ------------------------------*/ +/* + Py_RETURN_NONE + Python 2.4 macro. + defined here until we switch to 2.4 + also in api2_2x/gen_utils.h +*/ +#ifndef Py_RETURN_NONE +#define Py_RETURN_NONE return Py_BuildValue("O", Py_None) +#endif +#ifndef Py_RETURN_FALSE +#define Py_RETURN_FALSE return PyBool_FromLong(0) +#endif +#ifndef Py_RETURN_TRUE +#define Py_RETURN_TRUE return PyBool_FromLong(1) +#endif + +/* for pre Py 2.5 */ +#if PY_VERSION_HEX < 0x02050000 +typedef int Py_ssize_t; +#define PY_SSIZE_T_MAX INT_MAX +#define PY_SSIZE_T_MIN INT_MIN +#define PY_METHODCHAR char * +#else +/* Py 2.5 and later */ +#define intargfunc ssizeargfunc +#define intintargfunc ssizessizeargfunc +#define PY_METHODCHAR const char * +#endif + // some basic python macros #define Py_Return { Py_INCREF(Py_None); return Py_None;} -static inline void Py_Fatal(char *M) { +static inline void Py_Fatal(const char *M) { //cout << M << endl; exit(-1); }; @@ -102,6 +131,12 @@ static inline void Py_Fatal(char *M) { return ((class_name*) self)->Py##method_name(self, args, kwds); \ }; \ +#define KX_PYMETHOD_VARARGS(class_name, method_name) \ + PyObject* Py##method_name(PyObject* self, PyObject* args); \ + static PyObject* sPy##method_name( PyObject* self, PyObject* args) { \ + return ((class_name*) self)->Py##method_name(self, args); \ + }; \ + #define KX_PYMETHOD_NOARGS(class_name, method_name) \ PyObject* Py##method_name(PyObject* self); \ static PyObject* sPy##method_name( PyObject* self) { \ @@ -119,28 +154,28 @@ static inline void Py_Fatal(char *M) { static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \ return ((class_name*) self)->Py##method_name(self, args, kwds); \ }; \ - static char method_name##_doc[]; \ + static const char method_name##_doc[]; \ #define KX_PYMETHOD_DOC_VARARGS(class_name, method_name) \ PyObject* Py##method_name(PyObject* self, PyObject* args); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args) { \ return ((class_name*) self)->Py##method_name(self, args); \ }; \ - static char method_name##_doc[]; \ + static const char method_name##_doc[]; \ #define KX_PYMETHOD_DOC_O(class_name, method_name) \ PyObject* Py##method_name(PyObject* self, PyObject* value); \ static PyObject* sPy##method_name( PyObject* self, PyObject* value) { \ return ((class_name*) self)->Py##method_name(self, value); \ }; \ - static char method_name##_doc[]; \ + static const char method_name##_doc[]; \ #define KX_PYMETHOD_DOC_NOARGS(class_name, method_name) \ PyObject* Py##method_name(PyObject* self); \ static PyObject* sPy##method_name( PyObject* self) { \ return ((class_name*) self)->Py##method_name(self); \ }; \ - static char method_name##_doc[]; \ + static const char method_name##_doc[]; \ /* The line above should remain empty */ @@ -148,15 +183,21 @@ static inline void Py_Fatal(char *M) { * Method table macro (with doc) */ #define KX_PYMETHODTABLE(class_name, method_name) \ - {#method_name , (PyCFunction) class_name::sPy##method_name, METH_VARARGS, class_name::method_name##_doc} + {#method_name , (PyCFunction) class_name::sPy##method_name, METH_VARARGS, (PY_METHODCHAR)class_name::method_name##_doc} + +#define KX_PYMETHODTABLE_NOARG(class_name, method_name) \ + {#method_name , (PyCFunction) class_name::sPy##method_name, METH_NOARGS, (PY_METHODCHAR)class_name::method_name##_doc} /** * Function implementation macro */ #define KX_PYMETHODDEF_DOC(class_name, method_name, doc_string) \ -char class_name::method_name##_doc[] = doc_string; \ +const char class_name::method_name##_doc[] = doc_string; \ PyObject* class_name::Py##method_name(PyObject*, PyObject* args, PyObject*) +#define KX_PYMETHODDEF_DOC_NOARG(class_name, method_name, doc_string) \ +const char class_name::method_name##_doc[] = doc_string; \ +PyObject* class_name::Py##method_name(PyObject*) /*------------------------------ * PyObjectPlus diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp index 7bcb45228db..7296dfbec10 100644 --- a/source/gameengine/Expressions/Value.cpp +++ b/source/gameengine/Expressions/Value.cpp @@ -391,16 +391,23 @@ float CValue::GetPropertyNumber(const STR_String& inName,float defnumber) bool CValue::RemoveProperty(const STR_String & inName) { // Check if there are properties at all which can be removed - if (m_pNamedPropertyArray == NULL) - return false; - - CValue* val = GetProperty(inName); - if (NULL != val) - { - val->Release(); - m_pNamedPropertyArray->erase(inName); - return true; - } + if (m_pNamedPropertyArray) { + CValue* val = GetProperty(inName); + if (NULL != val) + { + val->Release(); + m_pNamedPropertyArray->erase(inName); + return true; + } + } + + char err[128]; + if (m_pNamedPropertyArray) + sprintf(err, "attribute \"%s\" dosnt exist", inName.ReadPtr()); + else + sprintf(err, "attribute \"%s\" dosnt exist (no property array)", inName.ReadPtr()); + + PyErr_SetString(PyExc_AttributeError, err); return false; } @@ -755,7 +762,8 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj) int CValue::_delattr(const STR_String& attr) { - RemoveProperty(attr); + if (!RemoveProperty(attr)) /* sets error */ + return 1; return 0; } diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp index 18d7b6ffcd0..092956e6489 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp @@ -29,9 +29,9 @@ #include "SCA_Joystick.h" #include "SCA_JoystickPrivate.h" - -SCA_Joystick::SCA_Joystick() +SCA_Joystick::SCA_Joystick(short int index) : + m_joyindex(index), m_axis10(0), m_axis11(0), m_axis20(0), @@ -42,92 +42,74 @@ SCA_Joystick::SCA_Joystick() m_isinit(0), m_istrig(0) { +#ifndef DISABLE_SDL m_private = new PrivateData(); +#endif } SCA_Joystick::~SCA_Joystick() { +#ifndef DISABLE_SDL delete m_private; +#endif } -SCA_Joystick *SCA_Joystick::m_instance = NULL; +SCA_Joystick *SCA_Joystick::m_instance[JOYINDEX_MAX]; int SCA_Joystick::m_refCount = 0; -SCA_Joystick *SCA_Joystick::GetInstance() +SCA_Joystick *SCA_Joystick::GetInstance( short int joyindex ) { - if (m_instance == 0) +#ifdef DISABLE_SDL + return NULL; +#else + if (joyindex < 0 || joyindex >= JOYINDEX_MAX) { + echo("Error-invalid joystick index: " << joyindex); + return NULL; + } + + if (m_refCount == 0) { - m_instance = new SCA_Joystick(); - m_instance->CreateJoystickDevice(); + int i; + // do this once only + if(SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO ) == -1 ){ + echo("Error-Initializing-SDL: " << SDL_GetError()); + return NULL; + } + for (i=0; i<JOYINDEX_MAX; i++) { + m_instance[i] = new SCA_Joystick(i); + m_instance[i]->CreateJoystickDevice(); + } m_refCount = 1; } else { m_refCount++; } - return m_instance; + return m_instance[joyindex]; +#endif } void SCA_Joystick::ReleaseInstance() { if (--m_refCount == 0) { - DestroyJoystickDevice(); - delete m_instance; - m_instance = NULL; - } -} - - -bool SCA_Joystick::CreateJoystickDevice() -{ - bool init = false; - init = pCreateJoystickDevice(); - return init; -} - - -void SCA_Joystick::DestroyJoystickDevice() -{ - if(m_isinit) - pDestroyJoystickDevice(); -} - - -void SCA_Joystick::HandleEvents() -{ - if(m_isinit) - { - if(SDL_PollEvent(&m_private->m_event)) - { - switch(m_private->m_event.type) - { - case SDL_JOYAXISMOTION: - HANDLE_AXISMOTION(OnAxisMotion); - break; - case SDL_JOYHATMOTION: - HANDLE_HATMOTION(OnHatMotion); - break; - case SDL_JOYBUTTONUP: - HANDLE_BUTTONUP(OnButtonUp); - break; - case SDL_JOYBUTTONDOWN: - HANDLE_BUTTONDOWN(OnButtonDown); - break; - case SDL_JOYBALLMOTION: - HANDLE_BALLMOTION(OnBallMotion); - break; - default: - HANDLE_NOEVENT(OnNothing); - break; +#ifndef DISABLE_SDL + int i; + for (i=0; i<JOYINDEX_MAX; i++) { + if (m_instance[i]) { + m_instance[i]->DestroyJoystickDevice(); + delete m_instance[i]; } + m_instance[i]= NULL; } + + SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO ); +#endif } } - void SCA_Joystick::cSetPrecision(int val) { m_prec = val; @@ -176,19 +158,27 @@ bool SCA_Joystick::aDownAxisIsPositive(int axis) bool SCA_Joystick::aButtonPressIsPositive(int button) { +#ifdef DISABLE_SDL + return false; +#else bool result; SDL_JoystickGetButton(m_private->m_joystick, button)? result = true:result = false; m_istrig = result; return result; +#endif } bool SCA_Joystick::aButtonReleaseIsPositive(int button) { +#ifdef DISABLE_SDL + return false; +#else bool result; SDL_JoystickGetButton(m_private->m_joystick, button)? result = false : result = true; m_istrig = result; return result; +#endif } @@ -226,78 +216,11 @@ int SCA_Joystick::pGetHat(int direction) return 0; } - -bool SCA_Joystick::GetJoyAxisMotion() -{ - bool result = false; - if(m_isinit){ - if(SDL_PollEvent(&m_private->m_event)){ - switch(m_private->m_event.type) - { - case SDL_JOYAXISMOTION: - result = true; - break; - } - } - } - return result; -} - - -bool SCA_Joystick::GetJoyButtonPress() -{ - bool result = false; - if(m_isinit){ - if(SDL_PollEvent(&m_private->m_event)){ - switch(m_private->m_event.type) - { - case SDL_JOYBUTTONDOWN: - result = true; - break; - } - } - } - return result; -} - - -bool SCA_Joystick::GetJoyButtonRelease() -{ - bool result = false; - if(m_isinit) - { - if(SDL_PollEvent(&m_private->m_event)){ - switch(m_private->m_event.type) - { - case SDL_JOYBUTTONUP: - result = true; - break; - } - } - } - return result; -} - - -bool SCA_Joystick::GetJoyHatMotion() -{ - bool result = false; - if(m_isinit){ - if(SDL_PollEvent(&m_private->m_event)){ - switch(m_private->m_event.type) - { - case SDL_JOYHATMOTION: - result = true; - break; - } - } - } - return 0; -} - - int SCA_Joystick::GetNumberOfAxes() { +#ifdef DISABLE_SDL + return -1; +#else int number; if(m_isinit){ if(m_private->m_joystick){ @@ -306,11 +229,15 @@ int SCA_Joystick::GetNumberOfAxes() } } return -1; +#endif } int SCA_Joystick::GetNumberOfButtons() { +#ifdef DISABLE_SDL + return -1; +#else int number; if(m_isinit){ if(m_private->m_joystick){ @@ -319,11 +246,15 @@ int SCA_Joystick::GetNumberOfButtons() } } return -1; +#endif } int SCA_Joystick::GetNumberOfHats() { +#ifdef DISABLE_SDL + return -1; +#else int number; if(m_isinit){ if(m_private->m_joystick){ @@ -332,47 +263,57 @@ int SCA_Joystick::GetNumberOfHats() } } return -1; +#endif } -bool SCA_Joystick::pCreateJoystickDevice() +bool SCA_Joystick::CreateJoystickDevice(void) { +#ifdef DISABLE_SDL + return false; +#else if(m_isinit == false){ - if(SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO ) == -1 ){ - echo("Error-Initializing-SDL: " << SDL_GetError()); - return false; - } - if(SDL_NumJoysticks() > 0){ - for(int i=0; i<SDL_NumJoysticks();i++){ - m_private->m_joystick = SDL_JoystickOpen(i); - SDL_JoystickEventState(SDL_ENABLE); - m_numjoys = i; - } - echo("Joystick-initialized"); - m_isinit = true; - return true; - }else{ - echo("Joystick-Error: " << SDL_NumJoysticks() << " avaiable joystick(s)"); + if (m_joyindex>=SDL_NumJoysticks()) { + // don't print a message, because this is done anyway + //echo("Joystick-Error: " << SDL_NumJoysticks() << " avaiable joystick(s)"); return false; } + + m_private->m_joystick = SDL_JoystickOpen(m_joyindex); + SDL_JoystickEventState(SDL_ENABLE); + + echo("Joystick " << m_joyindex << " initialized"); + m_isinit = true; } - return false; + return true; +#endif } -void SCA_Joystick::pDestroyJoystickDevice() +void SCA_Joystick::DestroyJoystickDevice(void) { - echo("Closing-"); - for(int i=0; i<SDL_NumJoysticks(); i++){ - if(SDL_JoystickOpened(i)){ +#ifndef DISABLE_SDL + if (m_isinit){ + if(SDL_JoystickOpened(m_joyindex)){ + echo("Closing-joystick " << m_joyindex); SDL_JoystickClose(m_private->m_joystick); } + m_isinit = false; } - SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO ); +#endif } +int SCA_Joystick::Connected(void) +{ +#ifndef DISABLE_SDL + if (m_isinit && SDL_JoystickOpened(m_joyindex)) + return 1; +#endif + return 0; +} void SCA_Joystick::pFillAxes() { +#ifndef DISABLE_SDL if(GetNumberOfAxes() == 1){ m_axis10 = SDL_JoystickGetAxis(m_private->m_joystick, 0); m_axis11 = SDL_JoystickGetAxis(m_private->m_joystick, 1); @@ -382,18 +323,20 @@ void SCA_Joystick::pFillAxes() m_axis20 = SDL_JoystickGetAxis(m_private->m_joystick, 2); m_axis21 = SDL_JoystickGetAxis(m_private->m_joystick, 3); }else{ - m_axis10 = 0;m_axis11 = 0; - m_axis20 = 0;m_axis21 = 0; + m_axis10 = m_axis11 = m_axis20 = m_axis21 = 0; } +#endif } int SCA_Joystick::pGetAxis(int axisnum, int udlr) { +#ifndef DISABLE_SDL if(axisnum == 1 && udlr == 1)return m_axis10; //u/d if(axisnum == 1 && udlr == 0)return m_axis11; //l/r if(axisnum == 2 && udlr == 0)return m_axis20; //... if(axisnum == 2 && udlr == 1)return m_axis21; +#endif return 0; } diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.h b/source/gameengine/GameLogic/Joystick/SCA_Joystick.h index 1e853070b09..ea7ecf7cefe 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.h +++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.h @@ -1,72 +1,37 @@ /** - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - - - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): snailrose. - * - * ***** END GPL LICENSE BLOCK ***** - */ #ifndef _SCA_JOYSTICK_H_ - #define _SCA_JOYSTICK_H_ - - #include "SCA_JoystickDefines.h" - - - - +#include "SDL.h" /* - * Basic Joystick class * I will make this class a singleton because there should be only one joystick * even if there are more than one scene using it and count how many scene are using it. @@ -76,235 +41,145 @@ class SCA_Joystick { - static SCA_Joystick *m_instance; + static SCA_Joystick *m_instance[JOYINDEX_MAX]; static int m_refCount; class PrivateData; - +#ifndef DISABLE_SDL PrivateData *m_private; - +#endif int m_joyindex; - /*! - - * the number of avail joysticks - - */ - - int m_numjoys; - /* - *support for 2 axes - */ int m_axis10,m_axis11; - int m_axis20,m_axis21; - /* - + /* * Precision or range of the axes - */ - int m_prec; /* - * multiple axis values stored here - */ - int m_axisnum; - int m_axisvalue; /* - * max # of axes avail - */ - /*disabled - int m_axismax; - */ /* - * button values stored here - */ - int m_buttonnum; /* - * max # of buttons avail - */ int m_buttonmax; - /* - * hat values stored here - */ - int m_hatnum; - int m_hatdir; /* * max # of hats avail - disabled - int m_hatmax; - */ - /* is the joystick initialized ?*/ - bool m_isinit; - /* is triggered */ - bool m_istrig; +#ifndef DISABLE_SDL /* - - * Open the joystick - + * event callbacks */ - - bool pCreateJoystickDevice(void); - + void OnAxisMotion(SDL_Event *sdl_event); + void OnHatMotion(SDL_Event *sdl_event); + void OnButtonUp(SDL_Event *sdl_event); + void OnButtonDown(SDL_Event *sdl_event); + void OnNothing(SDL_Event *sdl_event); + void OnBallMotion(SDL_Event *sdl_event){} +#endif /* - - * Close the joystick - + * Open the joystick */ - - void pDestroyJoystickDevice(void); - - + bool CreateJoystickDevice(void); /* - - * event callbacks - + * Close the joystick */ - - void OnAxisMotion(void); - - void OnHatMotion(void); - - void OnButtonUp(void); - - void OnButtonDown(void); - - void OnNothing(void); - - void OnBallMotion(void){} + void DestroyJoystickDevice(void); /* - * fills the axis mnember values - */ - void pFillAxes(void); - - - void pFillButtons(void); /* - * returns m_axis10,m_axis11... - */ - int pGetAxis(int axisnum, int udlr); - + /* - * gets the current button - */ int pGetButtonPress(int button); /* - * returns if no button is pressed - */ - int pGetButtonRelease(int button); /* - * gets the current hat direction - */ - int pGetHat(int direction); - SCA_Joystick(); + SCA_Joystick(short int index); ~SCA_Joystick(); - bool CreateJoystickDevice(void); - - void DestroyJoystickDevice(void); - - public: - static SCA_Joystick *GetInstance(); - + static SCA_Joystick *GetInstance( short int joyindex ); + static void HandleEvents( void ); void ReleaseInstance(); - void HandleEvents(); - /* - */ bool aUpAxisIsPositive(int axis); - bool aDownAxisIsPositive(int axis); - bool aLeftAxisIsPositive(int axis); - bool aRightAxisIsPositive(int axis); - bool aButtonPressIsPositive(int button); - bool aButtonReleaseIsPositive(int button); - bool aHatIsPositive(int dir); /* - * precision is default '3200' which is overridden by input - */ void cSetPrecision(int val); - - int GetAxis10(void){ return m_axis10; @@ -312,80 +187,49 @@ public: } int GetAxis11(void){ - return m_axis11; - } int GetAxis20(void){ - return m_axis20; - } int GetAxis21(void){ - return m_axis21; - } int GetButton(void){ - return m_buttonnum; - } int GetHat(void){ - return m_hatdir; - } int GetThreshold(void){ - return m_prec; - } bool IsTrig(void){ - return m_istrig; - } - - - /* - - * returns true if an event is being processed - - */ - - bool GetJoyAxisMotion(void); - - bool GetJoyButtonPress(void); - - bool GetJoyButtonRelease(void); - - bool GetJoyHatMotion(void); - /* - * returns the # of... - */ int GetNumberOfAxes(void); - int GetNumberOfButtons(void); - int GetNumberOfHats(void); - - + /* + * Test if the joystick is connected + */ + int Connected(void); }; - - +#ifndef DISABLE_SDL +void Joystick_HandleEvents( void ); +#endif #endif diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h b/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h index 15a421188b9..73ffe1406d9 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h +++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h @@ -38,12 +38,6 @@ #define echo(x) std::cout << x << std::endl; #endif -/* function callbacks */ -#define HANDLE_AXISMOTION(fn) ((fn)(), 0L) -#define HANDLE_HATMOTION(fn) ((fn)(), 0L) -#define HANDLE_BUTTONUP(fn) ((fn)(), 0L) -#define HANDLE_BUTTONDOWN(fn) ((fn)(), 0L) -#define HANDLE_BALLMOTION(fn) ((fn)(), 0L) -#define HANDLE_NOEVENT(fn) ((fn)(), 0L) +#define JOYINDEX_MAX 8 #endif diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp index ab523470e21..0e2078265c9 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp @@ -29,42 +29,77 @@ #include "SCA_JoystickPrivate.h" - -void SCA_Joystick::OnAxisMotion(void) +#ifndef DISABLE_SDL +void SCA_Joystick::OnAxisMotion(SDL_Event* sdl_event) { pFillAxes(); - m_axisnum = m_private->m_event.jaxis.axis; - m_axisvalue = m_private->m_event.jaxis.value; + m_axisnum = sdl_event->jaxis.axis; + m_axisvalue = sdl_event->jaxis.value; m_istrig = 1; } -void SCA_Joystick::OnHatMotion(void) +void SCA_Joystick::OnHatMotion(SDL_Event* sdl_event) { - m_hatdir = m_private->m_event.jhat.value; - m_hatnum = m_private->m_event.jhat.hat; + m_hatdir = sdl_event->jhat.value; + m_hatnum = sdl_event->jhat.hat; m_istrig = 1; } -void SCA_Joystick::OnButtonUp(void) +void SCA_Joystick::OnButtonUp(SDL_Event* sdl_event) { m_buttonnum = -2; } -void SCA_Joystick::OnButtonDown(void) +void SCA_Joystick::OnButtonDown(SDL_Event* sdl_event) { m_buttonmax = GetNumberOfButtons(); - if(m_private->m_event.jbutton.button >= 1 || m_private->m_event.jbutton.button <= m_buttonmax) + if(sdl_event->jbutton.button >= 1 || sdl_event->jbutton.button <= m_buttonmax) { m_istrig = 1; - m_buttonnum = m_private->m_event.jbutton.button; + m_buttonnum = sdl_event->jbutton.button; } } -void SCA_Joystick::OnNothing(void) +void SCA_Joystick::OnNothing(SDL_Event* sdl_event) { m_istrig = 0; } + +/* only handle events for 1 joystick */ + +void SCA_Joystick::HandleEvents(void) +{ + SDL_Event sdl_event; + + if(SDL_PollEvent(&sdl_event)) + { + /* Note! m_instance[sdl_event.jaxis.which] + * will segfault if over JOYINDEX_MAX, not too nice but what are the chances? */ + switch(sdl_event.type) + { + case SDL_JOYAXISMOTION: + SCA_Joystick::m_instance[sdl_event.jaxis.which]->OnAxisMotion(&sdl_event); + break; + case SDL_JOYHATMOTION: + SCA_Joystick::m_instance[sdl_event.jhat.which]->OnHatMotion(&sdl_event); + break; + case SDL_JOYBUTTONUP: + SCA_Joystick::m_instance[sdl_event.jbutton.which]->OnButtonUp(&sdl_event); + break; + case SDL_JOYBUTTONDOWN: + SCA_Joystick::m_instance[sdl_event.jbutton.which]->OnButtonDown(&sdl_event); + break; + case SDL_JOYBALLMOTION: + SCA_Joystick::m_instance[sdl_event.jball.which]->OnBallMotion(&sdl_event); + break; + default: + printf("SCA_Joystick::HandleEvents, Unknown SDL event, this should not happen\n"); + break; + } + } +} +#endif diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickPrivate.h b/source/gameengine/GameLogic/Joystick/SCA_JoystickPrivate.h index 23fad3cd55d..acbbcae9cd7 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickPrivate.h +++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickPrivate.h @@ -29,14 +29,11 @@ #define __SCA_JOYSTICKPRIVATE_H__ #include "SCA_Joystick.h" +#ifndef DISABLE_SDL class SCA_Joystick::PrivateData { public: /* - * SDL events structure - */ - SDL_Event m_event; - /* * The Joystick */ SDL_Joystick* m_joystick; @@ -47,3 +44,5 @@ public: } }; #endif + +#endif diff --git a/source/gameengine/GameLogic/Makefile b/source/gameengine/GameLogic/Makefile index b3eae5d67dc..355ece6e8bd 100644 --- a/source/gameengine/GameLogic/Makefile +++ b/source/gameengine/GameLogic/Makefile @@ -42,6 +42,7 @@ CPPFLAGS += -I../Expressions CPPFLAGS += -I../Rasterizer CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../../blender/makesdna CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) CPPFLAGS += $(NAN_SDLCFLAGS) diff --git a/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp b/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp index 96a770a553f..9ec4ea00337 100644 --- a/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp +++ b/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp @@ -23,8 +23,8 @@ SCA_2DFilterActuator::SCA_2DFilterActuator( : SCA_IActuator(gameobj, T), m_type(type), m_flag(flag), - m_int_arg(int_arg), m_float_arg(float_arg), + m_int_arg(int_arg), m_rasterizer(rasterizer), m_rendertools(rendertools) { @@ -64,13 +64,11 @@ bool SCA_2DFilterActuator::Update() if( m_type == RAS_2DFilterManager::RAS_2DFILTER_MOTIONBLUR ) { if(!m_flag) - { m_rasterizer->EnableMotionBlur(m_float_arg); - } else - { m_rasterizer->DisableMotionBlur(); - } + + return false; } else if(m_type < RAS_2DFilterManager::RAS_2DFILTER_NUMBER_OF_FILTERS) { diff --git a/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp b/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp index 6501a3173a7..6d6a059207b 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp +++ b/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp @@ -149,8 +149,8 @@ PyParentObject SCA_ActuatorSensor::Parents[] = { }; PyMethodDef SCA_ActuatorSensor::Methods[] = { - {"getActuator", (PyCFunction) SCA_ActuatorSensor::sPyGetActuator, METH_NOARGS, GetActuator_doc}, - {"setActuator", (PyCFunction) SCA_ActuatorSensor::sPySetActuator, METH_VARARGS, SetActuator_doc}, + {"getActuator", (PyCFunction) SCA_ActuatorSensor::sPyGetActuator, METH_NOARGS, (PY_METHODCHAR)GetActuator_doc}, + {"setActuator", (PyCFunction) SCA_ActuatorSensor::sPySetActuator, METH_VARARGS, (PY_METHODCHAR)SetActuator_doc}, {NULL,NULL} //Sentinel }; @@ -159,7 +159,7 @@ PyObject* SCA_ActuatorSensor::_getattr(const STR_String& attr) { } /* 3. getActuator */ -char SCA_ActuatorSensor::GetActuator_doc[] = +const char SCA_ActuatorSensor::GetActuator_doc[] = "getActuator()\n" "\tReturn the Actuator with which the sensor operates.\n"; PyObject* SCA_ActuatorSensor::PyGetActuator(PyObject* self) @@ -168,7 +168,7 @@ PyObject* SCA_ActuatorSensor::PyGetActuator(PyObject* self) } /* 4. setActuator */ -char SCA_ActuatorSensor::SetActuator_doc[] = +const char SCA_ActuatorSensor::SetActuator_doc[] = "setActuator(name)\n" "\t- name: string\n" "\tSets the Actuator with which to operate. If there is no Actuator\n" diff --git a/source/gameengine/GameLogic/SCA_DelaySensor.cpp b/source/gameengine/GameLogic/SCA_DelaySensor.cpp new file mode 100644 index 00000000000..f15d4c7249f --- /dev/null +++ b/source/gameengine/GameLogic/SCA_DelaySensor.cpp @@ -0,0 +1,257 @@ +/** + * Delay trigger + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef WIN32 +// This warning tells us about truncation of __long__ stl-generated names. +// It can occasionally cause DevStudio to have internal compiler warnings. +#pragma warning( disable : 4786 ) +#endif + +#include "SCA_DelaySensor.h" +#include "SCA_LogicManager.h" +#include "SCA_EventManager.h" + +/* ------------------------------------------------------------------------- */ +/* Native functions */ +/* ------------------------------------------------------------------------- */ + +SCA_DelaySensor::SCA_DelaySensor(class SCA_EventManager* eventmgr, + SCA_IObject* gameobj, + int delay, + int duration, + bool repeat, + PyTypeObject* T) + : SCA_ISensor(gameobj,eventmgr, T), + m_delay(delay), + m_duration(duration), + m_repeat(repeat) +{ + Init(); +} + +void SCA_DelaySensor::Init() +{ + m_lastResult = false; + m_frameCount = -1; + m_reset = true; +} + +SCA_DelaySensor::~SCA_DelaySensor() +{ + /* intentionally empty */ +} + +CValue* SCA_DelaySensor::GetReplica() +{ + CValue* replica = new SCA_DelaySensor(*this); + // this will copy properties and so on... + CValue::AddDataToReplica(replica); + + return replica; +} + + + +bool SCA_DelaySensor::IsPositiveTrigger() +{ + return (m_invert ? !m_lastResult : m_lastResult); +} + +bool SCA_DelaySensor::Evaluate(CValue* event) +{ + bool trigger = false; + bool result; + + if (m_frameCount==-1) { + // this is needed to ensure ON trigger in case delay==0 + // and avoid spurious OFF trigger when duration==0 + m_lastResult = false; + m_frameCount = 0; + } + + if (m_frameCount<m_delay) { + m_frameCount++; + result = false; + } else if (m_duration > 0) { + if (m_frameCount < m_delay+m_duration) { + m_frameCount++; + result = true; + } else { + result = false; + if (m_repeat) + m_frameCount = -1; + } + } else { + result = true; + if (m_repeat) + m_frameCount = -1; + } + if ((m_reset && m_level) || result != m_lastResult) + trigger = true; + m_reset = false; + m_lastResult = result; + return trigger; +} + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ + +/* Integration hooks ------------------------------------------------------- */ +PyTypeObject SCA_DelaySensor::Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "SCA_DelaySensor", + sizeof(SCA_DelaySensor), + 0, + PyDestructor, + 0, + __getattr, + __setattr, + 0, //&MyPyCompare, + __repr, + 0, //&cvalue_as_number, + 0, + 0, + 0, + 0 +}; + +PyParentObject SCA_DelaySensor::Parents[] = { + &SCA_DelaySensor::Type, + &SCA_ISensor::Type, + &SCA_ILogicBrick::Type, + &CValue::Type, + NULL +}; + +PyMethodDef SCA_DelaySensor::Methods[] = { + /* setProperty */ + {"setDelay", (PyCFunction) SCA_DelaySensor::sPySetDelay, METH_VARARGS, (PY_METHODCHAR)SetDelay_doc}, + {"setDuration", (PyCFunction) SCA_DelaySensor::sPySetDuration, METH_VARARGS, (PY_METHODCHAR)SetDuration_doc}, + {"setRepeat", (PyCFunction) SCA_DelaySensor::sPySetRepeat, METH_VARARGS, (PY_METHODCHAR)SetRepeat_doc}, + /* getProperty */ + {"getDelay", (PyCFunction) SCA_DelaySensor::sPyGetDelay, METH_NOARGS, (PY_METHODCHAR)GetDelay_doc}, + {"getDuration", (PyCFunction) SCA_DelaySensor::sPyGetDuration, METH_NOARGS, (PY_METHODCHAR)GetDuration_doc}, + {"getRepeat", (PyCFunction) SCA_DelaySensor::sPyGetRepeat, METH_NOARGS, (PY_METHODCHAR)GetRepeat_doc}, + {NULL,NULL} //Sentinel +}; + +PyObject* SCA_DelaySensor::_getattr(const STR_String& attr) { + _getattr_up(SCA_ISensor); +} + +const char SCA_DelaySensor::SetDelay_doc[] = +"setDelay(delay)\n" +"\t- delay: length of the initial OFF period as number of frame\n" +"\t 0 for immediate trigger\n" +"\tSet the initial delay before the positive trigger\n"; +PyObject* SCA_DelaySensor::PySetDelay(PyObject* self, PyObject* args, PyObject* kwds) +{ + int delay; + + if(!PyArg_ParseTuple(args, "i", &delay)) { + return NULL; + } + if (delay < 0) { + PyErr_SetString(PyExc_ValueError, "Delay cannot be negative"); + return NULL; + } + m_delay = delay; + Py_Return; +} + +const char SCA_DelaySensor::SetDuration_doc[] = +"setDuration(duration)\n" +"\t- duration: length of the ON period in number of frame after the initial off period\n" +"\t 0 for no ON period\n" +"\tSet the duration of the ON pulse after initial delay.\n" +"\tIf > 0, a negative trigger is fired at the end of the ON pulse.\n"; +PyObject* SCA_DelaySensor::PySetDuration(PyObject* self, PyObject* args, PyObject* kwds) +{ + int duration; + + if(!PyArg_ParseTuple(args, "i", &duration)) { + return NULL; + } + if (duration < 0) { + PyErr_SetString(PyExc_ValueError, "Duration cannot be negative"); + return NULL; + } + m_duration = duration; + Py_Return; +} + +const char SCA_DelaySensor::SetRepeat_doc[] = +"setRepeat(repeat)\n" +"\t- repeat: 1 if the initial OFF-ON cycle should be repeated indefinately\n" +"\t 0 if the initial OFF-ON cycle should run only once\n" +"\tSet the sensor repeat mode\n"; +PyObject* SCA_DelaySensor::PySetRepeat(PyObject* self, PyObject* args, PyObject* kwds) +{ + int repeat; + + if(!PyArg_ParseTuple(args, "i", &repeat)) { + return NULL; + } + m_repeat = (repeat != 0); + Py_Return; +} + +const char SCA_DelaySensor::GetDelay_doc[] = +"getDelay()\n" +"\tReturn the delay parameter value\n"; +PyObject* SCA_DelaySensor::PyGetDelay(PyObject* self) +{ + return PyInt_FromLong(m_delay); +} + +const char SCA_DelaySensor::GetDuration_doc[] = +"getDuration()\n" +"\tReturn the duration parameter value\n"; +PyObject* SCA_DelaySensor::PyGetDuration(PyObject* self) +{ + return PyInt_FromLong(m_duration); +} + +const char SCA_DelaySensor::GetRepeat_doc[] = +"getRepeat()\n" +"\tReturn the repeat parameter value\n"; +PyObject* SCA_DelaySensor::PyGetRepeat(PyObject* self) +{ + return BoolToPyArg(m_repeat); +} + +/* eof */ diff --git a/source/gameengine/GameLogic/SCA_DelaySensor.h b/source/gameengine/GameLogic/SCA_DelaySensor.h new file mode 100644 index 00000000000..a997fabe3cd --- /dev/null +++ b/source/gameengine/GameLogic/SCA_DelaySensor.h @@ -0,0 +1,77 @@ +/** + * SCA_DelaySensor.h + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __KX_DELAYSENSOR +#define __KX_DELAYSENSOR +#include "SCA_ISensor.h" + +class SCA_DelaySensor : public SCA_ISensor +{ + Py_Header; + bool m_lastResult; + bool m_repeat; + int m_delay; + int m_duration; + int m_frameCount; + +public: + SCA_DelaySensor(class SCA_EventManager* eventmgr, + SCA_IObject* gameobj, + int delay, + int duration, + bool repeat, + PyTypeObject* T =&Type); + virtual ~SCA_DelaySensor(); + virtual CValue* GetReplica(); + virtual bool Evaluate(CValue* event); + virtual bool IsPositiveTrigger(); + virtual void Init(); + + + /* --------------------------------------------------------------------- */ + /* Python interface ---------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + + virtual PyObject* _getattr(const STR_String& attr); + + /* setProperty */ + KX_PYMETHOD_DOC(SCA_DelaySensor,SetDelay); + KX_PYMETHOD_DOC(SCA_DelaySensor,SetDuration); + KX_PYMETHOD_DOC(SCA_DelaySensor,SetRepeat); + /* getProperty */ + KX_PYMETHOD_DOC_NOARGS(SCA_DelaySensor,GetDelay); + KX_PYMETHOD_DOC_NOARGS(SCA_DelaySensor,GetDuration); + KX_PYMETHOD_DOC_NOARGS(SCA_DelaySensor,GetRepeat); + +}; + +#endif //__KX_ALWAYSSENSOR + diff --git a/source/gameengine/GameLogic/SCA_IController.cpp b/source/gameengine/GameLogic/SCA_IController.cpp index 8f156cc63e7..0bd20117f31 100644 --- a/source/gameengine/GameLogic/SCA_IController.cpp +++ b/source/gameengine/GameLogic/SCA_IController.cpp @@ -188,6 +188,8 @@ void SCA_IController::ApplyState(unsigned int state) for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) { (*sensit)->IncLink(); + // remember that this controller just activated that sensor + (*sensit)->AddNewController(this); } SetActive(true); } diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp index f5512664d8f..abd049e9d64 100644 --- a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp +++ b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp @@ -27,6 +27,7 @@ */ #include "SCA_ILogicBrick.h" +#include "PyObjectPlus.h" #ifdef HAVE_CONFIG_H #include <config.h> diff --git a/source/gameengine/GameLogic/SCA_ISensor.cpp b/source/gameengine/GameLogic/SCA_ISensor.cpp index 2dc49924062..b10ac676464 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.cpp +++ b/source/gameengine/GameLogic/SCA_ISensor.cpp @@ -32,6 +32,8 @@ #include "SCA_ISensor.h" #include "SCA_EventManager.h" #include "SCA_LogicManager.h" +// needed for IsTriggered() +#include "SCA_PythonController.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -132,10 +134,8 @@ void SCA_ISensor::DecLink() { } if (!m_links) { - // sensor is detached from all controllers, initialize it so that it - // is fresh as at startup when it is reattached again. + // sensor is detached from all controllers, remove it from manager UnregisterToManager(); - Init(); } } @@ -168,27 +168,31 @@ PyParentObject SCA_ISensor::Parents[] = { }; PyMethodDef SCA_ISensor::Methods[] = { {"isPositive", (PyCFunction) SCA_ISensor::sPyIsPositive, - METH_VARARGS, IsPositive_doc}, + METH_NOARGS, (PY_METHODCHAR)IsPositive_doc}, + {"isTriggered", (PyCFunction) SCA_ISensor::sPyIsTriggered, + METH_VARARGS, (PY_METHODCHAR)IsTriggered_doc}, {"getUsePosPulseMode", (PyCFunction) SCA_ISensor::sPyGetUsePosPulseMode, - METH_NOARGS, GetUsePosPulseMode_doc}, + METH_NOARGS, (PY_METHODCHAR)GetUsePosPulseMode_doc}, {"setUsePosPulseMode", (PyCFunction) SCA_ISensor::sPySetUsePosPulseMode, - METH_VARARGS, SetUsePosPulseMode_doc}, + METH_VARARGS, (PY_METHODCHAR)SetUsePosPulseMode_doc}, {"getFrequency", (PyCFunction) SCA_ISensor::sPyGetFrequency, - METH_NOARGS, GetFrequency_doc}, + METH_NOARGS, (PY_METHODCHAR)GetFrequency_doc}, {"setFrequency", (PyCFunction) SCA_ISensor::sPySetFrequency, - METH_VARARGS, SetFrequency_doc}, + METH_VARARGS, (PY_METHODCHAR)SetFrequency_doc}, {"getUseNegPulseMode", (PyCFunction) SCA_ISensor::sPyGetUseNegPulseMode, - METH_NOARGS, GetUseNegPulseMode_doc}, + METH_NOARGS, (PY_METHODCHAR)GetUseNegPulseMode_doc}, {"setUseNegPulseMode", (PyCFunction) SCA_ISensor::sPySetUseNegPulseMode, - METH_VARARGS, SetUseNegPulseMode_doc}, + METH_VARARGS, (PY_METHODCHAR)SetUseNegPulseMode_doc}, {"getInvert", (PyCFunction) SCA_ISensor::sPyGetInvert, - METH_NOARGS, GetInvert_doc}, + METH_NOARGS, (PY_METHODCHAR)GetInvert_doc}, {"setInvert", (PyCFunction) SCA_ISensor::sPySetInvert, - METH_VARARGS, SetInvert_doc}, + METH_VARARGS, (PY_METHODCHAR)SetInvert_doc}, {"getLevel", (PyCFunction) SCA_ISensor::sPyGetLevel, - METH_NOARGS, GetLevel_doc}, + METH_NOARGS, (PY_METHODCHAR)GetLevel_doc}, {"setLevel", (PyCFunction) SCA_ISensor::sPySetLevel, - METH_VARARGS, SetLevel_doc}, + METH_VARARGS, (PY_METHODCHAR)SetLevel_doc}, + {"reset", (PyCFunction) SCA_ISensor::sPyReset, + METH_NOARGS, (PY_METHODCHAR)Reset_doc}, {NULL,NULL} //Sentinel }; @@ -202,6 +206,9 @@ SCA_ISensor::_getattr(const STR_String& attr) void SCA_ISensor::RegisterToManager() { + // sensor is just activated, initialize it + Init(); + m_newControllers.erase(m_newControllers.begin(), m_newControllers.end()); m_eventmgr->RegisterSensor(this); } @@ -219,6 +226,9 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr, CValue* event) bool result = this->Evaluate(event); if (result) { logicmgr->AddActivatedSensor(this); + // reset these counters so that pulse are synchronized with transition + m_pos_ticks = 0; + m_neg_ticks = 0; } else { /* First, the pulsing behaviour, if pulse mode is @@ -247,23 +257,51 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr, CValue* event) } } } + if (!m_newControllers.empty()) + { + if (!IsActive() && m_level) + { + // This level sensor is connected to at least one controller that was just made + // active but it did not generate an event yet, do it now to those controllers only + for (std::vector<SCA_IController*>::iterator ci=m_newControllers.begin(); + ci != m_newControllers.end(); ci++) + { + logicmgr->AddTriggeredController(*ci, this); + } + } + // clear the list. Instead of using clear, which also release the memory, + // use erase, which keeps the memory available for next time. + m_newControllers.erase(m_newControllers.begin(), m_newControllers.end()); + } } } /* Python functions: */ -char SCA_ISensor::IsPositive_doc[] = +const char SCA_ISensor::IsPositive_doc[] = "isPositive()\n" -"\tReturns whether the sensor is registered a positive event.\n"; -PyObject* SCA_ISensor::PyIsPositive(PyObject* self, PyObject* args, PyObject* kwds) +"\tReturns whether the sensor is in an active state.\n"; +PyObject* SCA_ISensor::PyIsPositive(PyObject* self) { int retval = IsPositiveTrigger(); return PyInt_FromLong(retval); } +const char SCA_ISensor::IsTriggered_doc[] = +"isTriggered()\n" +"\tReturns whether the sensor has triggered the current controller.\n"; +PyObject* SCA_ISensor::PyIsTriggered(PyObject* self) +{ + // check with the current controller + int retval = 0; + if (SCA_PythonController::m_sCurrentController) + retval = SCA_PythonController::m_sCurrentController->IsTriggered(this); + return PyInt_FromLong(retval); +} + /** * getUsePulseMode: getter for the pulse mode (KX_TRUE = on) */ -char SCA_ISensor::GetUsePosPulseMode_doc[] = +const char SCA_ISensor::GetUsePosPulseMode_doc[] = "getUsePosPulseMode()\n" "\tReturns whether positive pulse mode is active.\n"; PyObject* SCA_ISensor::PyGetUsePosPulseMode(PyObject* self) @@ -274,7 +312,7 @@ PyObject* SCA_ISensor::PyGetUsePosPulseMode(PyObject* self) /** * setUsePulseMode: setter for the pulse mode (KX_TRUE = on) */ -char SCA_ISensor::SetUsePosPulseMode_doc[] = +const char SCA_ISensor::SetUsePosPulseMode_doc[] = "setUsePosPulseMode(pulse?)\n" "\t - pulse? : Pulse when a positive event occurs?\n" "\t (KX_TRUE, KX_FALSE)\n" @@ -290,7 +328,7 @@ PyObject* SCA_ISensor::PySetUsePosPulseMode(PyObject* self, PyObject* args, PyOb /** * getFrequency: getter for the pulse mode interval */ -char SCA_ISensor::GetFrequency_doc[] = +const char SCA_ISensor::GetFrequency_doc[] = "getFrequency()\n" "\tReturns the frequency of the updates in pulse mode.\n" ; PyObject* SCA_ISensor::PyGetFrequency(PyObject* self) @@ -301,7 +339,7 @@ PyObject* SCA_ISensor::PyGetFrequency(PyObject* self) /** * setFrequency: setter for the pulse mode (KX_TRUE = on) */ -char SCA_ISensor::SetFrequency_doc[] = +const char SCA_ISensor::SetFrequency_doc[] = "setFrequency(pulse_frequency)\n" "\t- pulse_frequency: The frequency of the updates in pulse mode (integer)" "\tSet the frequency of the updates in pulse mode.\n" @@ -325,7 +363,7 @@ PyObject* SCA_ISensor::PySetFrequency(PyObject* self, PyObject* args, PyObject* } -char SCA_ISensor::GetInvert_doc[] = +const char SCA_ISensor::GetInvert_doc[] = "getInvert()\n" "\tReturns whether or not pulses from this sensor are inverted.\n" ; PyObject* SCA_ISensor::PyGetInvert(PyObject* self) @@ -333,7 +371,7 @@ PyObject* SCA_ISensor::PyGetInvert(PyObject* self) return BoolToPyArg(m_invert); } -char SCA_ISensor::SetInvert_doc[] = +const char SCA_ISensor::SetInvert_doc[] = "setInvert(invert?)\n" "\t- invert?: Invert the event-values? (KX_TRUE, KX_FALSE)\n" "\tSet whether to invert pulses.\n"; @@ -345,7 +383,7 @@ PyObject* SCA_ISensor::PySetInvert(PyObject* self, PyObject* args, PyObject* kwd Py_Return; } -char SCA_ISensor::GetLevel_doc[] = +const char SCA_ISensor::GetLevel_doc[] = "getLevel()\n" "\tReturns whether this sensor is a level detector or a edge detector.\n" "\tIt makes a difference only in case of logic state transition (state actuator).\n" @@ -357,7 +395,7 @@ PyObject* SCA_ISensor::PyGetLevel(PyObject* self) return BoolToPyArg(m_level); } -char SCA_ISensor::SetLevel_doc[] = +const char SCA_ISensor::SetLevel_doc[] = "setLevel(level?)\n" "\t- level?: Detect level instead of edge? (KX_TRUE, KX_FALSE)\n" "\tSet whether to detect level or edge transition when entering a state.\n"; @@ -369,7 +407,7 @@ PyObject* SCA_ISensor::PySetLevel(PyObject* self, PyObject* args, PyObject* kwds Py_Return; } -char SCA_ISensor::GetUseNegPulseMode_doc[] = +const char SCA_ISensor::GetUseNegPulseMode_doc[] = "getUseNegPulseMode()\n" "\tReturns whether negative pulse mode is active.\n"; PyObject* SCA_ISensor::PyGetUseNegPulseMode(PyObject* self) @@ -377,7 +415,7 @@ PyObject* SCA_ISensor::PyGetUseNegPulseMode(PyObject* self) return BoolToPyArg(m_neg_pulsemode); } -char SCA_ISensor::SetUseNegPulseMode_doc[] = +const char SCA_ISensor::SetUseNegPulseMode_doc[] = "setUseNegPulseMode(pulse?)\n" "\t - pulse? : Pulse when a negative event occurs?\n" "\t (KX_TRUE, KX_FALSE)\n" @@ -390,4 +428,15 @@ PyObject* SCA_ISensor::PySetUseNegPulseMode(PyObject* self, PyObject* args, PyOb Py_Return; } +const char SCA_ISensor::Reset_doc[] = +"reset()\n" +"\tReset sensor internal state, effect depends on the type of sensor and settings.\n" +"\tThe sensor is put in its initial state as if it was just activated.\n"; +PyObject* SCA_ISensor::PyReset(PyObject* self) +{ + Init(); + Py_Return; +} + + /* eof */ diff --git a/source/gameengine/GameLogic/SCA_ISensor.h b/source/gameengine/GameLogic/SCA_ISensor.h index d5dabbce3ee..0d65270dc7b 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.h +++ b/source/gameengine/GameLogic/SCA_ISensor.h @@ -34,6 +34,8 @@ #include "SCA_ILogicBrick.h" +#include <vector> + /** * Interface Class for all logic Sensors. Implements * pulsemode,pulsefrequency */ @@ -73,9 +75,9 @@ class SCA_ISensor : public SCA_ILogicBrick /** number of connections to controller */ int m_links; - /** Pass the activation on to the logic manager.*/ - void SignalActivation(class SCA_LogicManager* logicmgr); - + /** list of controllers that have just activated this sensor because of a state change */ + std::vector<class SCA_IController*> m_newControllers; + public: SCA_ISensor(SCA_IObject* gameobj, class SCA_EventManager* eventmgr, @@ -128,6 +130,8 @@ public: /** Resume sensing. */ void Resume(); + void AddNewController(class SCA_IController* controller) + { m_newControllers.push_back(controller); } void ClrLink() { m_links = 0; } void IncLink() @@ -137,7 +141,8 @@ public: { return !m_links; } /* Python functions: */ - KX_PYMETHOD_DOC(SCA_ISensor,IsPositive); + KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,IsPositive); + KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,IsTriggered); KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,GetUsePosPulseMode); KX_PYMETHOD_DOC(SCA_ISensor,SetUsePosPulseMode); KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,GetFrequency); @@ -148,6 +153,7 @@ public: KX_PYMETHOD_DOC(SCA_ISensor,SetInvert); KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,GetLevel); KX_PYMETHOD_DOC(SCA_ISensor,SetLevel); + KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,Reset); }; diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.cpp b/source/gameengine/GameLogic/SCA_JoystickManager.cpp index 8ff28ba0b51..d874b5b013a 100644 --- a/source/gameengine/GameLogic/SCA_JoystickManager.cpp +++ b/source/gameengine/GameLogic/SCA_JoystickManager.cpp @@ -40,35 +40,48 @@ SCA_JoystickManager::SCA_JoystickManager(class SCA_LogicManager* logicmgr) : SCA_EventManager(JOY_EVENTMGR), m_logicmgr(logicmgr) { - m_joystick = SCA_Joystick::GetInstance(); + int i; + for (i=0; i<JOYINDEX_MAX; i++) { + m_joystick[i] = SCA_Joystick::GetInstance( i ); + } } SCA_JoystickManager::~SCA_JoystickManager() { - m_joystick->ReleaseInstance(); + int i; + for (i=0; i<JOYINDEX_MAX; i++) { + m_joystick[i]->ReleaseInstance(); + } } void SCA_JoystickManager::NextFrame(double curtime,double deltatime) { - set<SCA_ISensor*>::iterator it; - for (it = m_sensors.begin(); it != m_sensors.end(); it++) - { - SCA_JoystickSensor* joysensor = (SCA_JoystickSensor*)(*it); - if(!joysensor->IsSuspended()) + if (m_sensors.size()==0) { + return; + } + else { + set<SCA_ISensor*>::iterator it; +#ifndef DISABLE_SDL + SCA_Joystick::HandleEvents(); /* Handle all SDL Joystick events */ +#endif + for (it = m_sensors.begin(); it != m_sensors.end(); it++) { - m_joystick->HandleEvents(); - joysensor->Activate(m_logicmgr, NULL); + SCA_JoystickSensor* joysensor = (SCA_JoystickSensor*)(*it); + if(!joysensor->IsSuspended()) + { + joysensor->Activate(m_logicmgr, NULL); + } } } } -SCA_Joystick *SCA_JoystickManager::GetJoystickDevice() +SCA_Joystick *SCA_JoystickManager::GetJoystickDevice( short int joyindex) { /* *Return the instance of SCA_Joystick for use */ - return m_joystick; + return m_joystick[joyindex]; } diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.h b/source/gameengine/GameLogic/SCA_JoystickManager.h index f2bb27965fa..d3a7ac95bea 100644 --- a/source/gameengine/GameLogic/SCA_JoystickManager.h +++ b/source/gameengine/GameLogic/SCA_JoystickManager.h @@ -40,12 +40,12 @@ class SCA_JoystickManager : public SCA_EventManager /** * SDL Joystick Class Instance */ - SCA_Joystick *m_joystick; + SCA_Joystick *m_joystick[JOYINDEX_MAX]; public: SCA_JoystickManager(class SCA_LogicManager* logicmgr); virtual ~SCA_JoystickManager(); virtual void NextFrame(double curtime,double deltatime); - SCA_Joystick* GetJoystickDevice(void); + SCA_Joystick* GetJoystickDevice(short int joyindex); }; diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp index 3fb439eb25b..58818240009 100644 --- a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp +++ b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp @@ -30,8 +30,11 @@ #include "SCA_EventManager.h" #include "SCA_LogicManager.h" +#include "PyObjectPlus.h" + #include <iostream> + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -39,6 +42,7 @@ SCA_JoystickSensor::SCA_JoystickSensor(class SCA_JoystickManager* eventmgr, SCA_IObject* gameobj, + short int joyindex, short int joymode, int axis, int axisf,int prec, int button, int buttonf, @@ -53,7 +57,8 @@ SCA_JoystickSensor::SCA_JoystickSensor(class SCA_JoystickManager* eventmgr, m_hat(hat), m_hatf(hatf), m_precision(prec), - m_joymode(joymode) + m_joymode(joymode), + m_joyindex(joyindex) { /* std::cout << " axis " << m_axis << std::endl; @@ -99,10 +104,13 @@ bool SCA_JoystickSensor::IsPositiveTrigger() bool SCA_JoystickSensor::Evaluate(CValue* event) { - SCA_Joystick *js = m_pJoystickMgr->GetJoystickDevice(); + SCA_Joystick *js = m_pJoystickMgr->GetJoystickDevice(m_joyindex); bool result = false; bool reset = m_reset && m_level; + if(js==NULL) + return false; + m_reset = false; switch(m_joymode) { @@ -118,7 +126,7 @@ bool SCA_JoystickSensor::Evaluate(CValue* event) js->cSetPrecision(m_precision); if(m_axisf == 1){ if(js->aUpAxisIsPositive(m_axis)){ - m_istrig =1; + m_istrig = 1; result = true; }else{ if(m_istrig){ @@ -241,11 +249,31 @@ bool SCA_JoystickSensor::Evaluate(CValue* event) printf("Error invalid switch statement\n"); break; } - if(!js->IsTrig()){ + + if (js->IsTrig()) { + /* The if below detects changes with the joystick trigger state. + * js->IsTrig() will stay true as long as the key is held. + * even though the event from SDL will only be sent once. + * (js->IsTrig() && m_istrig_lastjs) - when true it means this sensor + * had the same joystick trigger state last time, + * Setting the result false this time means it wont run the sensors + * controller every time (like a pulse sensor) + * + * This is not done with the joystick its self incase other sensors use + * it or become active. + */ + if (m_istrig_lastjs) { + result = false; + } + m_istrig_lastjs = true; + } else { m_istrig = 0; + m_istrig_lastjs = false; } + if (reset) result = true; + return result; } @@ -293,18 +321,21 @@ PyParentObject SCA_JoystickSensor::Parents[] = { PyMethodDef SCA_JoystickSensor::Methods[] = { - {"getAxis", (PyCFunction) SCA_JoystickSensor::sPyGetAxis, METH_NOARGS, GetAxis_doc}, - {"setAxis", (PyCFunction) SCA_JoystickSensor::sPySetAxis, METH_VARARGS, SetAxis_doc}, - {"getAxisValue", (PyCFunction) SCA_JoystickSensor::sPyGetRealAxis, METH_NOARGS, GetRealAxis_doc}, - {"getThreshold", (PyCFunction) SCA_JoystickSensor::sPyGetThreshold, METH_NOARGS, GetThreshold_doc}, - {"setThreshold", (PyCFunction) SCA_JoystickSensor::sPySetThreshold, METH_VARARGS, SetThreshold_doc}, - {"getButton", (PyCFunction) SCA_JoystickSensor::sPyGetButton, METH_NOARGS, GetButton_doc}, - {"setButton", (PyCFunction) SCA_JoystickSensor::sPySetButton, METH_VARARGS, SetButton_doc}, - {"getHat", (PyCFunction) SCA_JoystickSensor::sPyGetHat, METH_NOARGS, GetHat_doc}, - {"setHat", (PyCFunction) SCA_JoystickSensor::sPySetHat, METH_VARARGS, SetHat_doc}, - {"getNumAxes", (PyCFunction) SCA_JoystickSensor::sPyNumberOfAxes, METH_NOARGS, NumberOfAxes_doc}, - {"getNumButtons",(PyCFunction) SCA_JoystickSensor::sPyNumberOfButtons,METH_NOARGS, NumberOfButtons_doc}, - {"getNumHats", (PyCFunction) SCA_JoystickSensor::sPyNumberOfHats, METH_NOARGS, NumberOfHats_doc}, + {"getIndex", (PyCFunction) SCA_JoystickSensor::sPyGetIndex, METH_NOARGS, (PY_METHODCHAR)GetIndex_doc}, + {"setIndex", (PyCFunction) SCA_JoystickSensor::sPySetIndex, METH_O, (PY_METHODCHAR)SetIndex_doc}, + {"getAxis", (PyCFunction) SCA_JoystickSensor::sPyGetAxis, METH_NOARGS, (PY_METHODCHAR)GetAxis_doc}, + {"setAxis", (PyCFunction) SCA_JoystickSensor::sPySetAxis, METH_VARARGS, (PY_METHODCHAR)SetAxis_doc}, + {"getAxisValue", (PyCFunction) SCA_JoystickSensor::sPyGetRealAxis, METH_NOARGS, (PY_METHODCHAR)GetRealAxis_doc}, + {"getThreshold", (PyCFunction) SCA_JoystickSensor::sPyGetThreshold, METH_NOARGS, (PY_METHODCHAR)GetThreshold_doc}, + {"setThreshold", (PyCFunction) SCA_JoystickSensor::sPySetThreshold, METH_VARARGS, (PY_METHODCHAR)SetThreshold_doc}, + {"getButton", (PyCFunction) SCA_JoystickSensor::sPyGetButton, METH_NOARGS, (PY_METHODCHAR)GetButton_doc}, + {"setButton", (PyCFunction) SCA_JoystickSensor::sPySetButton, METH_VARARGS, (PY_METHODCHAR)SetButton_doc}, + {"getHat", (PyCFunction) SCA_JoystickSensor::sPyGetHat, METH_NOARGS, (PY_METHODCHAR)GetHat_doc}, + {"setHat", (PyCFunction) SCA_JoystickSensor::sPySetHat, METH_VARARGS, (PY_METHODCHAR)SetHat_doc}, + {"getNumAxes", (PyCFunction) SCA_JoystickSensor::sPyNumberOfAxes, METH_NOARGS, (PY_METHODCHAR)NumberOfAxes_doc}, + {"getNumButtons",(PyCFunction) SCA_JoystickSensor::sPyNumberOfButtons,METH_NOARGS, (PY_METHODCHAR)NumberOfButtons_doc}, + {"getNumHats", (PyCFunction) SCA_JoystickSensor::sPyNumberOfHats, METH_NOARGS, (PY_METHODCHAR)NumberOfHats_doc}, + {"isConnected", (PyCFunction) SCA_JoystickSensor::sPyConnected, METH_NOARGS, (PY_METHODCHAR)Connected_doc}, {NULL,NULL} //Sentinel }; @@ -314,24 +345,44 @@ PyObject* SCA_JoystickSensor::_getattr(const STR_String& attr) { } +/* get index ---------------------------------------------------------- */ +const char SCA_JoystickSensor::GetIndex_doc[] = +"getIndex\n" +"\tReturns the joystick index to use.\n"; +PyObject* SCA_JoystickSensor::PyGetIndex( PyObject* self ) { + return PyInt_FromLong(m_joyindex); +} + + +/* set index ---------------------------------------------------------- */ +const char SCA_JoystickSensor::SetIndex_doc[] = +"setIndex\n" +"\tSets the joystick index to use.\n"; +PyObject* SCA_JoystickSensor::PySetIndex( PyObject* self, PyObject* value ) { + int index = PyInt_AsLong( value ); /* -1 on error, will raise an error in this case */ + if (index < 0 || index >= JOYINDEX_MAX) { + PyErr_SetString(PyExc_ValueError, "joystick index out of range or not an int"); + return NULL; + } + + m_joyindex = index; + Py_RETURN_NONE; +} + /* get axis ---------------------------------------------------------- */ -char SCA_JoystickSensor::GetAxis_doc[] = +const char SCA_JoystickSensor::GetAxis_doc[] = "getAxis\n" "\tReturns the current state of the axis.\n"; -PyObject* SCA_JoystickSensor::PyGetAxis( PyObject* self, - PyObject* args, - PyObject* kwds) { - return Py_BuildValue("[ii]",m_axis, m_axisf); +PyObject* SCA_JoystickSensor::PyGetAxis( PyObject* self) { + return PyInt_FromLong(m_joyindex); } /* set axis ---------------------------------------------------------- */ -char SCA_JoystickSensor::SetAxis_doc[] = +const char SCA_JoystickSensor::SetAxis_doc[] = "setAxis\n" "\tSets the current state of the axis.\n"; -PyObject* SCA_JoystickSensor::PySetAxis( PyObject* self, - PyObject* args, - PyObject* kwds) { +PyObject* SCA_JoystickSensor::PySetAxis( PyObject* self, PyObject* args ) { int axis,axisflag; if(!PyArg_ParseTuple(args, "ii", &axis, &axisflag)){ @@ -339,145 +390,126 @@ PyObject* SCA_JoystickSensor::PySetAxis( PyObject* self, } m_axis = axis; m_axisf = axisflag; - Py_Return; + Py_RETURN_NONE; } /* get axis value ----------------------------------------------------- */ -char SCA_JoystickSensor::GetRealAxis_doc[] = +const char SCA_JoystickSensor::GetRealAxis_doc[] = "getAxisValue\n" "\tReturns a list of the values for each axis .\n"; -PyObject* SCA_JoystickSensor::PyGetRealAxis( PyObject* self, - PyObject* args, - PyObject* kwds) { - int a,b,c,d; - SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(); - a = joy->GetAxis10(); - b = joy->GetAxis11(); - c = joy->GetAxis20(); - d = joy->GetAxis21(); - return Py_BuildValue("[iiii]",a,b,c,d); +PyObject* SCA_JoystickSensor::PyGetRealAxis( PyObject* self) { + SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex); + if(joy) + return Py_BuildValue("[iiii]", joy->GetAxis10(), joy->GetAxis11(), joy->GetAxis20(), joy->GetAxis21()); + else + return Py_BuildValue("[iiii]", 0, 0, 0, 0); } /* get threshold ----------------------------------------------------- */ -char SCA_JoystickSensor::GetThreshold_doc[] = +const char SCA_JoystickSensor::GetThreshold_doc[] = "getThreshold\n" "\tReturns the threshold of the axis.\n"; -PyObject* SCA_JoystickSensor::PyGetThreshold( PyObject* self, - PyObject* args, - PyObject* kwds) { - return Py_BuildValue("i", m_precision); +PyObject* SCA_JoystickSensor::PyGetThreshold( PyObject* self) { + return PyInt_FromLong(m_precision); } /* set threshold ----------------------------------------------------- */ -char SCA_JoystickSensor::SetThreshold_doc[] = +const char SCA_JoystickSensor::SetThreshold_doc[] = "setThreshold\n" "\tSets the threshold of the axis.\n"; -PyObject* SCA_JoystickSensor::PySetThreshold( PyObject* self, - PyObject* args, - PyObject* kwds) { +PyObject* SCA_JoystickSensor::PySetThreshold( PyObject* self, PyObject* args ) { int thresh; if(!PyArg_ParseTuple(args, "i", &thresh)){ return NULL; } m_precision = thresh; - Py_Return; + Py_RETURN_NONE; } /* get button -------------------------------------------------------- */ -char SCA_JoystickSensor::GetButton_doc[] = +const char SCA_JoystickSensor::GetButton_doc[] = "getButton\n" "\tReturns the currently pressed button.\n"; -PyObject* SCA_JoystickSensor::PyGetButton( PyObject* self, - PyObject* args, - PyObject* kwds) { +PyObject* SCA_JoystickSensor::PyGetButton( PyObject* self) { return Py_BuildValue("[ii]",m_button, m_buttonf); } /* set button -------------------------------------------------------- */ -char SCA_JoystickSensor::SetButton_doc[] = +const char SCA_JoystickSensor::SetButton_doc[] = "setButton\n" "\tSets the button the sensor reacts to.\n"; -PyObject* SCA_JoystickSensor::PySetButton( PyObject* self, - PyObject* args, - PyObject* kwds) { +PyObject* SCA_JoystickSensor::PySetButton( PyObject* self, PyObject* args ) { int button,buttonflag; if(!PyArg_ParseTuple(args, "ii", &button, &buttonflag)){ return NULL; } m_button = button; m_buttonf = buttonflag; - Py_Return; + Py_RETURN_NONE; } /* get hat ----------------------------------------------------------- */ -char SCA_JoystickSensor::GetHat_doc[] = +const char SCA_JoystickSensor::GetHat_doc[] = "getHat\n" "\tReturns the current direction of the hat.\n"; -PyObject* SCA_JoystickSensor::PyGetHat( PyObject* self, - PyObject* args, - PyObject* kwds) { +PyObject* SCA_JoystickSensor::PyGetHat( PyObject* self ) { return Py_BuildValue("[ii]",m_hat, m_hatf); } /* set hat ----------------------------------------------------------- */ -char SCA_JoystickSensor::SetHat_doc[] = +const char SCA_JoystickSensor::SetHat_doc[] = "setHat\n" "\tSets the hat the sensor reacts to.\n"; -PyObject* SCA_JoystickSensor::PySetHat( PyObject* self, - PyObject* args, - PyObject* kwds) { +PyObject* SCA_JoystickSensor::PySetHat( PyObject* self, PyObject* args ) { int hat,hatflag; if(!PyArg_ParseTuple(args, "ii", &hat, &hatflag)){ return NULL; } m_hat = hat; m_hatf = hatflag; - Py_Return; + Py_RETURN_NONE; } /* get # of ----------------------------------------------------- */ -char SCA_JoystickSensor::NumberOfAxes_doc[] = +const char SCA_JoystickSensor::NumberOfAxes_doc[] = "getNumAxes\n" "\tReturns the number of axes .\n"; -PyObject* SCA_JoystickSensor::PyNumberOfAxes( PyObject* self, - PyObject* args, - PyObject* kwds) { - int num; - SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(); - num = joy->GetNumberOfAxes(); - return Py_BuildValue("i",num); +PyObject* SCA_JoystickSensor::PyNumberOfAxes( PyObject* self ) { + SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex); + // when the joystick is null their is 0 exis still. dumb but scripters should use isConnected() + return PyInt_FromLong( joy ? joy->GetNumberOfAxes() : 0 ); } -char SCA_JoystickSensor::NumberOfButtons_doc[] = +const char SCA_JoystickSensor::NumberOfButtons_doc[] = "getNumButtons\n" "\tReturns the number of buttons .\n"; -PyObject* SCA_JoystickSensor::PyNumberOfButtons( PyObject* self, - PyObject* args, - PyObject* kwds) { - int num; - SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(); - num = joy->GetNumberOfButtons(); - return Py_BuildValue("i",num); +PyObject* SCA_JoystickSensor::PyNumberOfButtons( PyObject* self ) { + SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex); + return PyInt_FromLong( joy ? joy->GetNumberOfButtons() : 0 ); } -char SCA_JoystickSensor::NumberOfHats_doc[] = +const char SCA_JoystickSensor::NumberOfHats_doc[] = "getNumHats\n" "\tReturns the number of hats .\n"; -PyObject* SCA_JoystickSensor::PyNumberOfHats( PyObject* self, - PyObject* args, - PyObject* kwds) { - int num; - SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(); - num = joy->GetNumberOfHats(); - return Py_BuildValue("i",num); +PyObject* SCA_JoystickSensor::PyNumberOfHats( PyObject* self ) { + SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex); + return PyInt_FromLong( joy ? joy->GetNumberOfHats() : 0 ); +} + +const char SCA_JoystickSensor::Connected_doc[] = +"getConnected\n" +"\tReturns True if a joystick is connected at this joysticks index.\n"; +PyObject* SCA_JoystickSensor::PyConnected( PyObject* self ) { + SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex); + return PyBool_FromLong( joy ? joy->Connected() : 0 ); } diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.h b/source/gameengine/GameLogic/SCA_JoystickSensor.h index 69068da6494..8b74f6e0296 100644 --- a/source/gameengine/GameLogic/SCA_JoystickSensor.h +++ b/source/gameengine/GameLogic/SCA_JoystickSensor.h @@ -69,9 +69,19 @@ class SCA_JoystickSensor :public SCA_ISensor */ bool m_istrig; /** + * Last trigger state for this sensors joystick, + * Otherwise it will trigger all the time + * this is used to see if the trigger state changes. + */ + bool m_istrig_lastjs; + /** * The mode to determine axis,button or hat */ short int m_joymode; + /** + * Select which joystick to use + */ + short int m_joyindex; enum KX_JOYSENSORMODE { KX_JOYSENSORMODE_NODEF = 0, @@ -85,6 +95,7 @@ class SCA_JoystickSensor :public SCA_ISensor public: SCA_JoystickSensor(class SCA_JoystickManager* eventmgr, SCA_IObject* gameobj, + short int joyindex, short int joymode, int axis, int axisf,int prec, int button, int buttonf, @@ -97,28 +108,36 @@ public: virtual bool IsPositiveTrigger(); virtual void Init(); + short int GetJoyIndex(void){ + return m_joyindex; + } + /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ virtual PyObject* _getattr(const STR_String& attr); + /* Joystick Index */ + KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetIndex); + KX_PYMETHOD_DOC_O(SCA_JoystickSensor,SetIndex); /* Axes*/ - KX_PYMETHOD_DOC(SCA_JoystickSensor,GetAxis); - KX_PYMETHOD_DOC(SCA_JoystickSensor,SetAxis); - KX_PYMETHOD_DOC(SCA_JoystickSensor,GetRealAxis); - KX_PYMETHOD_DOC(SCA_JoystickSensor,GetThreshold); - KX_PYMETHOD_DOC(SCA_JoystickSensor,SetThreshold); + KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetAxis); + KX_PYMETHOD_DOC_VARARGS(SCA_JoystickSensor,SetAxis); + KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetRealAxis); + KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetThreshold); + KX_PYMETHOD_DOC_VARARGS(SCA_JoystickSensor,SetThreshold); /* Buttons */ - KX_PYMETHOD_DOC(SCA_JoystickSensor,GetButton); - KX_PYMETHOD_DOC(SCA_JoystickSensor,SetButton); + KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetButton); + KX_PYMETHOD_DOC_VARARGS(SCA_JoystickSensor,SetButton); /* Hats */ - KX_PYMETHOD_DOC(SCA_JoystickSensor,GetHat); - KX_PYMETHOD_DOC(SCA_JoystickSensor,SetHat); + KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetHat); + KX_PYMETHOD_DOC_VARARGS(SCA_JoystickSensor,SetHat); /* number of */ - KX_PYMETHOD_DOC(SCA_JoystickSensor,NumberOfAxes); - KX_PYMETHOD_DOC(SCA_JoystickSensor,NumberOfButtons); - KX_PYMETHOD_DOC(SCA_JoystickSensor,NumberOfHats); + KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,NumberOfAxes); + KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,NumberOfButtons); + KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,NumberOfHats); + KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,Connected); }; diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp index a7a6fa93db4..d09a5394965 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp @@ -505,12 +505,12 @@ PyObject* SCA_KeyboardSensor::sPySetAllMode(PyObject* self, PyObject* kwds) { // printf("sPyIsPositive\n"); - return ((SCA_KeyboardSensor*) self)->PyIsPositive(self, args, kwds); + return ((SCA_KeyboardSensor*) self)->PyIsPositive(self); } /** 1. GetKey : check which key this sensor looks at */ -char SCA_KeyboardSensor::GetKey_doc[] = +const char SCA_KeyboardSensor::GetKey_doc[] = "getKey()\n" "\tReturn the code of the key this sensor is listening to.\n" ; PyObject* SCA_KeyboardSensor::PyGetKey(PyObject* self, PyObject* args, PyObject* kwds) @@ -519,7 +519,7 @@ PyObject* SCA_KeyboardSensor::PyGetKey(PyObject* self, PyObject* args, PyObject* } /** 2. SetKey: change the key to look at */ -char SCA_KeyboardSensor::SetKey_doc[] = +const char SCA_KeyboardSensor::SetKey_doc[] = "setKey(keycode)\n" "\t- keycode: any code from GameKeys\n" "\tSet the key this sensor should listen to.\n" ; @@ -539,7 +539,7 @@ PyObject* SCA_KeyboardSensor::PySetKey(PyObject* self, PyObject* args, PyObject* } /** 3. GetHold1 : set the first bucky bit */ -char SCA_KeyboardSensor::GetHold1_doc[] = +const char SCA_KeyboardSensor::GetHold1_doc[] = "getHold1()\n" "\tReturn the code of the first key modifier to the key this \n" "\tsensor is listening to.\n" ; @@ -549,7 +549,7 @@ PyObject* SCA_KeyboardSensor::PyGetHold1(PyObject* self, PyObject* args, PyObjec } /** 4. SetHold1: change the first bucky bit */ -char SCA_KeyboardSensor::SetHold1_doc[] = +const char SCA_KeyboardSensor::SetHold1_doc[] = "setHold1(keycode)\n" "\t- keycode: any code from GameKeys\n" "\tSet the first modifier to the key this sensor should listen to.\n" ; @@ -569,7 +569,7 @@ PyObject* SCA_KeyboardSensor::PySetHold1(PyObject* self, PyObject* args, PyObjec } /** 5. GetHold2 : get the second bucky bit */ -char SCA_KeyboardSensor::GetHold2_doc[] = +const char SCA_KeyboardSensor::GetHold2_doc[] = "getHold2()\n" "\tReturn the code of the second key modifier to the key this \n" "\tsensor is listening to.\n" ; @@ -579,7 +579,7 @@ PyObject* SCA_KeyboardSensor::PyGetHold2(PyObject* self, PyObject* args, PyObjec } /** 6. SetHold2: change the second bucky bit */ -char SCA_KeyboardSensor::SetHold2_doc[] = +const char SCA_KeyboardSensor::SetHold2_doc[] = "setHold2(keycode)\n" "\t- keycode: any code from GameKeys\n" "\tSet the first modifier to the key this sensor should listen to.\n" ; @@ -599,7 +599,7 @@ PyObject* SCA_KeyboardSensor::PySetHold2(PyObject* self, PyObject* args, PyObjec } -char SCA_KeyboardSensor::GetPressedKeys_doc[] = +const char SCA_KeyboardSensor::GetPressedKeys_doc[] = "getPressedKeys()\n" "\tGet a list of pressed keys that have either been pressed, or just released this frame.\n" ; @@ -639,7 +639,7 @@ PyObject* SCA_KeyboardSensor::PyGetPressedKeys(PyObject* self, PyObject* args, P -char SCA_KeyboardSensor::GetCurrentlyPressedKeys_doc[] = +const char SCA_KeyboardSensor::GetCurrentlyPressedKeys_doc[] = "getCurrentlyPressedKeys()\n" "\tGet a list of keys that are currently pressed.\n" ; @@ -710,17 +710,17 @@ PyParentObject SCA_KeyboardSensor::Parents[] = { }; PyMethodDef SCA_KeyboardSensor::Methods[] = { - {"getKey", (PyCFunction) SCA_KeyboardSensor::sPyGetKey, METH_VARARGS, GetKey_doc}, - {"setKey", (PyCFunction) SCA_KeyboardSensor::sPySetKey, METH_VARARGS, SetKey_doc}, - {"getHold1", (PyCFunction) SCA_KeyboardSensor::sPyGetHold1, METH_VARARGS, GetHold1_doc}, - {"setHold1", (PyCFunction) SCA_KeyboardSensor::sPySetHold1, METH_VARARGS, SetHold1_doc}, - {"getHold2", (PyCFunction) SCA_KeyboardSensor::sPyGetHold2, METH_VARARGS, GetHold2_doc}, - {"setHold2", (PyCFunction) SCA_KeyboardSensor::sPySetHold2, METH_VARARGS, SetHold2_doc}, -// {"getUseAllKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetUseAllKeys, METH_VARARGS, GetUseAllKeys_doc}, -// {"setUseAllKeys", (PyCFunction) SCA_KeyboardSensor::sPySetUseAllKeys, METH_VARARGS, SetUseAllKeys_doc}, - {"getPressedKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetPressedKeys, METH_VARARGS, GetPressedKeys_doc}, - {"getCurrentlyPressedKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetCurrentlyPressedKeys, METH_VARARGS, GetCurrentlyPressedKeys_doc}, -// {"getKeyEvents", (PyCFunction) SCA_KeyboardSensor::sPyGetKeyEvents, METH_VARARGS, GetKeyEvents_doc}, + {"getKey", (PyCFunction) SCA_KeyboardSensor::sPyGetKey, METH_VARARGS, (PY_METHODCHAR)GetKey_doc}, + {"setKey", (PyCFunction) SCA_KeyboardSensor::sPySetKey, METH_VARARGS, (PY_METHODCHAR)SetKey_doc}, + {"getHold1", (PyCFunction) SCA_KeyboardSensor::sPyGetHold1, METH_VARARGS, (PY_METHODCHAR)GetHold1_doc}, + {"setHold1", (PyCFunction) SCA_KeyboardSensor::sPySetHold1, METH_VARARGS, (PY_METHODCHAR)SetHold1_doc}, + {"getHold2", (PyCFunction) SCA_KeyboardSensor::sPyGetHold2, METH_VARARGS, (PY_METHODCHAR)GetHold2_doc}, + {"setHold2", (PyCFunction) SCA_KeyboardSensor::sPySetHold2, METH_VARARGS, (PY_METHODCHAR)SetHold2_doc}, +// {"getUseAllKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetUseAllKeys, METH_VARARGS, (PY_METHODCHAR)GetUseAllKeys_doc}, +// {"setUseAllKeys", (PyCFunction) SCA_KeyboardSensor::sPySetUseAllKeys, METH_VARARGS, (PY_METHODCHAR)SetUseAllKeys_doc}, + {"getPressedKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetPressedKeys, METH_VARARGS, (PY_METHODCHAR)GetPressedKeys_doc}, + {"getCurrentlyPressedKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetCurrentlyPressedKeys, METH_VARARGS, (PY_METHODCHAR)GetCurrentlyPressedKeys_doc}, +// {"getKeyEvents", (PyCFunction) SCA_KeyboardSensor::sPyGetKeyEvents, METH_VARARGS, (PY_METHODCHAR)GetKeyEvents_doc}, {NULL,NULL} //Sentinel }; diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp index 91e66aea359..b584b37180f 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.cpp +++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp @@ -33,6 +33,7 @@ #include "SCA_IController.h" #include "SCA_IActuator.h" #include "SCA_EventManager.h" +#include "SCA_PythonController.h" #include <set> #ifdef HAVE_CONFIG_H @@ -232,8 +233,6 @@ void SCA_LogicManager::BeginFrame(double curtime, double fixedtime) // for this frame, look up for activated sensors, and build the collection of triggered controllers // int numsensors = this->m_activatedsensors.size(); /*unused*/ - set<SmartControllerPtr> triggeredControllerSet; - for (vector<SCA_ISensor*>::const_iterator is=m_activatedsensors.begin(); !(is==m_activatedsensors.end());is++) { @@ -244,19 +243,28 @@ void SCA_LogicManager::BeginFrame(double curtime, double fixedtime) { SCA_IController* contr = *c;//controllerarray->at(c); if (contr->IsActive()) - triggeredControllerSet.insert(SmartControllerPtr(contr,0)); + { + m_triggeredControllerSet.insert(SmartControllerPtr(contr,0)); + // So that the controller knows which sensor has activited it. + // Only needed for the python controller though. + if (contr->GetType() == &SCA_PythonController::Type) + { + SCA_PythonController* pythonController = (SCA_PythonController*)contr; + pythonController->AddTriggeredSensor(sensor); + } + } } //sensor->SetActive(false); } // int numtriggered = triggeredControllerSet.size(); /*unused*/ - for (set<SmartControllerPtr>::iterator tit=triggeredControllerSet.begin(); - !(tit==triggeredControllerSet.end());tit++) + for (set<SmartControllerPtr>::iterator tit=m_triggeredControllerSet.begin(); + !(tit==m_triggeredControllerSet.end());tit++) { (*tit)->Trigger(this); } - triggeredControllerSet.clear(); + m_triggeredControllerSet.clear(); } @@ -382,6 +390,17 @@ void SCA_LogicManager::AddActivatedSensor(SCA_ISensor* sensor) } } +void SCA_LogicManager::AddTriggeredController(SCA_IController* controller, SCA_ISensor* sensor) +{ + m_triggeredControllerSet.insert(SmartControllerPtr(controller,0)); + // so that the controller knows which sensor has activited it + // only needed for python controller + if (controller->GetType() == &SCA_PythonController::Type) + { + SCA_PythonController* pythonController = (SCA_PythonController*)controller; + pythonController->AddTriggeredSensor(sensor); + } +} void SCA_LogicManager::AddActiveActuator(SCA_IActuator* actua,CValue* event) diff --git a/source/gameengine/GameLogic/SCA_LogicManager.h b/source/gameengine/GameLogic/SCA_LogicManager.h index e0d3d506702..50383879d8f 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.h +++ b/source/gameengine/GameLogic/SCA_LogicManager.h @@ -99,6 +99,7 @@ class SCA_LogicManager vector<class SCA_ISensor*> m_activatedsensors; set<class SmartActuatorPtr> m_activeActuators; + set<class SmartControllerPtr> m_triggeredControllerSet; map<SCA_ISensor*,controllerlist > m_sensorcontrollermapje; @@ -127,6 +128,7 @@ public: void EndFrame(); void AddActivatedSensor(SCA_ISensor* sensor); void AddActiveActuator(SCA_IActuator* sensor,class CValue* event); + void AddTriggeredController(SCA_IController* controller, SCA_ISensor* sensor); SCA_EventManager* FindEventManager(int eventmgrtype); void RemoveGameObject(const STR_String& gameobjname); diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.cpp b/source/gameengine/GameLogic/SCA_MouseSensor.cpp index 2298ddb0743..d4952ce4777 100644 --- a/source/gameengine/GameLogic/SCA_MouseSensor.cpp +++ b/source/gameengine/GameLogic/SCA_MouseSensor.cpp @@ -283,8 +283,8 @@ PyParentObject SCA_MouseSensor::Parents[] = { }; PyMethodDef SCA_MouseSensor::Methods[] = { - {"getXPosition", (PyCFunction) SCA_MouseSensor::sPyGetXPosition, METH_VARARGS, GetXPosition_doc}, - {"getYPosition", (PyCFunction) SCA_MouseSensor::sPyGetYPosition, METH_VARARGS, GetYPosition_doc}, + {"getXPosition", (PyCFunction) SCA_MouseSensor::sPyGetXPosition, METH_VARARGS, (PY_METHODCHAR)GetXPosition_doc}, + {"getYPosition", (PyCFunction) SCA_MouseSensor::sPyGetYPosition, METH_VARARGS, (PY_METHODCHAR)GetYPosition_doc}, {NULL,NULL} //Sentinel }; @@ -293,7 +293,7 @@ PyObject* SCA_MouseSensor::_getattr(const STR_String& attr) { } /* get x position ---------------------------------------------------------- */ -char SCA_MouseSensor::GetXPosition_doc[] = +const char SCA_MouseSensor::GetXPosition_doc[] = "getXPosition\n" "\tReturns the x-coordinate of the mouse sensor, in frame coordinates.\n" "\tThe lower-left corner is the origin. The coordinate is given in\n" @@ -305,7 +305,7 @@ PyObject* SCA_MouseSensor::PyGetXPosition(PyObject* self, } /* get y position ---------------------------------------------------------- */ -char SCA_MouseSensor::GetYPosition_doc[] = +const char SCA_MouseSensor::GetYPosition_doc[] = "getYPosition\n" "\tReturns the y-coordinate of the mouse sensor, in frame coordinates.\n" "\tThe lower-left corner is the origin. The coordinate is given in\n" diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp index 7062f2cef6a..3b541e87f02 100644 --- a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp +++ b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp @@ -245,10 +245,10 @@ PyParentObject SCA_PropertyActuator::Parents[] = { }; PyMethodDef SCA_PropertyActuator::Methods[] = { - {"setProperty", (PyCFunction) SCA_PropertyActuator::sPySetProperty, METH_VARARGS, SetProperty_doc}, - {"getProperty", (PyCFunction) SCA_PropertyActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc}, - {"setValue", (PyCFunction) SCA_PropertyActuator::sPySetValue, METH_VARARGS, SetValue_doc}, - {"getValue", (PyCFunction) SCA_PropertyActuator::sPyGetValue, METH_VARARGS, GetValue_doc}, + {"setProperty", (PyCFunction) SCA_PropertyActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, + {"getProperty", (PyCFunction) SCA_PropertyActuator::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, + {"setValue", (PyCFunction) SCA_PropertyActuator::sPySetValue, METH_VARARGS, (PY_METHODCHAR)SetValue_doc}, + {"getValue", (PyCFunction) SCA_PropertyActuator::sPyGetValue, METH_VARARGS, (PY_METHODCHAR)GetValue_doc}, {NULL,NULL} //Sentinel }; @@ -257,7 +257,7 @@ PyObject* SCA_PropertyActuator::_getattr(const STR_String& attr) { } /* 1. setProperty */ -char SCA_PropertyActuator::SetProperty_doc[] = +const char SCA_PropertyActuator::SetProperty_doc[] = "setProperty(name)\n" "\t- name: string\n" "\tSet the property on which to operate. If there is no property\n" @@ -283,7 +283,7 @@ PyObject* SCA_PropertyActuator::PySetProperty(PyObject* self, PyObject* args, Py } /* 2. getProperty */ -char SCA_PropertyActuator::GetProperty_doc[] = +const char SCA_PropertyActuator::GetProperty_doc[] = "getProperty(name)\n" "\tReturn the property on which the actuator operates.\n"; PyObject* SCA_PropertyActuator::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) @@ -292,7 +292,7 @@ PyObject* SCA_PropertyActuator::PyGetProperty(PyObject* self, PyObject* args, Py } /* 3. setValue */ -char SCA_PropertyActuator::SetValue_doc[] = +const char SCA_PropertyActuator::SetValue_doc[] = "setValue(value)\n" "\t- value: string\n" "\tSet the value with which the actuator operates. If the value\n" @@ -311,7 +311,7 @@ PyObject* SCA_PropertyActuator::PySetValue(PyObject* self, PyObject* args, PyObj } /* 4. getValue */ -char SCA_PropertyActuator::GetValue_doc[] = +const char SCA_PropertyActuator::GetValue_doc[] = "getValue()\n" "\tReturns the value with which the actuator operates.\n"; PyObject* SCA_PropertyActuator::PyGetValue(PyObject* self, PyObject* args, PyObject* kwds) diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp index c50c011cc63..64e3d49c6cb 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp +++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp @@ -333,12 +333,12 @@ PyParentObject SCA_PropertySensor::Parents[] = { }; PyMethodDef SCA_PropertySensor::Methods[] = { - {"getType", (PyCFunction) SCA_PropertySensor::sPyGetType, METH_VARARGS, GetType_doc}, - {"setType", (PyCFunction) SCA_PropertySensor::sPySetType, METH_VARARGS, SetType_doc}, - {"getProperty", (PyCFunction) SCA_PropertySensor::sPyGetProperty, METH_VARARGS, GetProperty_doc}, - {"setProperty", (PyCFunction) SCA_PropertySensor::sPySetProperty, METH_VARARGS, SetProperty_doc}, - {"getValue", (PyCFunction) SCA_PropertySensor::sPyGetValue, METH_VARARGS, GetValue_doc}, - {"setValue", (PyCFunction) SCA_PropertySensor::sPySetValue, METH_VARARGS, SetValue_doc}, + {"getType", (PyCFunction) SCA_PropertySensor::sPyGetType, METH_VARARGS, (PY_METHODCHAR)GetType_doc}, + {"setType", (PyCFunction) SCA_PropertySensor::sPySetType, METH_VARARGS, (PY_METHODCHAR)SetType_doc}, + {"getProperty", (PyCFunction) SCA_PropertySensor::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, + {"setProperty", (PyCFunction) SCA_PropertySensor::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, + {"getValue", (PyCFunction) SCA_PropertySensor::sPyGetValue, METH_VARARGS, (PY_METHODCHAR)GetValue_doc}, + {"setValue", (PyCFunction) SCA_PropertySensor::sPySetValue, METH_VARARGS, (PY_METHODCHAR)SetValue_doc}, {NULL,NULL} //Sentinel }; @@ -347,7 +347,7 @@ PyObject* SCA_PropertySensor::_getattr(const STR_String& attr) { } /* 1. getType */ -char SCA_PropertySensor::GetType_doc[] = +const char SCA_PropertySensor::GetType_doc[] = "getType()\n" "\tReturns the type of check this sensor performs.\n"; PyObject* SCA_PropertySensor::PyGetType(PyObject* self, PyObject* args, PyObject* kwds) @@ -356,7 +356,7 @@ PyObject* SCA_PropertySensor::PyGetType(PyObject* self, PyObject* args, PyObject } /* 2. setType */ -char SCA_PropertySensor::SetType_doc[] = +const char SCA_PropertySensor::SetType_doc[] = "setType(type)\n" "\t- type: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL,\n" "\t KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED,\n" @@ -379,7 +379,7 @@ PyObject* SCA_PropertySensor::PySetType(PyObject* self, PyObject* args, PyObject } /* 3. getProperty */ -char SCA_PropertySensor::GetProperty_doc[] = +const char SCA_PropertySensor::GetProperty_doc[] = "getProperty()\n" "\tReturn the property with which the sensor operates.\n"; PyObject* SCA_PropertySensor::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) @@ -388,7 +388,7 @@ PyObject* SCA_PropertySensor::PyGetProperty(PyObject* self, PyObject* args, PyOb } /* 4. setProperty */ -char SCA_PropertySensor::SetProperty_doc[] = +const char SCA_PropertySensor::SetProperty_doc[] = "setProperty(name)\n" "\t- name: string\n" "\tSets the property with which to operate. If there is no property\n" @@ -414,7 +414,7 @@ PyObject* SCA_PropertySensor::PySetProperty(PyObject* self, PyObject* args, PyOb } /* 5. getValue */ -char SCA_PropertySensor::GetValue_doc[] = +const char SCA_PropertySensor::GetValue_doc[] = "getValue()\n" "\tReturns the value with which the sensor operates.\n"; PyObject* SCA_PropertySensor::PyGetValue(PyObject* self, PyObject* args, PyObject* kwds) @@ -423,7 +423,7 @@ PyObject* SCA_PropertySensor::PyGetValue(PyObject* self, PyObject* args, PyObjec } /* 6. setValue */ -char SCA_PropertySensor::SetValue_doc[] = +const char SCA_PropertySensor::SetValue_doc[] = "setValue(value)\n" "\t- value: string\n" "\tSet the value with which the sensor operates. If the value\n" diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp index cd1b029fc34..4cb9bc8fe53 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.cpp +++ b/source/gameengine/GameLogic/SCA_PythonController.cpp @@ -33,8 +33,11 @@ #include "SCA_LogicManager.h" #include "SCA_ISensor.h" #include "SCA_IActuator.h" +#include "PyObjectPlus.h" #include "compile.h" #include "eval.h" +#include <algorithm> + #ifdef HAVE_CONFIG_H #include <config.h> @@ -139,8 +142,16 @@ void SCA_PythonController::SetDictionary(PyObject* pythondictionary) m_pythondictionary = PyDict_Copy(pythondictionary); /* new reference */ } +int SCA_PythonController::IsTriggered(class SCA_ISensor* sensor) +{ + if (std::find(m_triggeredSensors.begin(), m_triggeredSensors.end(), sensor) != + m_triggeredSensors.end()) + return 1; + return 0; +} + #if 0 -static char* sPyGetCurrentController__doc__; +static const char* sPyGetCurrentController__doc__; #endif @@ -151,7 +162,7 @@ PyObject* SCA_PythonController::sPyGetCurrentController(PyObject* self) } #if 0 -static char* sPyAddActiveActuator__doc__; +static const char* sPyAddActiveActuator__doc__; #endif PyObject* SCA_PythonController::sPyAddActiveActuator( @@ -188,9 +199,9 @@ PyObject* SCA_PythonController::sPyAddActiveActuator( } -char* SCA_PythonController::sPyGetCurrentController__doc__ = "getCurrentController()"; -char* SCA_PythonController::sPyAddActiveActuator__doc__= "addActiveActuator(actuator,bool)"; -char SCA_PythonController::GetActuators_doc[] = "getActuator"; +const char* SCA_PythonController::sPyGetCurrentController__doc__ = "getCurrentController()"; +const char* SCA_PythonController::sPyAddActiveActuator__doc__= "addActiveActuator(actuator,bool)"; +const char SCA_PythonController::GetActuators_doc[] = "getActuator"; PyTypeObject SCA_PythonController::Type = { PyObject_HEAD_INIT(&PyType_Type) @@ -218,10 +229,10 @@ PyParentObject SCA_PythonController::Parents[] = { NULL }; PyMethodDef SCA_PythonController::Methods[] = { - {"getActuators", (PyCFunction) SCA_PythonController::sPyGetActuators, METH_NOARGS, SCA_PythonController::GetActuators_doc}, - {"getActuator", (PyCFunction) SCA_PythonController::sPyGetActuator, METH_O, SCA_PythonController::GetActuator_doc}, - {"getSensors", (PyCFunction) SCA_PythonController::sPyGetSensors, METH_NOARGS, SCA_PythonController::GetSensors_doc}, - {"getSensor", (PyCFunction) SCA_PythonController::sPyGetSensor, METH_O, SCA_PythonController::GetSensor_doc}, + {"getActuators", (PyCFunction) SCA_PythonController::sPyGetActuators, METH_NOARGS, (PY_METHODCHAR)SCA_PythonController::GetActuators_doc}, + {"getActuator", (PyCFunction) SCA_PythonController::sPyGetActuator, METH_O, (PY_METHODCHAR)SCA_PythonController::GetActuator_doc}, + {"getSensors", (PyCFunction) SCA_PythonController::sPyGetSensors, METH_NOARGS, (PY_METHODCHAR)SCA_PythonController::GetSensors_doc}, + {"getSensor", (PyCFunction) SCA_PythonController::sPyGetSensor, METH_O, (PY_METHODCHAR)SCA_PythonController::GetSensor_doc}, {"getScript", (PyCFunction) SCA_PythonController::sPyGetScript, METH_NOARGS}, {"setScript", (PyCFunction) SCA_PythonController::sPySetScript, METH_O}, {"getState", (PyCFunction) SCA_PythonController::sPyGetState, METH_NOARGS}, @@ -248,7 +259,7 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) { // didn't compile, so instead of compile, complain // something is wrong, tell the user what went wrong - printf("PYTHON SCRIPT ERROR:\n"); + printf("Python compile error from controller \"%s\": \n", GetName().Ptr()); //PyRun_SimpleString(m_scriptText.Ptr()); PyErr_Print(); return; @@ -285,7 +296,7 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) else { // something is wrong, tell the user what went wrong - printf("PYTHON SCRIPT ERROR:\n"); + printf("Python script error from controller \"%s\": \n", GetName().Ptr()); PyErr_Print(); //PyRun_SimpleString(m_scriptText.Ptr()); } @@ -294,7 +305,7 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) // something in this dictionary and crash? PyDict_Clear(excdict); Py_DECREF(excdict); - + m_triggeredSensors.erase(m_triggeredSensors.begin(), m_triggeredSensors.end()); m_sCurrentController = NULL; } @@ -318,7 +329,7 @@ PyObject* SCA_PythonController::PyGetActuators(PyObject* self) return resultlist; } -char SCA_PythonController::GetSensor_doc[] = +const char SCA_PythonController::GetSensor_doc[] = "GetSensor (char sensorname) return linked sensor that is named [sensorname]\n"; PyObject* SCA_PythonController::PyGetSensor(PyObject* self, PyObject* value) @@ -348,7 +359,7 @@ SCA_PythonController::PyGetSensor(PyObject* self, PyObject* value) -char SCA_PythonController::GetActuator_doc[] = +const char SCA_PythonController::GetActuator_doc[] = "GetActuator (char sensorname) return linked actuator that is named [actuatorname]\n"; PyObject* SCA_PythonController::PyGetActuator(PyObject* self, PyObject* value) @@ -377,7 +388,7 @@ SCA_PythonController::PyGetActuator(PyObject* self, PyObject* value) } -char SCA_PythonController::GetSensors_doc[] = "getSensors returns a list of all attached sensors"; +const char SCA_PythonController::GetSensors_doc[] = "getSensors returns a list of all attached sensors"; PyObject* SCA_PythonController::PyGetSensors(PyObject* self) { diff --git a/source/gameengine/GameLogic/SCA_PythonController.h b/source/gameengine/GameLogic/SCA_PythonController.h index 39b6c68c359..d9b2e242bea 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.h +++ b/source/gameengine/GameLogic/SCA_PythonController.h @@ -36,6 +36,8 @@ #include "SCA_LogicManager.h" #include "BoolValue.h" +#include <vector> + class SCA_IObject; class SCA_PythonController : public SCA_IController { @@ -47,6 +49,7 @@ class SCA_PythonController : public SCA_IController STR_String m_scriptText; STR_String m_scriptName; PyObject* m_pythondictionary; + std::vector<class SCA_ISensor*> m_triggeredSensors; public: static SCA_PythonController* m_sCurrentController; // protected !!! @@ -64,10 +67,13 @@ class SCA_PythonController : public SCA_IController void SetScriptText(const STR_String& text); void SetScriptName(const STR_String& name); void SetDictionary(PyObject* pythondictionary); + void AddTriggeredSensor(class SCA_ISensor* sensor) + { m_triggeredSensors.push_back(sensor); } + int IsTriggered(class SCA_ISensor* sensor); - static char* sPyGetCurrentController__doc__; + static const char* sPyGetCurrentController__doc__; static PyObject* sPyGetCurrentController(PyObject* self); - static char* sPyAddActiveActuator__doc__; + static const char* sPyAddActiveActuator__doc__; static PyObject* sPyAddActiveActuator(PyObject* self, PyObject* args); virtual PyObject* _getattr(const STR_String& attr); diff --git a/source/gameengine/GameLogic/SCA_RandomActuator.cpp b/source/gameengine/GameLogic/SCA_RandomActuator.cpp index 0a1ac2d0668..7b50a483cd8 100644 --- a/source/gameengine/GameLogic/SCA_RandomActuator.cpp +++ b/source/gameengine/GameLogic/SCA_RandomActuator.cpp @@ -339,23 +339,23 @@ PyParentObject SCA_RandomActuator::Parents[] = { }; PyMethodDef SCA_RandomActuator::Methods[] = { - {"setSeed", (PyCFunction) SCA_RandomActuator::sPySetSeed, METH_VARARGS, SetSeed_doc}, - {"getSeed", (PyCFunction) SCA_RandomActuator::sPyGetSeed, METH_VARARGS, GetSeed_doc}, - {"getPara1", (PyCFunction) SCA_RandomActuator::sPyGetPara1, METH_VARARGS, GetPara1_doc}, - {"getPara2", (PyCFunction) SCA_RandomActuator::sPyGetPara2, METH_VARARGS, GetPara2_doc}, - {"getDistribution", (PyCFunction) SCA_RandomActuator::sPyGetDistribution, METH_VARARGS, GetDistribution_doc}, - {"setProperty", (PyCFunction) SCA_RandomActuator::sPySetProperty, METH_VARARGS, SetProperty_doc}, - {"getProperty", (PyCFunction) SCA_RandomActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc}, - {"setBoolConst", (PyCFunction) SCA_RandomActuator::sPySetBoolConst, METH_VARARGS, SetBoolConst_doc}, - {"setBoolUniform", (PyCFunction) SCA_RandomActuator::sPySetBoolUniform, METH_VARARGS, SetBoolUniform_doc}, - {"setBoolBernouilli",(PyCFunction) SCA_RandomActuator::sPySetBoolBernouilli, METH_VARARGS, SetBoolBernouilli_doc}, - {"setIntConst", (PyCFunction) SCA_RandomActuator::sPySetIntConst, METH_VARARGS, SetIntConst_doc}, - {"setIntUniform", (PyCFunction) SCA_RandomActuator::sPySetIntUniform, METH_VARARGS, SetIntUniform_doc}, - {"setIntPoisson", (PyCFunction) SCA_RandomActuator::sPySetIntPoisson, METH_VARARGS, SetIntPoisson_doc}, - {"setFloatConst", (PyCFunction) SCA_RandomActuator::sPySetFloatConst, METH_VARARGS, SetFloatConst_doc}, - {"setFloatUniform", (PyCFunction) SCA_RandomActuator::sPySetFloatUniform, METH_VARARGS, SetFloatUniform_doc}, - {"setFloatNormal", (PyCFunction) SCA_RandomActuator::sPySetFloatNormal, METH_VARARGS, SetFloatNormal_doc}, - {"setFloatNegativeExponential", (PyCFunction) SCA_RandomActuator::sPySetFloatNegativeExponential, METH_VARARGS, SetFloatNegativeExponential_doc}, + {"setSeed", (PyCFunction) SCA_RandomActuator::sPySetSeed, METH_VARARGS, (PY_METHODCHAR)SetSeed_doc}, + {"getSeed", (PyCFunction) SCA_RandomActuator::sPyGetSeed, METH_VARARGS, (PY_METHODCHAR)GetSeed_doc}, + {"getPara1", (PyCFunction) SCA_RandomActuator::sPyGetPara1, METH_VARARGS, (PY_METHODCHAR)GetPara1_doc}, + {"getPara2", (PyCFunction) SCA_RandomActuator::sPyGetPara2, METH_VARARGS, (PY_METHODCHAR)GetPara2_doc}, + {"getDistribution", (PyCFunction) SCA_RandomActuator::sPyGetDistribution, METH_VARARGS, (PY_METHODCHAR)GetDistribution_doc}, + {"setProperty", (PyCFunction) SCA_RandomActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, + {"getProperty", (PyCFunction) SCA_RandomActuator::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, + {"setBoolConst", (PyCFunction) SCA_RandomActuator::sPySetBoolConst, METH_VARARGS, (PY_METHODCHAR)SetBoolConst_doc}, + {"setBoolUniform", (PyCFunction) SCA_RandomActuator::sPySetBoolUniform, METH_VARARGS, (PY_METHODCHAR)SetBoolUniform_doc}, + {"setBoolBernouilli",(PyCFunction) SCA_RandomActuator::sPySetBoolBernouilli, METH_VARARGS, (PY_METHODCHAR)SetBoolBernouilli_doc}, + {"setIntConst", (PyCFunction) SCA_RandomActuator::sPySetIntConst, METH_VARARGS, (PY_METHODCHAR)SetIntConst_doc}, + {"setIntUniform", (PyCFunction) SCA_RandomActuator::sPySetIntUniform, METH_VARARGS, (PY_METHODCHAR)SetIntUniform_doc}, + {"setIntPoisson", (PyCFunction) SCA_RandomActuator::sPySetIntPoisson, METH_VARARGS, (PY_METHODCHAR)SetIntPoisson_doc}, + {"setFloatConst", (PyCFunction) SCA_RandomActuator::sPySetFloatConst, METH_VARARGS, (PY_METHODCHAR)SetFloatConst_doc}, + {"setFloatUniform", (PyCFunction) SCA_RandomActuator::sPySetFloatUniform, METH_VARARGS, (PY_METHODCHAR)SetFloatUniform_doc}, + {"setFloatNormal", (PyCFunction) SCA_RandomActuator::sPySetFloatNormal, METH_VARARGS, (PY_METHODCHAR)SetFloatNormal_doc}, + {"setFloatNegativeExponential", (PyCFunction) SCA_RandomActuator::sPySetFloatNegativeExponential, METH_VARARGS, (PY_METHODCHAR)SetFloatNegativeExponential_doc}, {NULL,NULL} //Sentinel }; @@ -364,7 +364,7 @@ PyObject* SCA_RandomActuator::_getattr(const STR_String& attr) { } /* 1. setSeed */ -char SCA_RandomActuator::SetSeed_doc[] = +const char SCA_RandomActuator::SetSeed_doc[] = "setSeed(seed)\n" "\t- seed: integer\n" "\tSet the initial seed of the generator. Equal seeds produce\n" @@ -381,7 +381,7 @@ PyObject* SCA_RandomActuator::PySetSeed(PyObject* self, PyObject* args, PyObject Py_Return; } /* 2. getSeed */ -char SCA_RandomActuator::GetSeed_doc[] = +const char SCA_RandomActuator::GetSeed_doc[] = "getSeed()\n" "\tReturns the initial seed of the generator. Equal seeds produce\n" "\tequal series.\n"; @@ -390,7 +390,7 @@ PyObject* SCA_RandomActuator::PyGetSeed(PyObject* self, PyObject* args, PyObject } /* 4. getPara1 */ -char SCA_RandomActuator::GetPara1_doc[] = +const char SCA_RandomActuator::GetPara1_doc[] = "getPara1()\n" "\tReturns the first parameter of the active distribution. Refer\n" "\tto the documentation of the generator types for the meaning\n" @@ -400,7 +400,7 @@ PyObject* SCA_RandomActuator::PyGetPara1(PyObject* self, PyObject* args, PyObjec } /* 6. getPara2 */ -char SCA_RandomActuator::GetPara2_doc[] = +const char SCA_RandomActuator::GetPara2_doc[] = "getPara2()\n" "\tReturns the first parameter of the active distribution. Refer\n" "\tto the documentation of the generator types for the meaning\n" @@ -410,7 +410,7 @@ PyObject* SCA_RandomActuator::PyGetPara2(PyObject* self, PyObject* args, PyObjec } /* 8. getDistribution */ -char SCA_RandomActuator::GetDistribution_doc[] = +const char SCA_RandomActuator::GetDistribution_doc[] = "getDistribution()\n" "\tReturns the type of the active distribution.\n"; PyObject* SCA_RandomActuator::PyGetDistribution(PyObject* self, PyObject* args, PyObject* kwds) { @@ -418,7 +418,7 @@ PyObject* SCA_RandomActuator::PyGetDistribution(PyObject* self, PyObject* args, } /* 9. setProperty */ -char SCA_RandomActuator::SetProperty_doc[] = +const char SCA_RandomActuator::SetProperty_doc[] = "setProperty(name)\n" "\t- name: string\n" "\tSet the property to which the random value is assigned. If the \n" @@ -441,7 +441,7 @@ PyObject* SCA_RandomActuator::PySetProperty(PyObject* self, PyObject* args, PyOb Py_Return; } /* 10. getProperty */ -char SCA_RandomActuator::GetProperty_doc[] = +const char SCA_RandomActuator::GetProperty_doc[] = "getProperty(name)\n" "\tReturn the property to which the random value is assigned. If the \n" "\tgenerator and property types do not match, the assignment is ignored.\n"; @@ -450,7 +450,7 @@ PyObject* SCA_RandomActuator::PyGetProperty(PyObject* self, PyObject* args, PyOb } /* 11. setBoolConst */ -char SCA_RandomActuator::SetBoolConst_doc[] = +const char SCA_RandomActuator::SetBoolConst_doc[] = "setBoolConst(value)\n" "\t- value: 0 or 1\n" "\tSet this generator to produce a constant boolean value.\n"; @@ -470,7 +470,7 @@ PyObject* SCA_RandomActuator::PySetBoolConst(PyObject* self, Py_Return; } /* 12. setBoolUniform, */ -char SCA_RandomActuator::SetBoolUniform_doc[] = +const char SCA_RandomActuator::SetBoolUniform_doc[] = "setBoolUniform()\n" "\tSet this generator to produce true and false, each with 50%% chance of occuring\n"; PyObject* SCA_RandomActuator::PySetBoolUniform(PyObject* self, @@ -482,7 +482,7 @@ PyObject* SCA_RandomActuator::PySetBoolUniform(PyObject* self, Py_Return; } /* 13. setBoolBernouilli, */ -char SCA_RandomActuator::SetBoolBernouilli_doc[] = +const char SCA_RandomActuator::SetBoolBernouilli_doc[] = "setBoolBernouilli(value)\n" "\t- value: a float between 0 and 1\n" "\tReturn false value * 100%% of the time.\n"; @@ -500,7 +500,7 @@ PyObject* SCA_RandomActuator::PySetBoolBernouilli(PyObject* self, Py_Return; } /* 14. setIntConst,*/ -char SCA_RandomActuator::SetIntConst_doc[] = +const char SCA_RandomActuator::SetIntConst_doc[] = "setIntConst(value)\n" "\t- value: integer\n" "\tAlways return value\n"; @@ -518,7 +518,7 @@ PyObject* SCA_RandomActuator::PySetIntConst(PyObject* self, Py_Return; } /* 15. setIntUniform,*/ -char SCA_RandomActuator::SetIntUniform_doc[] = +const char SCA_RandomActuator::SetIntUniform_doc[] = "setIntUniform(lower_bound, upper_bound)\n" "\t- lower_bound: integer\n" "\t- upper_bound: integer\n" @@ -539,7 +539,7 @@ PyObject* SCA_RandomActuator::PySetIntUniform(PyObject* self, Py_Return; } /* 16. setIntPoisson, */ -char SCA_RandomActuator::SetIntPoisson_doc[] = +const char SCA_RandomActuator::SetIntPoisson_doc[] = "setIntPoisson(value)\n" "\t- value: float\n" "\tReturn a Poisson-distributed number. This performs a series\n" @@ -559,7 +559,7 @@ PyObject* SCA_RandomActuator::PySetIntPoisson(PyObject* self, Py_Return; } /* 17. setFloatConst,*/ -char SCA_RandomActuator::SetFloatConst_doc[] = +const char SCA_RandomActuator::SetFloatConst_doc[] = "setFloatConst(value)\n" "\t- value: float\n" "\tAlways return value\n"; @@ -577,7 +577,7 @@ PyObject* SCA_RandomActuator::PySetFloatConst(PyObject* self, Py_Return; } /* 18. setFloatUniform, */ -char SCA_RandomActuator::SetFloatUniform_doc[] = +const char SCA_RandomActuator::SetFloatUniform_doc[] = "setFloatUniform(lower_bound, upper_bound)\n" "\t- lower_bound: float\n" "\t- upper_bound: float\n" @@ -598,7 +598,7 @@ PyObject* SCA_RandomActuator::PySetFloatUniform(PyObject* self, Py_Return; } /* 19. setFloatNormal, */ -char SCA_RandomActuator::SetFloatNormal_doc[] = +const char SCA_RandomActuator::SetFloatNormal_doc[] = "setFloatNormal(mean, standard_deviation)\n" "\t- mean: float\n" "\t- standard_deviation: float\n" @@ -619,7 +619,7 @@ PyObject* SCA_RandomActuator::PySetFloatNormal(PyObject* self, Py_Return; } /* 20. setFloatNegativeExponential, */ -char SCA_RandomActuator::SetFloatNegativeExponential_doc[] = +const char SCA_RandomActuator::SetFloatNegativeExponential_doc[] = "setFloatNegativeExponential(half_life)\n" "\t- half_life: float\n" "\tReturn negative-exponentially distributed numbers. The half-life 'time'\n" diff --git a/source/gameengine/GameLogic/SCA_RandomSensor.cpp b/source/gameengine/GameLogic/SCA_RandomSensor.cpp index 3626522e49a..202fd6382e6 100644 --- a/source/gameengine/GameLogic/SCA_RandomSensor.cpp +++ b/source/gameengine/GameLogic/SCA_RandomSensor.cpp @@ -154,9 +154,9 @@ PyParentObject SCA_RandomSensor::Parents[] = { }; PyMethodDef SCA_RandomSensor::Methods[] = { - {"setSeed", (PyCFunction) SCA_RandomSensor::sPySetSeed, METH_VARARGS, SetSeed_doc}, - {"getSeed", (PyCFunction) SCA_RandomSensor::sPyGetSeed, METH_VARARGS, GetSeed_doc}, - {"getLastDraw", (PyCFunction) SCA_RandomSensor::sPyGetLastDraw, METH_VARARGS, GetLastDraw_doc}, + {"setSeed", (PyCFunction) SCA_RandomSensor::sPySetSeed, METH_VARARGS, (PY_METHODCHAR)SetSeed_doc}, + {"getSeed", (PyCFunction) SCA_RandomSensor::sPyGetSeed, METH_VARARGS, (PY_METHODCHAR)GetSeed_doc}, + {"getLastDraw", (PyCFunction) SCA_RandomSensor::sPyGetLastDraw, METH_VARARGS, (PY_METHODCHAR)GetLastDraw_doc}, {NULL,NULL} //Sentinel }; @@ -165,7 +165,7 @@ PyObject* SCA_RandomSensor::_getattr(const STR_String& attr) { } /* 1. setSeed */ -char SCA_RandomSensor::SetSeed_doc[] = +const char SCA_RandomSensor::SetSeed_doc[] = "setSeed(seed)\n" "\t- seed: integer\n" "\tSet the initial seed of the generator. Equal seeds produce\n" @@ -183,7 +183,7 @@ PyObject* SCA_RandomSensor::PySetSeed(PyObject* self, PyObject* args, PyObject* } /* 2. getSeed */ -char SCA_RandomSensor::GetSeed_doc[] = +const char SCA_RandomSensor::GetSeed_doc[] = "getSeed()\n" "\tReturns the initial seed of the generator. Equal seeds produce\n" "\tequal series.\n"; @@ -192,7 +192,7 @@ PyObject* SCA_RandomSensor::PyGetSeed(PyObject* self, PyObject* args, PyObject* } /* 3. getLastDraw */ -char SCA_RandomSensor::GetLastDraw_doc[] = +const char SCA_RandomSensor::GetLastDraw_doc[] = "getLastDraw()\n" "\tReturn the last value that was drawn.\n"; PyObject* SCA_RandomSensor::PyGetLastDraw(PyObject* self, PyObject* args, PyObject* kwds) { diff --git a/source/gameengine/GameLogic/SConscript b/source/gameengine/GameLogic/SConscript index 1ca884f6dec..fa5a3123215 100644 --- a/source/gameengine/GameLogic/SConscript +++ b/source/gameengine/GameLogic/SConscript @@ -10,4 +10,9 @@ incs += ' #/source/gameengine/Rasterizer' incs += ' ' + env['BF_PYTHON_INC'] incs += ' ' + env['BF_SDL_INC'] -env.BlenderLib ( 'bf_logic', sources, Split(incs), [], libtype=['game','player'], priority=[30, 110] ) +defs = '' + +if not env['WITH_BF_SDL']: + defs += ' DISABLE_SDL' + +env.BlenderLib ( 'bf_logic', sources, Split(incs), Split(defs), libtype=['game','player'], priority=[30, 110] ) diff --git a/source/gameengine/GamePlayer/CMakeLists.txt b/source/gameengine/GamePlayer/CMakeLists.txt index ff1040bfb40..fc5912155cf 100644 --- a/source/gameengine/GamePlayer/CMakeLists.txt +++ b/source/gameengine/GamePlayer/CMakeLists.txt @@ -25,3 +25,7 @@ # ***** END GPL LICENSE BLOCK ***** SUBDIRS(common ghost) + +IF(WITH_WEBPLUGIN) + SUBDIRS(xembed) +ENDIF(WITH_WEBPLUGIN) diff --git a/source/gameengine/GamePlayer/common/CMakeLists.txt b/source/gameengine/GamePlayer/common/CMakeLists.txt index e26f8b9d69a..0c6c4179e2d 100644 --- a/source/gameengine/GamePlayer/common/CMakeLists.txt +++ b/source/gameengine/GamePlayer/common/CMakeLists.txt @@ -30,7 +30,6 @@ SET(SRC GPC_Engine.cpp GPC_KeyboardDevice.cpp GPC_MouseDevice.cpp - GPC_PolygonMaterial.cpp GPC_RawImage.cpp GPC_RawLoadDotBlendArray.cpp GPC_RawLogoArrays.cpp @@ -69,6 +68,7 @@ SET(INC ../../../../source/gameengine/GamePlayer/ghost ../../../../source/blender/misc ../../../../source/blender/blenloader + ../../../../source/blender/gpu ../../../../extern/glew/include ${PYTHON_INC} ${SOLID_INC} diff --git a/source/gameengine/GamePlayer/common/GPC_RawImage.cpp b/source/gameengine/GamePlayer/common/GPC_RawImage.cpp index a9cfb0a9366..e6e97cbdfd3 100644 --- a/source/gameengine/GamePlayer/common/GPC_RawImage.cpp +++ b/source/gameengine/GamePlayer/common/GPC_RawImage.cpp @@ -45,7 +45,7 @@ GPC_RawImage::GPC_RawImage() bool GPC_RawImage::Load( - char *srcName, + const char *srcName, int destWidth, int destHeight, TImageAlignment alignment, int offsetX, int offsetY) { diff --git a/source/gameengine/GamePlayer/common/GPC_RawImage.h b/source/gameengine/GamePlayer/common/GPC_RawImage.h index 17c00d2fcc3..49a3043bffc 100644 --- a/source/gameengine/GamePlayer/common/GPC_RawImage.h +++ b/source/gameengine/GamePlayer/common/GPC_RawImage.h @@ -61,7 +61,7 @@ public: * @param offsetX Amount of horzontal offset applied to the resource image. * @param offsetY Amount of vertical offset applied to the resource image. */ - virtual bool Load(char *srcName, + virtual bool Load(const char *srcName, int destWidth, int destHeight, TImageAlignment alignment = alignTopLeft, int offsetX = 0, int offsetY = 0); diff --git a/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp b/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp index 8b828393c67..78d8eaf2aa3 100644 --- a/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp +++ b/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp @@ -27,141 +27,256 @@ * ***** END GPL LICENSE BLOCK ***** */ -#include <assert.h> - -#ifdef WIN32 -#pragma warning (disable : 4786) -#include <windows.h> -#endif - #include "GL/glew.h" -#include <iostream> - -#include "GPC_RenderTools.h" - #include "RAS_IRenderTools.h" #include "RAS_IRasterizer.h" #include "RAS_LightObject.h" #include "RAS_ICanvas.h" #include "RAS_GLExtensionManager.h" -// next two includes/dependencies come from the shadow feature -// it needs the gameobject and the sumo physics scene for a raycast #include "KX_GameObject.h" - -#include "GPC_PolygonMaterial.h" #include "KX_PolygonMaterial.h" -#include "Value.h" +#include "KX_BlenderMaterial.h" +#include "KX_RayCast.h" +#include "KX_IPhysicsController.h" + +#include "PHY_IPhysicsEnvironment.h" -//#include "KX_BlenderGL.h" // for text printing -//#include "KX_BlenderClientObject.h" #include "STR_String.h" -#include "RAS_BucketManager.h" // for polymaterial (needed for textprinting) - - -// Blender includes -/* This list includes only data type definitions */ -#include "DNA_object_types.h" -#include "DNA_material_types.h" -#include "DNA_image_types.h" -#include "DNA_lamp_types.h" -#include "DNA_group_types.h" -#include "DNA_scene_types.h" -#include "DNA_camera_types.h" -#include "DNA_property_types.h" -#include "DNA_text_types.h" -#include "DNA_sensor_types.h" -#include "DNA_controller_types.h" -#include "DNA_actuator_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_view3d_types.h" -#include "DNA_world_types.h" - -#include "BKE_global.h" -#include "BKE_image.h" -#include "BKE_bmfont.h" + +#include "GPU_draw.h" + +#include "BKE_bmfont.h" // for text printing #include "BKE_bmfont_types.h" -#include "BKE_main.h" -#include "IMB_imbuf_types.h" -// End of Blender includes +#include "GPC_RenderTools.h" -#include "KX_Scene.h" -#include "KX_RayCast.h" -#include "KX_IPhysicsController.h" -#include "PHY_IPhysicsEnvironment.h" -#include "KX_BlenderMaterial.h" +unsigned int GPC_RenderTools::m_numgllights; GPC_RenderTools::GPC_RenderTools() { m_font = BMF_GetFont(BMF_kHelvetica10); + glGetIntegerv(GL_MAX_LIGHTS, (GLint*) &m_numgllights); if (m_numgllights < 8) m_numgllights = 8; } - GPC_RenderTools::~GPC_RenderTools() { } +void GPC_RenderTools::BeginFrame(RAS_IRasterizer* rasty) +{ + m_clientobject = NULL; + m_lastlightlayer = -1; + m_lastlighting = false; + DisableOpenGLLights(); +} void GPC_RenderTools::EndFrame(RAS_IRasterizer* rasty) { } +/* ProcessLighting performs lighting on objects. the layer is a bitfield that + * contains layer information. There are 20 'official' layers in blender. A + * light is applied on an object only when they are in the same layer. OpenGL + * has a maximum of 8 lights (simultaneous), so 20 * 8 lights are possible in + * a scene. */ -void GPC_RenderTools::BeginFrame(RAS_IRasterizer* rasty) +void GPC_RenderTools::ProcessLighting(int layer, const MT_Transform& viewmat) { - m_clientobject=NULL; - m_modified=true; - DisableOpenGLLights(); + if(m_lastlightlayer == layer) + return; -} + m_lastlightlayer = layer; -int GPC_RenderTools::ProcessLighting(int layer) -{ - int result = false; + bool enable = false; - if (layer < 0) - { - DisableOpenGLLights(); - result = false; - } else + if (layer >= 0) { if (m_clientobject) - { - if (applyLights(layer)) - { - EnableOpenGLLights(); - result = true; - } else - { - DisableOpenGLLights(); - result = false; - } + { + if (layer == RAS_LIGHT_OBJECT_LAYER) + layer = static_cast<KX_GameObject*>(m_clientobject)->GetLayer(); + + enable = applyLights(layer, viewmat); } } - return result; + + if(enable) + EnableOpenGLLights(); + else + DisableOpenGLLights(); } void GPC_RenderTools::EnableOpenGLLights() { + if(m_lastlighting == true) + return; + glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); - glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE); + + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, true); if (GLEW_EXT_separate_specular_color || GLEW_VERSION_1_2) glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); + + m_lastlighting = true; +} + +void GPC_RenderTools::DisableOpenGLLights() +{ + if(m_lastlighting == false) + return; + + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + + m_lastlighting = false; +} + + +void GPC_RenderTools::SetClientObject(RAS_IRasterizer *rasty, void* obj) +{ + if (m_clientobject != obj) + { + bool ccw = (obj == NULL || !((KX_GameObject*)obj)->IsNegativeScaling()); + rasty->SetFrontFace(ccw); + + m_clientobject = obj; + } +} + +bool GPC_RenderTools::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) +{ + double* const oglmatrix = (double* const) data; + MT_Point3 resultpoint(result->m_hitPoint); + MT_Vector3 resultnormal(result->m_hitNormal); + MT_Vector3 left(oglmatrix[0],oglmatrix[1],oglmatrix[2]); + MT_Vector3 dir = -(left.cross(resultnormal)).safe_normalized(); + left = (dir.cross(resultnormal)).safe_normalized(); + // for the up vector, we take the 'resultnormal' returned by the physics + + double maat[16]={ + left[0], left[1], left[2], 0, + dir[0], dir[1], dir[2], 0, + resultnormal[0],resultnormal[1],resultnormal[2], 0, + 0, 0, 0, 1}; + glTranslated(resultpoint[0],resultpoint[1],resultpoint[2]); + //glMultMatrixd(oglmatrix); + glMultMatrixd(maat); + return true; } -void GPC_RenderTools::RenderText2D(RAS_TEXT_RENDER_MODE mode, - const char* text, - int xco, - int yco, - int width, - int height) +void GPC_RenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmatrix,int objectdrawmode ) +{ + /* FIXME: + blender: intern/moto/include/MT_Vector3.inl:42: MT_Vector3 operator/(const + MT_Vector3&, double): Assertion `!MT_fuzzyZero(s)' failed. + + Program received signal SIGABRT, Aborted. + [Switching to Thread 16384 (LWP 1519)] + 0x40477571 in kill () from /lib/libc.so.6 + (gdb) bt + #7 0x08334368 in MT_Vector3::normalized() const () + #8 0x0833e6ec in GPC_RenderTools::applyTransform(RAS_IRasterizer*, double*, int) () + */ + + if (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED || + objectdrawmode & RAS_IPolyMaterial::BILLBOARD_AXISALIGNED) + { + // rotate the billboard/halo + //page 360/361 3D Game Engine Design, David Eberly for a discussion + // on screen aligned and axis aligned billboards + // assumed is that the preprocessor transformed all billboard polygons + // so that their normal points into the positive x direction (1.0 , 0.0 , 0.0) + // when new parenting for objects is done, this rotation + // will be moved into the object + + MT_Point3 objpos (oglmatrix[12],oglmatrix[13],oglmatrix[14]); + MT_Point3 campos = rasty->GetCameraPosition(); + MT_Vector3 dir = (campos - objpos).safe_normalized(); + MT_Vector3 up(0,0,1.0); + + KX_GameObject* gameobj = (KX_GameObject*) this->m_clientobject; + // get scaling of halo object + MT_Vector3 size = gameobj->GetSGNode()->GetLocalScale(); + + bool screenaligned = (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED)!=0;//false; //either screen or axisaligned + if (screenaligned) + { + up = (up - up.dot(dir) * dir).safe_normalized(); + } else + { + dir = (dir - up.dot(dir)*up).safe_normalized(); + } + + MT_Vector3 left = dir.normalized(); + dir = (left.cross(up)).normalized(); + + // we have calculated the row vectors, now we keep + // local scaling into account: + + left *= size[0]; + dir *= size[1]; + up *= size[2]; + double maat[16]={ + left[0], left[1],left[2], 0, + dir[0], dir[1],dir[2],0, + up[0],up[1],up[2],0, + 0,0,0,1}; + glTranslated(objpos[0],objpos[1],objpos[2]); + glMultMatrixd(maat); + + } else + { + if (objectdrawmode & RAS_IPolyMaterial::SHADOW) + { + // shadow must be cast to the ground, physics system needed here! + MT_Point3 frompoint(oglmatrix[12],oglmatrix[13],oglmatrix[14]); + KX_GameObject *gameobj = (KX_GameObject*) this->m_clientobject; + MT_Vector3 direction = MT_Vector3(0,0,-1); + + direction.normalize(); + direction *= 100000; + + MT_Point3 topoint = frompoint + direction; + + KX_Scene* kxscene = (KX_Scene*) m_auxilaryClientInfo; + PHY_IPhysicsEnvironment* physics_environment = kxscene->GetPhysicsEnvironment(); + KX_IPhysicsController* physics_controller = gameobj->GetPhysicsController(); + + KX_GameObject *parent = gameobj->GetParent(); + if (!physics_controller && parent) + physics_controller = parent->GetPhysicsController(); + if (parent) + parent->Release(); + + KX_RayCast::Callback<GPC_RenderTools> callback(this, physics_controller, oglmatrix); + if (!KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback)) + { + // couldn't find something to cast the shadow on... + glMultMatrixd(oglmatrix); + } + } else + { + + // 'normal' object + glMultMatrixd(oglmatrix); + } + } +} + + +void GPC_RenderTools::RenderText2D(RAS_TEXT_RENDER_MODE mode, + const char* text, + int xco, + int yco, + int width, + int height) { STR_String tmpstr(text); int lines; @@ -234,21 +349,19 @@ void GPC_RenderTools::RenderText2D(RAS_TEXT_RENDER_MODE mode, glDisable(GL_LIGHTING); } -/** - * Copied from KX_BlenderRenderTools.cpp in KX_blenderhook - * Renders text into a (series of) polygon(s), using a texture font, - * Each character consists of one polygon (one quad or two triangles) - */ +/* Render Text renders text into a (series of) polygon, using a texture font, + * Each character consists of one polygon (one quad or two triangles) */ + void GPC_RenderTools::RenderText( int mode, RAS_IPolyMaterial* polymat, - float v1[3], float v2[3], float v3[3], float v4[3]) + float v1[3], float v2[3], float v3[3], float v4[3], int glattrib) { STR_String mytext = ((CValue*)m_clientobject)->GetPropertyText("Text"); const unsigned int flag = polymat->GetFlag(); struct MTFace* tface = 0; - unsigned int* col = 0; + unsigned int *col = 0; if(flag & RAS_BLENDERMAT) { KX_BlenderMaterial *bl_mat = static_cast<KX_BlenderMaterial*>(polymat); @@ -259,110 +372,29 @@ void GPC_RenderTools::RenderText( tface = blenderpoly->GetMTFace(); col = blenderpoly->GetMCol(); } - - BL_RenderText(mode, mytext, mytext.Length(), tface, col, v1, v2, v3, v4); + + GPU_render_text(tface, mode, mytext, mytext.Length(), col, v1, v2, v3, v4, glattrib); } - -/** - * Copied from KX_BlenderGL.cpp in KX_blenderhook - */ -void GPC_RenderTools::BL_RenderText( - int mode, - const char* textstr, - int textlen, - struct MTFace* tface, - unsigned int* col, - float v1[3],float v2[3],float v3[3],float v4[3]) +void GPC_RenderTools::PushMatrix() { - struct Image* ima; - - if (mode & TF_BMFONT) { - //char string[MAX_PROPSTRING]; -// float tmat[4][4]; - int characters, index, character; - float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance; - -// bProperty *prop; - - // string = "Frank van Beek"; - - characters = textlen; - - ima = (struct Image*) tface->tpage; - if (ima == NULL) { - characters = 0; - } - - if(!col) glColor3f(1.0f, 1.0f, 1.0f); - - glPushMatrix(); - for (index = 0; index < characters; index++) { - // lets calculate offset stuff - character = textstr[index]; - - // space starts at offset 1 - // character = character - ' ' + 1; - - matrixGlyph((ImBuf *)ima->ibufs.first, character, & centerx, ¢ery, &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); - - glBegin(GL_POLYGON); - // printf(" %c %f %f %f %f\n", character, tface->uv[0][0], tface->uv[0][1], ); - // glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy); - glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy); - - if(col) BL_spack(col[0]); - // glVertex3fv(v1); - glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]); - - glTexCoord2f((tface->uv[1][0] - centerx) * sizex + transx, (tface->uv[1][1] - centery) * sizey + transy); - if(col) BL_spack(col[1]); - // glVertex3fv(v2); - glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]); - - glTexCoord2f((tface->uv[2][0] - centerx) * sizex + transx, (tface->uv[2][1] - centery) * sizey + transy); - if(col) BL_spack(col[2]); - // glVertex3fv(v3); - glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]); - - if(v4) { - // glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, 1.0 - (1.0 - tface->uv[3][1]) * sizey - transy); - glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, (tface->uv[3][1] - centery) * sizey + transy); - if(col) BL_spack(col[3]); - // glVertex3fv(v4); - glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]); - } - glEnd(); - - glTranslatef(advance, 0.0, 0.0); - } - glPopMatrix(); - - } + glPushMatrix(); } - -RAS_IPolyMaterial* GPC_RenderTools::CreateBlenderPolyMaterial( - const STR_String &texname, - bool ba,const STR_String& matname,int tile,int tilexrep,int tileyrep,int mode,bool transparant, bool zsort, - int lightlayer,bool bIsTriangle,void* clientobject,void* tface) +void GPC_RenderTools::PopMatrix() { - assert(!"Deprecated"); -/* return new GPC_PolygonMaterial(texname, ba,matname,tile,tilexrep,tileyrep, - mode,transparant,zsort,lightlayer,bIsTriangle,clientobject,tface); - */ - return NULL; + glPopMatrix(); } -int GPC_RenderTools::applyLights(int objectlayer) +int GPC_RenderTools::applyLights(int objectlayer, const MT_Transform& viewmat) { -// taken from blender source, incompatibility between Blender Object / GameObject - - int count; + // taken from blender source, incompatibility between Blender Object / GameObject + float glviewmat[16]; + unsigned int count; float vec[4]; - + vec[3]= 1.0; for(count=0; count<m_numgllights; count++) @@ -371,23 +403,20 @@ int GPC_RenderTools::applyLights(int objectlayer) //std::vector<struct RAS_LightObject*> m_lights; std::vector<struct RAS_LightObject*>::iterator lit = m_lights.begin(); + viewmat.getValue(glviewmat); + glPushMatrix(); + glLoadMatrixf(glviewmat); for (lit = m_lights.begin(), count = 0; !(lit==m_lights.end()) && count < m_numgllights; ++lit) { RAS_LightObject* lightdata = (*lit); if (lightdata->m_layer & objectlayer) { - - glPushMatrix(); - glLoadMatrixf(m_viewmat); - - vec[0] = (*(lightdata->m_worldmatrix))(0,3); vec[1] = (*(lightdata->m_worldmatrix))(1,3); vec[2] = (*(lightdata->m_worldmatrix))(2,3); vec[3] = 1; - if(lightdata->m_type==RAS_LightObject::LIGHT_SUN) { vec[0] = (*(lightdata->m_worldmatrix))(0,2); @@ -443,142 +472,16 @@ int GPC_RenderTools::applyLights(int objectlayer) } glLightfv((GLenum)(GL_LIGHT0+count), GL_SPECULAR, vec); glEnable((GLenum)(GL_LIGHT0+count)); - - count++; - glPopMatrix(); + count++; } } + glPopMatrix(); return count; } -void GPC_RenderTools::SetClientObject(void* obj) -{ - if (m_clientobject != obj) - { - if (obj == NULL || !((KX_GameObject*)obj)->IsNegativeScaling()) - { - glFrontFace(GL_CCW); - } else - { - glFrontFace(GL_CW); - } - m_clientobject = obj; - m_modified = true; - } -} - -bool GPC_RenderTools::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) -{ - double* const oglmatrix = (double* const) data; - MT_Point3 resultpoint(hit_point); - MT_Vector3 resultnormal(hit_normal); - MT_Vector3 left(oglmatrix[0],oglmatrix[1],oglmatrix[2]); - MT_Vector3 dir = -(left.cross(resultnormal)).safe_normalized(); - left = (dir.cross(resultnormal)).safe_normalized(); - // for the up vector, we take the 'resultnormal' returned by the physics - - double maat[16]={ - left[0], left[1], left[2], 0, - dir[0], dir[1], dir[2], 0, - resultnormal[0],resultnormal[1],resultnormal[2], 0, - 0, 0, 0, 1}; - glTranslated(resultpoint[0],resultpoint[1],resultpoint[2]); - //glMultMatrixd(oglmatrix); - glMultMatrixd(maat); - return true; -} - -void GPC_RenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmatrix,int objectdrawmode ) -{ - if (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED || - objectdrawmode & RAS_IPolyMaterial::BILLBOARD_AXISALIGNED) - { - // rotate the billboard/halo - //page 360/361 3D Game Engine Design, David Eberly for a discussion - // on screen aligned and axis aligned billboards - // assumed is that the preprocessor transformed all billboard polygons - // so that their normal points into the positive x direction (1.0 , 0.0 , 0.0) - // when new parenting for objects is done, this rotation - // will be moved into the object - - MT_Point3 objpos (oglmatrix[12],oglmatrix[13],oglmatrix[14]); - MT_Point3 campos = rasty->GetCameraPosition(); - MT_Vector3 dir = (campos - objpos).safe_normalized(); - MT_Vector3 up(0,0,1.0); - - KX_GameObject* gameobj = (KX_GameObject*) this->m_clientobject; - // get scaling of halo object - MT_Vector3 size = gameobj->GetSGNode()->GetLocalScale(); - - bool screenaligned = (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED)!=0;//false; //either screen or axisaligned - if (screenaligned) - { - up = (up - up.dot(dir) * dir).safe_normalized(); - } else - { - dir = (dir - up.dot(dir)*up).safe_normalized(); - } - - MT_Vector3 left = dir.normalized(); - dir = (left.cross(up)).normalized(); - - // we have calculated the row vectors, now we keep - // local scaling into account: - - left *= size[0]; - dir *= size[1]; - up *= size[2]; - double maat[16]={ - left[0], left[1],left[2], 0, - dir[0], dir[1],dir[2],0, - up[0],up[1],up[2],0, - 0,0,0,1}; - glTranslated(objpos[0],objpos[1],objpos[2]); - glMultMatrixd(maat); - - } else - { - if (objectdrawmode & RAS_IPolyMaterial::SHADOW) - { - // shadow must be cast to the ground, physics system needed here! - MT_Point3 frompoint(oglmatrix[12],oglmatrix[13],oglmatrix[14]); - KX_GameObject *gameobj = (KX_GameObject*) this->m_clientobject; - MT_Vector3 direction = MT_Vector3(0,0,-1); - - direction.normalize(); - direction *= 100000; - - MT_Point3 topoint = frompoint + direction; - - KX_Scene* kxscene = (KX_Scene*) m_auxilaryClientInfo; - PHY_IPhysicsEnvironment* physics_environment = kxscene->GetPhysicsEnvironment(); - KX_IPhysicsController* physics_controller = gameobj->GetPhysicsController(); - - KX_GameObject *parent = gameobj->GetParent(); - if (!physics_controller && parent) - physics_controller = parent->GetPhysicsController(); - if (parent) - parent->Release(); - - MT_Point3 resultpoint; - MT_Vector3 resultnormal; - if (!KX_RayCast::RayTest(physics_controller, physics_environment, frompoint, topoint, resultpoint, resultnormal, KX_RayCast::Callback<GPC_RenderTools>(this, oglmatrix))) - { - // couldn't find something to cast the shadow on... - glMultMatrixd(oglmatrix); - } - } else - { - - // 'normal' object - glMultMatrixd(oglmatrix); - } - } -} - void GPC_RenderTools::MotionBlur(RAS_IRasterizer* rasterizer) { int state = rasterizer->GetMotionBlurState(); @@ -609,7 +512,6 @@ void GPC_RenderTools::Update2DFilter(vector<STR_String>& propNames, void* gameOb void GPC_RenderTools::Render2DFilters(RAS_ICanvas* canvas) { - m_filtermanager.RenderFilters( canvas); + m_filtermanager.RenderFilters(canvas); } -unsigned int GPC_RenderTools::m_numgllights; diff --git a/source/gameengine/GamePlayer/common/GPC_RenderTools.h b/source/gameengine/GamePlayer/common/GPC_RenderTools.h index 8fae3d2b305..382956e73ea 100644 --- a/source/gameengine/GamePlayer/common/GPC_RenderTools.h +++ b/source/gameengine/GamePlayer/common/GPC_RenderTools.h @@ -31,114 +31,67 @@ #define __GPC_RENDERTOOLS_H #ifdef WIN32 - #include <windows.h> +// don't show stl-warnings +#pragma warning (disable:4786) +#include <windows.h> #endif // WIN32 -#include "GL/glew.h" - #include "RAS_IRenderTools.h" #include "BMF_Api.h" struct KX_ClientObjectInfo; +class KX_RayCast; +/* BlenderRenderTools are a set of tools to apply 2D/3D graphics effects, which + * are not part of the (polygon) Rasterizer. Effects like 2D text, 3D (polygon) + * text, lighting. + * + * Most of this code is duplicated in KX_BlenderRenderTools, so this should be + * moved to some common location to avoid duplication. */ class GPC_RenderTools : public RAS_IRenderTools { + int m_lastlightlayer; + bool m_lastlighting; + static unsigned int m_numgllights; + + BMF_Font* m_font; + public: - GPC_RenderTools(); - virtual ~GPC_RenderTools(); - - virtual void EndFrame(RAS_IRasterizer* rasty); - virtual void BeginFrame(RAS_IRasterizer* rasty); - - void DisableOpenGLLights() - { - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - } - - void EnableOpenGLLights(); - - int ProcessLighting(int layer); - - void Perspective(int a, int width, int height, float mat[4][4], float viewmat[4][4]) - { - if(a== 0) - { - glMatrixMode(GL_PROJECTION); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - } - else - { - if(a== 1) - { - glMatrixMode(GL_PROJECTION); - glMatrixMode(GL_MODELVIEW); - } - } - } - - /** - * @attention mode is ignored here - */ - virtual void RenderText2D( - RAS_TEXT_RENDER_MODE mode, - const char* text, - int xco, - int yco, - int width, - int height); - - /** - * Renders text into a (series of) polygon(s), using a texture font, - * Each character consists of one polygon (one quad or two triangles) - */ - virtual void RenderText( - int mode, - RAS_IPolyMaterial* polymat, - float v1[3], - float v2[3], - float v3[3], - float v4[3]); - - void Render(RAS_IRasterizer* rasty,double* oglmatrix,int objectdrawmode) - { - glPopMatrix(); - glPushMatrix(); - glMultMatrixd(oglmatrix); - } - - void applyTransform(RAS_IRasterizer* rasty, double* oglmatrix, int objectdrawmode); - - virtual void PushMatrix() - { - glPushMatrix(); - } - - virtual void PopMatrix() - { - glPopMatrix(); - } - - virtual class RAS_IPolyMaterial* CreateBlenderPolyMaterial( - const STR_String &texname, - bool ba, - const STR_String& matname, - int tile, - int tilexrep,int tileyrep, - int mode, - bool transparant, - bool zsort, - int lightlayer, - bool bIsTriangle, - void* clientobject, - void* tface); - - int applyLights(int objectlayer); - - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + GPC_RenderTools(); + virtual ~GPC_RenderTools(); + + void EndFrame(RAS_IRasterizer* rasty); + void BeginFrame(RAS_IRasterizer* rasty); + + void EnableOpenGLLights(); + void DisableOpenGLLights(); + void ProcessLighting(int layer, const MT_Transform& viewmat); + + /* @attention mode is ignored here */ + void RenderText2D(RAS_TEXT_RENDER_MODE mode, + const char* text, + int xco, + int yco, + int width, + int height); + void RenderText(int mode, + class RAS_IPolyMaterial* polymat, + float v1[3], + float v2[3], + float v3[3], + float v4[3], + int glattrib); + + void applyTransform(RAS_IRasterizer* rasty, double* oglmatrix, int objectdrawmode); + int applyLights(int objectlayer, const MT_Transform& viewmat); + + void PushMatrix(); + void PopMatrix(); + + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo* client) { return true; } virtual void MotionBlur(RAS_IRasterizer* rasterizer); @@ -146,28 +99,7 @@ public: virtual void Render2DFilters(RAS_ICanvas* canvas); - virtual void SetClientObject(void* obj); - -protected: - /** - * Copied from KX_BlenderGL.cpp in KX_blenderhook - */ - void BL_RenderText( - int mode, - const char* textstr, - int textlen, - struct MTFace* tface, - unsigned int* col, - float v1[3],float v2[3],float v3[3],float v4[3]); - void BL_spack(unsigned int ucol) - { - char *cp = (char *)&ucol; - glColor3ub(cp[3], cp[2], cp[1]); - } - - - BMF_Font* m_font; - static unsigned int m_numgllights; + virtual void SetClientObject(RAS_IRasterizer *rasty, void* obj); }; #endif // __GPC_RENDERTOOLS_H diff --git a/source/gameengine/GamePlayer/common/Makefile b/source/gameengine/GamePlayer/common/Makefile index 19d792ddbdb..6a12e659be6 100644 --- a/source/gameengine/GamePlayer/common/Makefile +++ b/source/gameengine/GamePlayer/common/Makefile @@ -43,6 +43,7 @@ CPPFLAGS += -I../../../blender/blenloader CPPFLAGS += -I../../../blender/blenlib CPPFLAGS += -I../../../blender/imbuf CPPFLAGS += -I../../../blender/makesdna +CPPFLAGS += -I../../../blender/gpu CPPFLAGS += -I../../../kernel/gen_system CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include @@ -72,10 +73,6 @@ CPPFLAGS += -I../../../gameengine/Rasterizer/RAS_OpenGLRasterizer CPPFLAGS += -I../../../gameengine/Physics/Sumo CPPFLAGS += -I../../../gameengine/Physics/common -ifeq ($(WITH_BF_GLEXT),true) - CPPFLAGS += -DWITH_GLEXT -endif - ############################### SOURCEDIR = source/gameengine/GamePlayer/common diff --git a/source/gameengine/GamePlayer/common/SConscript b/source/gameengine/GamePlayer/common/SConscript index 3b2367d2592..30f20a670d3 100644 --- a/source/gameengine/GamePlayer/common/SConscript +++ b/source/gameengine/GamePlayer/common/SConscript @@ -8,7 +8,6 @@ source_files = ['bmfont.cpp', 'GPC_Engine.cpp', 'GPC_KeyboardDevice.cpp', 'GPC_MouseDevice.cpp', - 'GPC_PolygonMaterial.cpp', 'GPC_RawImage.cpp', 'GPC_RawLoadDotBlendArray.cpp', 'GPC_RawLogoArrays.cpp', @@ -46,6 +45,7 @@ incs = ['.', '#source/gameengine/GamePlayer/ghost', '#source/blender/misc', '#source/blender/blenloader', + '#source/blender/gpu', '#extern/glew/include'] #This is all plugin stuff! diff --git a/source/gameengine/GamePlayer/common/unix/GPU_PolygonMaterial.h b/source/gameengine/GamePlayer/common/unix/GPU_PolygonMaterial.h index fee729a84ac..e5ed7f39811 100644 --- a/source/gameengine/GamePlayer/common/unix/GPU_PolygonMaterial.h +++ b/source/gameengine/GamePlayer/common/unix/GPU_PolygonMaterial.h @@ -37,9 +37,9 @@ class GPU_PolygonMaterial : public BP_PolygonMaterial public: GPUPolygonMaterial(const STR_String& texname, bool ba,const STR_String& matname, int tile, int tileXrep, int tileYrep, int mode, int transparant, - int lightlayer,bool bIsTriangle,void* clientobject,void* tpage) : + int lightlayer,,void* tpage) : BP_PolygonMaterial(texname, ba,matname, tile, tileXrep, tileYrep, - mode, transparant, lightlayer, bIsTriangle, clientobject), + mode, transparant, lightlayer), m_tface(tpage) { } diff --git a/source/gameengine/GamePlayer/ghost/CMakeLists.txt b/source/gameengine/GamePlayer/ghost/CMakeLists.txt index d9f0675001f..5e0ca93ac06 100644 --- a/source/gameengine/GamePlayer/ghost/CMakeLists.txt +++ b/source/gameengine/GamePlayer/ghost/CMakeLists.txt @@ -64,6 +64,7 @@ SET(INC ../../../../source/gameengine/GamePlayer/common ../../../../source/blender/misc ../../../../source/blender/blenloader + ../../../../source/blender/gpu ../../../../extern/solid ../../../../extern/glew/include ${PYTHON_INC} diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index 7be3b94d8ae..a9196a1a5e3 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -38,6 +38,7 @@ #endif #include "GL/glew.h" +#include "GPU_extensions.h" #include "GPG_Application.h" @@ -56,6 +57,7 @@ extern "C" #include "BLO_readfile.h" #include "BKE_global.h" #include "BKE_main.h" +#include "IMB_imbuf.h" #include "DNA_scene_types.h" #ifdef __cplusplus } @@ -98,15 +100,15 @@ extern "C" #include "GHOST_IWindow.h" #include "GHOST_Rect.h" - static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time); static GHOST_ISystem* fSystem = 0; static const int kTimerFreq = 10; -GPG_Application::GPG_Application(GHOST_ISystem* system, struct Main* maggie, STR_String startSceneName) - : m_startSceneName(startSceneName), - m_maggie(maggie), +GPG_Application::GPG_Application(GHOST_ISystem* system) + : m_startSceneName(""), + m_startScene(0), + m_maggie(0), m_exitRequested(0), m_system(system), m_mainWindow(0), @@ -114,6 +116,7 @@ GPG_Application::GPG_Application(GHOST_ISystem* system, struct Main* maggie, STR m_cursor(GHOST_kStandardCursorFirstCursor), m_engineInitialized(0), m_engineRunning(0), + m_isEmbedded(false), m_ketsjiengine(0), m_kxsystem(0), m_keyboard(0), @@ -125,7 +128,9 @@ GPG_Application::GPG_Application(GHOST_ISystem* system, struct Main* maggie, STR m_networkdevice(0), m_audiodevice(0), m_blendermat(0), - m_blenderglslmat(0) + m_blenderglslmat(0), + m_pyGlobalDictString(0), + m_pyGlobalDictString_Length(0) { fSystem = system; } @@ -134,21 +139,28 @@ GPG_Application::GPG_Application(GHOST_ISystem* system, struct Main* maggie, STR GPG_Application::~GPG_Application(void) { + if(m_pyGlobalDictString) { + delete [] m_pyGlobalDictString; + m_pyGlobalDictString = 0; + m_pyGlobalDictString_Length = 0; + } + exitEngine(); fSystem->disposeWindow(m_mainWindow); } -bool GPG_Application::SetGameEngineData(struct Main* maggie, STR_String startSceneName) +bool GPG_Application::SetGameEngineData(struct Main* maggie, Scene *scene) { bool result = false; - if (maggie != NULL && startSceneName != "") + if (maggie != NULL && scene != NULL) { - G.scene = (Scene*)maggie->scene.first; + G.scene = scene; m_maggie = maggie; - m_startSceneName = startSceneName; + m_startSceneName = scene->id.name+2; + m_startScene = scene; result = true; } @@ -320,6 +332,26 @@ bool GPG_Application::startWindow(STR_String& title, return success; } +bool GPG_Application::startEmbeddedWindow(STR_String& title, + const GHOST_TEmbedderWindowID parentWindow, + const bool stereoVisual, + const int stereoMode) { + + m_mainWindow = fSystem->createWindow(title, 0, 0, 0, 0, GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, stereoVisual, parentWindow); + + if (!m_mainWindow) { + printf("error: could not create main window\n"); + exit(-1); + } + m_isEmbedded = true; + + bool success = initEngine(m_mainWindow, stereoMode); + if (success) { + success = startEngine(); + } + return success; +} bool GPG_Application::startFullScreen( @@ -478,7 +510,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) { if (!m_engineInitialized) { - glewInit(); + GPU_extensions_init(); bgl::InitExtensions(true); // get and set the preferences @@ -497,13 +529,16 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) bool fixed_framerate= (SYS_GetCommandLineInt(syshandle, "fixed_framerate", fixedFr) != 0); bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0); - bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", G.fileflags & G_FILE_DIAPLAY_LISTS) != 0); + bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", G.fileflags & G_FILE_DISPLAY_LISTS) != 0); + + if(GLEW_ARB_multitexture && GLEW_VERSION_1_1) + m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0); + + if(GPU_extensions_minimum_support()) + m_blenderglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0); + else if(G.fileflags & G_FILE_GAME_MAT_GLSL) + m_blendermat = false; - if(GLEW_ARB_multitexture && GLEW_VERSION_1_1) { - int gameflag =(G.fileflags & G_FILE_GAME_MAT); - m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", gameflag) != 0); - } - // create the canvas, rasterizer and rendertools m_canvas = new GPG_Canvas(window); if (!m_canvas) @@ -626,33 +661,36 @@ bool GPG_Application::startEngine(void) { STR_String startscenename = m_startSceneName.Ptr(); m_ketsjiengine->SetSceneConverter(m_sceneconverter); - + // if (always_use_expand_framing) // sceneconverter->SetAlwaysUseExpandFraming(true); - if(m_blendermat) + if(m_blendermat && (G.fileflags & G_FILE_GAME_MAT)) m_sceneconverter->SetMaterials(true); - if(m_blenderglslmat) + if(m_blenderglslmat && (G.fileflags & G_FILE_GAME_MAT_GLSL)) m_sceneconverter->SetGLSLMaterials(true); KX_Scene* startscene = new KX_Scene(m_keyboard, m_mouse, m_networkdevice, m_audiodevice, - startscenename); + startscenename, + m_startScene); // some python things PyObject* dictionaryobject = initGamePlayerPythonScripting("Ketsji", psl_Lowest); m_ketsjiengine->SetPythonDictionary(dictionaryobject); initRasterizer(m_rasterizer, m_canvas); - PyDict_SetItemString(dictionaryobject, "GameLogic", initGameLogic(startscene)); // Same as importing the module + PyObject *gameLogic = initGameLogic(m_ketsjiengine, startscene); + PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module initGameKeys(); initPythonConstraintBinding(); initMathutils(); - - - + // Set the GameLogic.globalDict from marshal'd data, so we can + // load new blend files and keep data in GameLogic.globalDict + loadGamePythonConfig(m_pyGlobalDictString, m_pyGlobalDictString_Length); + m_sceneconverter->ConvertScene( startscenename, startscene, @@ -688,6 +726,16 @@ bool GPG_Application::startEngine(void) void GPG_Application::stopEngine() { + // GameLogic.globalDict gets converted into a buffer, and sorted in + // m_pyGlobalDictString so we can restore after python has stopped + // and started between .blend file loads. + if(m_pyGlobalDictString) { + delete [] m_pyGlobalDictString; + m_pyGlobalDictString = 0; + } + + m_pyGlobalDictString_Length = saveGamePythonConfig(&m_pyGlobalDictString); + // when exiting the mainloop exitGamePythonScripting(); m_ketsjiengine->StopEngine(); @@ -754,6 +802,12 @@ void GPG_Application::exitEngine() m_canvas = 0; } + libtiff_exit(); +#ifdef WITH_QUICKTIME + quicktime_exit(); +#endif + GPU_extensions_exit(); + m_exitRequested = 0; m_engineInitialized = false; } @@ -833,7 +887,7 @@ bool GPG_Application::handleKey(GHOST_IEvent* event, bool isDown) GHOST_TEventKeyData* keyData = static_cast<GHOST_TEventKeyData*>(eventData); //no need for this test //if (fSystem->getFullScreen()) { - if (keyData->key == GHOST_kKeyEsc && !m_keyboard->m_hookesc) { + if (keyData->key == GHOST_kKeyEsc && !m_keyboard->m_hookesc && !m_isEmbedded) { m_exitRequested = KX_EXIT_REQUEST_OUTSIDE; } //} diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.h b/source/gameengine/GamePlayer/ghost/GPG_Application.h index 17f5add8b19..38408f919b4 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.h +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.h @@ -50,17 +50,19 @@ class GPG_Canvas; class GPG_KeyboardDevice; class GPG_System; struct Main; +struct Scene; class GPG_Application : public GHOST_IEventConsumer { public: - GPG_Application(GHOST_ISystem* system, struct Main* maggie, STR_String startSceneName); + GPG_Application(GHOST_ISystem* system); ~GPG_Application(void); - bool SetGameEngineData(struct Main* maggie,STR_String startSceneName); + bool SetGameEngineData(struct Main* maggie, struct Scene* scene); bool startWindow(STR_String& title, int windowLeft, int windowTop, int windowWidth, int windowHeight, const bool stereoVisual, const int stereoMode); bool startFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode); + bool startEmbeddedWindow(STR_String& title, const GHOST_TEmbedderWindowID parent_window, const bool stereoVisual, const int stereoMode); #ifdef WIN32 bool startScreenSaverFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode); bool startScreenSaverPreview(HWND parentWindow, const bool stereoVisual, const int stereoMode); @@ -100,6 +102,7 @@ protected: /* The game data */ STR_String m_startSceneName; + struct Scene* m_startScene; struct Main* m_maggie; /* Exit state. */ @@ -118,6 +121,8 @@ protected: bool m_engineInitialized; /** Engine state. */ bool m_engineRunning; + /** Running on embedded window */ + bool m_isEmbedded; /** the gameengine itself */ KX_KetsjiEngine* m_ketsjiengine; @@ -142,6 +147,12 @@ protected: bool m_blendermat; bool m_blenderglslmat; - + + /* + * GameLogic.globalDict as a string so that loading new blend files can use the same dict. + * Do this because python starts/stops when loading blend files. + */ + char* m_pyGlobalDictString; + int m_pyGlobalDictString_Length; }; diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index 8222e5c8bac..9700e6387f2 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -52,25 +52,31 @@ extern "C" { #endif // __cplusplus +#include "MEM_guardedalloc.h" +#include "BKE_blender.h" #include "BKE_global.h" #include "BKE_icons.h" +#include "BKE_node.h" #include "BLI_blenlib.h" #include "DNA_scene_types.h" #include "BLO_readfile.h" #include "BLO_readblenfile.h" +#include "IMB_imbuf.h" int GHOST_HACK_getFirstFile(char buf[]); #ifdef __cplusplus } #endif // __cplusplus + +#include "GPU_draw.h" + /********************************** * End Blender include block **********************************/ #include "SYS_System.h" #include "GPG_Application.h" -#include "GPC_PolygonMaterial.h" #include "GHOST_ISystem.h" #include "RAS_IRasterizer.h" @@ -146,9 +152,9 @@ static BOOL scr_saver_init(int argc, char **argv) #endif /* WIN32 */ -void usage(char* program) +void usage(const char* program) { - char * consoleoption; + const char * consoleoption; #ifdef _WIN32 consoleoption = "-c "; #else @@ -176,9 +182,13 @@ void usage(char* program) printf(" anaglyph (Red-Blue glasses)\n"); printf(" vinterlace (Vertical interlace for autostereo display)\n"); printf(" depending on the type of stereo you want\n"); +#ifndef _WIN32 + printf(" -i: parent windows ID \n"); +#endif #ifdef _WIN32 printf(" -c: keep console window open\n"); #endif + printf(" -d: turn debugging on\n"); printf(" -g: game engine options:\n"); printf(" Name Default Description\n"); printf(" ----------------------------------------\n"); @@ -193,7 +203,8 @@ void usage(char* program) printf("example: %s -g show_framerate = 0 c:\\loadtest.blend\n", program); } -char *get_filename(int argc, char **argv) { +static void get_filename(int argc, char **argv, char *filename) +{ #ifdef __APPLE__ /* On Mac we park the game file (called game.blend) in the application bundle. * The executable is located in the bundle as well. @@ -201,22 +212,18 @@ char *get_filename(int argc, char **argv) { */ int srclen = ::strlen(argv[0]); int len = 0; - char *filename = NULL; + char *gamefile = NULL; + filename[0] = '\0'; + if (argc > 1) { if (BLI_exists(argv[argc-1])) { - len = ::strlen(argv[argc-1]); - filename = new char [len + 1]; - ::strcpy(filename, argv[argc-1]); - return(filename); + BLI_strncpy(filename, argv[argc-1], FILE_MAXDIR + FILE_MAXFILE); } if (::strncmp(argv[argc-1], "-psn_", 5)==0) { static char firstfilebuf[512]; if (GHOST_HACK_getFirstFile(firstfilebuf)) { - len = ::strlen(firstfilebuf); - filename = new char [len + 1]; - ::strcpy(filename, firstfilebuf); - return(filename); + BLI_strncpy(filename, firstfilebuf, FILE_MAXDIR + FILE_MAXFILE); } } } @@ -224,23 +231,26 @@ char *get_filename(int argc, char **argv) { srclen -= ::strlen("MacOS/blenderplayer"); if (srclen > 0) { len = srclen + ::strlen("Resources/game.blend"); - filename = new char [len + 1]; - ::strcpy(filename, argv[0]); - ::strcpy(filename + srclen, "Resources/game.blend"); + gamefile = new char [len + 1]; + ::strcpy(gamefile, argv[0]); + ::strcpy(gamefile + srclen, "Resources/game.blend"); //::printf("looking for file: %s\n", filename); - if (BLI_exists(filename)) { - return (filename); - } + if (BLI_exists(gamefile)) + BLI_strncpy(filename, gamefile, FILE_MAXDIR + FILE_MAXFILE); + + delete gamefile; } - return(NULL); #else - return (argc>1)?argv[argc-1]:NULL; + filename[0] = '\0'; + + if(argc > 1) + BLI_strncpy(filename, argv[argc-1], FILE_MAXDIR + FILE_MAXFILE); #endif // !_APPLE } -static BlendFileData *load_game_data(char *progname, char *filename = NULL) { +static BlendFileData *load_game_data(char *progname, char *filename = NULL, char *relativename = NULL) { BlendReadError error; BlendFileData *bfd = NULL; @@ -282,7 +292,7 @@ int main(int argc, char** argv) bool fullScreenParFound = false; bool windowParFound = false; bool closeConsole = true; - RAS_IRasterizer::StereoMode stereomode; + RAS_IRasterizer::StereoMode stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO; bool stereoWindow = false; bool stereoParFound = false; int windowLeft = 100; @@ -293,7 +303,10 @@ int main(int argc, char** argv) GHOST_TUns32 fullScreenHeight= 0; int fullScreenBpp = 32; int fullScreenFrequency = 60; + GHOST_TEmbedderWindowID parentWindow = 0; + + #ifdef __linux__ #ifdef __alpha__ signal (SIGFPE, SIG_IGN); @@ -321,8 +334,18 @@ int main(int argc, char** argv) ::DisposeNibReference(nibRef); */ #endif // __APPLE__ + + init_nodesystem(); + initglobals(); + GEN_init_messaging_system(); + +#ifdef WITH_QUICKTIME + quicktime_init(); +#endif + + libtiff_init(); // Parse command line options #ifndef NDEBUG @@ -401,6 +424,12 @@ int main(int argc, char** argv) } } break; + + case 'd': + i++; + G.f |= G_DEBUG; /* std output printf's */ + MEM_set_memory_debug(); + break; case 'p': // Parse window position and size options @@ -453,6 +482,16 @@ int main(int argc, char** argv) usage(argv[0]); return 0; break; +#ifndef _WIN32 + case 'i': + i++; + if ( (i + 1) < argc ) + parentWindow = atoi(argv[i++]); +#ifndef NDEBUG + printf("XWindows ID = %d\n", parentWindow); +#endif //NDEBUG + +#endif // _WIN32 case 'c': i++; closeConsole = false; @@ -523,21 +562,19 @@ int main(int argc, char** argv) return 0; } - if (!stereoParFound) stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO; - #ifdef WIN32 if (scr_saver_mode != SCREEN_SAVER_MODE_CONFIGURATION) #endif { #ifdef __APPLE__ //SYS_WriteCommandLineInt(syshandle, "show_framerate", 1); - SYS_WriteCommandLineInt(syshandle, "nomipmap", 1); + //SYS_WriteCommandLineInt(syshandle, "nomipmap", 1); //fullScreen = false; // Can't use full screen #endif if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0)) { - GPC_PolygonMaterial::SetMipMappingEnabled(0); + GPU_set_mipmap(0); } // Create the system @@ -559,11 +596,15 @@ int main(int argc, char** argv) { int exitcode = KX_EXIT_REQUEST_NO_REQUEST; STR_String exitstring = ""; - GPG_Application app(system, NULL, exitstring); + GPG_Application app(system); bool firstTimeRunning = true; - char *filename = get_filename(argc, argv); + char filename[FILE_MAXDIR + FILE_MAXFILE]; char *titlename; char pathname[160]; + + get_filename(argc, argv, filename); + if(filename[0]) + BLI_convertstringcwd(filename); do { @@ -595,7 +636,7 @@ int main(int argc, char** argv) } else { - bfd = load_game_data(argv[0], filename); + bfd = load_game_data(bprogname, filename[0]? filename: NULL); } //::printf("game data loaded from %s\n", filename); @@ -617,7 +658,7 @@ int main(int argc, char** argv) #endif // WIN32 Main *maggie = bfd->main; Scene *scene = bfd->curscene; - char *startscenename = scene->id.name + 2; + G.main = maggie; G.fileflags = bfd->fileflags; //Seg Fault; icon.c gIcons == 0 @@ -655,7 +696,7 @@ int main(int argc, char** argv) } // GPG_Application app (system, maggie, startscenename); - app.SetGameEngineData(maggie, startscenename); + app.SetGameEngineData(maggie, scene); if (firstTimeRunning) { @@ -723,7 +764,10 @@ int main(int argc, char** argv) else #endif { - app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight, + if (parentWindow != 0) + app.startEmbeddedWindow(title, parentWindow, stereoWindow, stereomode); + else + app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight, stereoWindow, stereomode); } } @@ -750,13 +794,8 @@ int main(int argc, char** argv) } } app.StopGameEngine(); + BLO_blendfiledata_free(bfd); - -#ifdef __APPLE__ - if (filename) { - delete [] filename; - } -#endif // __APPLE__ } } while (exitcode == KX_EXIT_REQUEST_RESTART_GAME || exitcode == KX_EXIT_REQUEST_START_OTHER_GAME); } @@ -772,6 +811,8 @@ int main(int argc, char** argv) } } + free_nodesystem(); + return error ? -1 : 0; } diff --git a/source/gameengine/GamePlayer/ghost/Makefile b/source/gameengine/GamePlayer/ghost/Makefile index 13940ac3fc8..52e219db8f2 100644 --- a/source/gameengine/GamePlayer/ghost/Makefile +++ b/source/gameengine/GamePlayer/ghost/Makefile @@ -41,6 +41,7 @@ CPPFLAGS += -I$(OPENGL_HEADERS) CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_BMFONT)/include CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I../../GamePlayer/common @@ -69,6 +70,7 @@ CPPFLAGS += -I../../../blender/blenloader CPPFLAGS += -I../../../blender/imbuf CPPFLAGS += -I../../../blender/makesdna CPPFLAGS += -I../../../blender/readblenfile +CPPFLAGS += -I../../../blender/gpu CPPFLAGS += -I../../../gameengine/BlenderRoutines @@ -80,7 +82,3 @@ CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_GHOST)/include CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) -ifeq ($(WITH_BF_GLEXT),true) - CPPFLAGS += -DWITH_GLEXT -endif - diff --git a/source/gameengine/GamePlayer/ghost/SConscript b/source/gameengine/GamePlayer/ghost/SConscript index f3cce6c7443..33cf07b6211 100644 --- a/source/gameengine/GamePlayer/ghost/SConscript +++ b/source/gameengine/GamePlayer/ghost/SConscript @@ -40,6 +40,7 @@ incs = ['.', '#source/gameengine/GamePlayer/common', '#source/blender/misc', '#source/blender/blenloader', + '#source/blender/gpu', '#extern/glew/include'] incs += Split(env['BF_PYTHON_INC']) @@ -48,8 +49,5 @@ cflags = [] if env['OURPLATFORM']=='win32-vc': cflags = ['/GR'] -if env['WITH_BF_GLEXT'] == 1: - env['CPPFLAGS'].append('-DWITH_GLEXT') - env.BlenderLib (libname='gp_ghost', sources=source_files, includes = incs, defines = [], libtype='player',priority=0, compileflags=cflags) diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp index a9a0771936c..8ec463be6ff 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.cpp +++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp @@ -9,108 +9,64 @@ #include "BL_BlenderShader.h" #include "BL_Material.h" -#ifdef BLENDER_GLSL #include "GPU_extensions.h" #include "GPU_material.h" -#endif #include "RAS_BucketManager.h" #include "RAS_MeshObject.h" #include "RAS_IRasterizer.h" - /* this is evil, but we need the scene to create materials with - * lights from the correct scene .. */ -static struct Scene *GetSceneForName(const STR_String& scenename) -{ - Scene *sce; - - for (sce= (Scene*)G.main->scene.first; sce; sce= (Scene*)sce->id.next) - if (scenename == (sce->id.name+2)) - return sce; - - return (Scene*)G.main->scene.first; -} - -bool BL_BlenderShader::Ok() -{ -#ifdef BLENDER_GLSL - VerifyShader(); - - return (mMat && mMat->gpumaterial); -#else - return 0; -#endif -} - BL_BlenderShader::BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer) : -#ifdef BLENDER_GLSL mScene(scene), mMat(ma), - mGPUMat(NULL), -#endif - mBound(false), mLightLayer(lightlayer) { -#ifdef BLENDER_GLSL - mBlenderScene = GetSceneForName(scene->GetName()); + mBlenderScene = scene->GetBlenderScene(); mBlendMode = GPU_BLEND_SOLID; - if(mMat) { + if(mMat) GPU_material_from_blender(mBlenderScene, mMat); - mGPUMat = mMat->gpumaterial; - } -#endif } BL_BlenderShader::~BL_BlenderShader() { -#ifdef BLENDER_GLSL - if(mMat && mMat->gpumaterial) - GPU_material_unbind(mMat->gpumaterial); -#endif + if(mMat && GPU_material_from_blender(mBlenderScene, mMat)) + GPU_material_unbind(GPU_material_from_blender(mBlenderScene, mMat)); } -bool BL_BlenderShader::VerifyShader() +bool BL_BlenderShader::Ok() { -#ifdef BLENDER_GLSL - if(mMat && !mMat->gpumaterial) - GPU_material_from_blender(mBlenderScene, mMat); + return VerifyShader(); +} - mGPUMat = mMat->gpumaterial; - - return (mMat && mGPUMat); -#else - return false; -#endif +bool BL_BlenderShader::VerifyShader() +{ + if(mMat) + return (GPU_material_from_blender(mBlenderScene, mMat) != 0); + else + return false; } -void BL_BlenderShader::SetProg(bool enable) +void BL_BlenderShader::SetProg(bool enable, double time) { -#ifdef BLENDER_GLSL if(VerifyShader()) { - if(enable) { - GPU_material_bind(mGPUMat, mLightLayer); - mBound = true; - } - else { - GPU_material_unbind(mGPUMat); - mBound = false; - } + if(enable) + GPU_material_bind(GPU_material_from_blender(mBlenderScene, mMat), mLightLayer, ~0, time); + else + GPU_material_unbind(GPU_material_from_blender(mBlenderScene, mMat)); } -#endif } int BL_BlenderShader::GetAttribNum() { -#ifdef BLENDER_GLSL GPUVertexAttribs attribs; int i, enabled = 0; if(!VerifyShader()) return enabled; - GPU_material_vertex_attributes(mGPUMat, &attribs); + GPU_material_vertex_attributes(GPU_material_from_blender(mBlenderScene, mMat), &attribs); for(i = 0; i < attribs.totlayer; i++) if(attribs.layer[i].glindex+1 > enabled) @@ -120,24 +76,23 @@ int BL_BlenderShader::GetAttribNum() enabled = BL_MAX_ATTRIB; return enabled; -#else - return 0; -#endif } void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat) { -#ifdef BLENDER_GLSL GPUVertexAttribs attribs; + GPUMaterial *gpumat; int i, attrib_num; ras->SetAttribNum(0); if(!VerifyShader()) return; + + gpumat = GPU_material_from_blender(mBlenderScene, mMat); if(ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) { - GPU_material_vertex_attributes(mGPUMat, &attribs); + GPU_material_vertex_attributes(gpumat, &attribs); attrib_num = GetAttribNum(); ras->SetTexCoordNum(0); @@ -168,44 +123,37 @@ void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat) else ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, attribs.layer[i].glindex); } - - ras->EnableTextures(true); } - else - ras->EnableTextures(false); -#endif } -void BL_BlenderShader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty ) +void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) { -#ifdef BLENDER_GLSL float obmat[4][4], viewmat[4][4], viewinvmat[4][4], obcol[4]; + GPUMaterial *gpumat; - VerifyShader(); + gpumat = GPU_material_from_blender(mBlenderScene, mMat); - if(!mGPUMat) // || !mBound) + if(!gpumat || !GPU_material_bound(gpumat)) return; MT_Matrix4x4 model; model.setValue(ms.m_OpenGLMatrix); - MT_Matrix4x4 view; - rasty->GetViewMatrix(view); + const MT_Matrix4x4& view = rasty->GetViewMatrix(); + const MT_Matrix4x4& viewinv = rasty->GetViewInvMatrix(); + // note: getValue gives back column major as needed by OpenGL model.getValue((float*)obmat); view.getValue((float*)viewmat); - - view.invert(); - view.getValue((float*)viewinvmat); + viewinv.getValue((float*)viewinvmat); if(ms.m_bObjectColor) ms.m_RGBAcolor.getValue((float*)obcol); else obcol[0]= obcol[1]= obcol[2]= obcol[3]= 1.0f; - GPU_material_bind_uniforms(mGPUMat, obmat, viewmat, viewinvmat, obcol); + GPU_material_bind_uniforms(gpumat, obmat, viewmat, viewinvmat, obcol); - mBlendMode = GPU_material_blend_mode(mGPUMat, obcol); -#endif + mBlendMode = GPU_material_blend_mode(gpumat, obcol); } int BL_BlenderShader::GetBlendMode() @@ -215,12 +163,8 @@ int BL_BlenderShader::GetBlendMode() bool BL_BlenderShader::Equals(BL_BlenderShader *blshader) { -#ifdef BLENDER_GLSL /* to avoid unneeded state switches */ - return (blshader && mGPUMat == blshader->mGPUMat && mLightLayer == blshader->mLightLayer); -#else - return true; -#endif + return (blshader && mMat == blshader->mMat && mLightLayer == blshader->mLightLayer); } // eof diff --git a/source/gameengine/Ketsji/BL_BlenderShader.h b/source/gameengine/Ketsji/BL_BlenderShader.h index da9765dafa4..5c1f59f94ad 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.h +++ b/source/gameengine/Ketsji/BL_BlenderShader.h @@ -2,9 +2,7 @@ #ifndef __BL_GPUSHADER_H__ #define __BL_GPUSHADER_H__ -#ifdef BLENDER_GLSL #include "GPU_material.h" -#endif #include "MT_Matrix4x4.h" #include "MT_Matrix3x3.h" @@ -29,13 +27,9 @@ class BL_Material; class BL_BlenderShader { private: -#ifdef BLENDER_GLSL KX_Scene *mScene; struct Scene *mBlenderScene; struct Material *mMat; - GPUMaterial *mGPUMat; -#endif - bool mBound; int mLightLayer; int mBlendMode; @@ -46,11 +40,11 @@ public: virtual ~BL_BlenderShader(); bool Ok(); - void SetProg(bool enable); + void SetProg(bool enable, double time=0.0); int GetAttribNum(); void SetAttribs(class RAS_IRasterizer* ras, const BL_Material *mat); - void Update(const class KX_MeshSlot & ms, class RAS_IRasterizer* rasty); + void Update(const class RAS_MeshSlot & ms, class RAS_IRasterizer* rasty); int GetBlendMode(); bool Equals(BL_BlenderShader *blshader); diff --git a/source/gameengine/Ketsji/BL_Material.h b/source/gameengine/Ketsji/BL_Material.h index dcb66ea2579..0eaa234566c 100644 --- a/source/gameengine/Ketsji/BL_Material.h +++ b/source/gameengine/Ketsji/BL_Material.h @@ -18,9 +18,9 @@ struct EnvMap; this will default to users available units to build with more available, just increment this value although the more you add the slower the search time will be. - we will go for three, which should be enough + we will go for eight, which should be enough */ -#define MAXTEX 3 //match in RAS_TexVert & RAS_OpenGLRasterizer +#define MAXTEX 8 //match in RAS_TexVert & RAS_OpenGLRasterizer // different mapping modes class BL_Mapping @@ -139,7 +139,7 @@ enum BL_ras_mode COLLIDER=2, ZSORT=4, ALPHA=8, - TRIANGLE=16, + // TRIANGLE=16, USE_LIGHT=32, WIRE=64 }; diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp index 57d0fe4140f..80892764089 100644 --- a/source/gameengine/Ketsji/BL_Shader.cpp +++ b/source/gameengine/Ketsji/BL_Shader.cpp @@ -433,7 +433,7 @@ void BL_Shader::SetProg(bool enable) } } -void BL_Shader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty ) +void BL_Shader::Update( const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) { if(!Ok() || !mPreDef.size()) return; @@ -445,8 +445,7 @@ void BL_Shader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty ) { MT_Matrix4x4 model; model.setValue(ms.m_OpenGLMatrix); - MT_Matrix4x4 view; - rasty->GetViewMatrix(view); + const MT_Matrix4x4& view = rasty->GetViewMatrix(); if(mAttr==SHD_TANGENT) ms.m_mesh->SetMeshModified(true); @@ -525,13 +524,15 @@ void BL_Shader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty ) } case VIEWMATRIX_INVERSE: { - view.invert(); + MT_Matrix4x4 viewinv = view; + viewinv.invert(); SetUniform(uni->mLoc, view); break; } case VIEWMATRIX_INVERSETRANSPOSE: { - view.invert(); + MT_Matrix4x4 viewinv = view; + viewinv.invert(); SetUniform(uni->mLoc, view, true); break; } @@ -670,6 +671,7 @@ void BL_Shader::SetUniform(int uniform, const MT_Matrix4x4& vec, bool transpose) ) { float value[16]; + // note: getValue gives back column major as needed by OpenGL vec.getValue(value); glUniformMatrix4fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value); } @@ -879,7 +881,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setSampler, "setSampler(name, index)" ) Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; int index=-1; if(PyArg_ParseTuple(args, "si", &uniform, &index)) { @@ -920,7 +922,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1f, "setUniform1f(name, fx)" ) Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; float value=0; if(PyArg_ParseTuple(args, "sf", &uniform, &value )) { @@ -944,7 +946,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2f , "setUniform2f(name, fx, fy)") if(mError) { Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; float array[2]={ 0,0 }; if(PyArg_ParseTuple(args, "sff", &uniform, &array[0],&array[1] )) { @@ -968,7 +970,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ") if(mError) { Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; float array[3]={0,0,0}; if(PyArg_ParseTuple(args, "sfff", &uniform, &array[0],&array[1],&array[2])) { @@ -993,7 +995,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) " if(mError) { Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; float array[4]={0,0,0,0}; if(PyArg_ParseTuple(args, "sffff", &uniform, &array[0],&array[1],&array[2], &array[3])) { @@ -1017,7 +1019,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1i, "setUniform1i(name, ix)" ) if(mError) { Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; int value=0; if(PyArg_ParseTuple(args, "si", &uniform, &value )) { @@ -1041,7 +1043,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2i , "setUniform2i(name, ix, iy)") if(mError) { Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; int array[2]={ 0,0 }; if(PyArg_ParseTuple(args, "sii", &uniform, &array[0],&array[1] )) { @@ -1066,7 +1068,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ") Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; int array[3]={0,0,0}; if(PyArg_ParseTuple(args, "siii", &uniform, &array[0],&array[1],&array[2])) { @@ -1089,7 +1091,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) " if(mError) { Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; int array[4]={0,0,0, 0}; if(PyArg_ParseTuple(args, "siiii", &uniform, &array[0],&array[1],&array[2], &array[3] )) { @@ -1112,7 +1114,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv , "setUniformfv( float (list2 or lis if(mError) { Py_RETURN_NONE; } - char*uniform = ""; + const char *uniform = ""; PyObject *listPtr =0; float array_data[4] = {0.f,0.f,0.f,0.f}; @@ -1181,7 +1183,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformiv, "setUniformiv( int (list2 or list3 if(mError) { Py_RETURN_NONE; } - char*uniform = ""; + const char *uniform = ""; PyObject *listPtr =0; int array_data[4] = {0,0,0,0}; @@ -1261,7 +1263,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix4, 0,0,0,1 }; - char *uniform=""; + const char *uniform=""; PyObject *matrix=0; int transp=1; // MT_ is row major so transpose by default.... if(PyArg_ParseTuple(args, "sO|i",&uniform, &matrix,&transp)) @@ -1302,7 +1304,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix3, 0,0,1, }; - char *uniform=""; + const char *uniform=""; PyObject *matrix=0; int transp=1; // MT_ is row major so transpose by default.... if(PyArg_ParseTuple(args, "sO|i",&uniform, &matrix,&transp)) @@ -1356,7 +1358,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformDef, "setUniformDef(name, enum)" ) Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; int nloc=0; if(PyArg_ParseTuple(args, "si",&uniform, &nloc)) { diff --git a/source/gameengine/Ketsji/BL_Shader.h b/source/gameengine/Ketsji/BL_Shader.h index 8f303454087..18ca8f8b4f8 100644 --- a/source/gameengine/Ketsji/BL_Shader.h +++ b/source/gameengine/Ketsji/BL_Shader.h @@ -102,8 +102,8 @@ private: bool mUse; // ... //BL_Sampler mSampler[MAXTEX]; // Number of samplers int mAttr; // Tangent attribute - char* vertProg; // Vertex program string - char* fragProg; // Fragment program string + const char* vertProg; // Vertex program string + const char* fragProg; // Fragment program string bool mError; // ... bool mDirty; // @@ -177,7 +177,7 @@ public: void UnloadShader(); // Update predefined uniforms each render call - void Update(const class KX_MeshSlot & ms, class RAS_IRasterizer* rasty); + void Update(const class RAS_MeshSlot & ms, class RAS_IRasterizer* rasty); //// Set sampler units (copied) //void InitializeSampler(int unit, BL_Texture* texture ); diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index be009d94701..58411f6d25e 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -69,6 +69,7 @@ SET(INC ../../../intern/SoundSystem ../../../source/blender/misc ../../../source/blender/blenloader + ../../../source/blender/gpu ../../../extern/bullet2/src ../../../extern/solid ../../../extern/glew/include diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp index 0c66ac1fde3..8956df9c96b 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp @@ -196,20 +196,20 @@ PyParentObject KX_NetworkMessageSensor::Parents[] = { PyMethodDef KX_NetworkMessageSensor::Methods[] = { {"setSubjectFilterText", (PyCFunction) - KX_NetworkMessageSensor::sPySetSubjectFilterText, METH_VARARGS, - SetSubjectFilterText_doc}, + KX_NetworkMessageSensor::sPySetSubjectFilterText, METH_O, + (PY_METHODCHAR)SetSubjectFilterText_doc}, {"getFrameMessageCount", (PyCFunction) - KX_NetworkMessageSensor::sPyGetFrameMessageCount, METH_VARARGS, - GetFrameMessageCount_doc}, + KX_NetworkMessageSensor::sPyGetFrameMessageCount, METH_NOARGS, + (PY_METHODCHAR)GetFrameMessageCount_doc}, {"getBodies", (PyCFunction) - KX_NetworkMessageSensor::sPyGetBodies, METH_VARARGS, - GetBodies_doc}, + KX_NetworkMessageSensor::sPyGetBodies, METH_NOARGS, + (PY_METHODCHAR)GetBodies_doc}, {"getSubject", (PyCFunction) - KX_NetworkMessageSensor::sPyGetSubject, METH_VARARGS, - GetSubject_doc}, + KX_NetworkMessageSensor::sPyGetSubject, METH_NOARGS, + (PY_METHODCHAR)GetSubject_doc}, {"getSubjects", (PyCFunction) - KX_NetworkMessageSensor::sPyGetSubjects, METH_VARARGS, - GetSubjects_doc}, + KX_NetworkMessageSensor::sPyGetSubjects, METH_NOARGS, + (PY_METHODCHAR)GetSubjects_doc}, {NULL,NULL} //Sentinel }; @@ -218,88 +218,66 @@ PyObject* KX_NetworkMessageSensor::_getattr(const STR_String& attr) { } // 1. Set the message subject that this sensor listens for -char KX_NetworkMessageSensor::SetSubjectFilterText_doc[] = +const char KX_NetworkMessageSensor::SetSubjectFilterText_doc[] = "\tsetSubjectFilterText(value)\n" "\tChange the message subject text that this sensor is listening to.\n"; -PyObject* KX_NetworkMessageSensor::PySetSubjectFilterText( - PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_NetworkMessageSensor::PySetSubjectFilterText( PyObject* self, PyObject* value) { - char* Subject; - - if (PyArg_ParseTuple(args, "s", &Subject)) - { - m_subject = Subject; - } - else { + char* Subject = PyString_AsString(value); + if (Subject==NULL) { + PyErr_SetString(PyExc_TypeError, "expected a string message"); return NULL; } - - Py_Return; + + m_subject = Subject; + Py_RETURN_NONE; } // 2. Get the number of messages received since the last frame -char KX_NetworkMessageSensor::GetFrameMessageCount_doc[] = +const char KX_NetworkMessageSensor::GetFrameMessageCount_doc[] = "\tgetFrameMessageCount()\n" "\tGet the number of messages received since the last frame.\n"; -PyObject* KX_NetworkMessageSensor::PyGetFrameMessageCount( - PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_NetworkMessageSensor::PyGetFrameMessageCount( PyObject* ) { return PyInt_FromLong(long(m_frame_message_count)); } // 3. Get the message bodies -char KX_NetworkMessageSensor::GetBodies_doc[] = +const char KX_NetworkMessageSensor::GetBodies_doc[] = "\tgetBodies()\n" "\tGet the list of message bodies.\n"; -PyObject* KX_NetworkMessageSensor::PyGetBodies( - PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_NetworkMessageSensor::PyGetBodies( PyObject* ) { if (m_BodyList) { return ((PyObject*) m_BodyList->AddRef()); + } else { + return ((PyObject*) new CListValue()); } - - Py_Return; } // 4. Get the message subject: field of the message sensor -char KX_NetworkMessageSensor::GetSubject_doc[] = +const char KX_NetworkMessageSensor::GetSubject_doc[] = "\tgetSubject()\n" "\tGet the subject: field of the message sensor.\n"; -PyObject* KX_NetworkMessageSensor::PyGetSubject( - PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_NetworkMessageSensor::PyGetSubject( PyObject* ) { - if (m_subject) { - return PyString_FromString(m_subject); - } - - Py_Return; + return PyString_FromString(m_subject ? m_subject : ""); } // 5. Get the message subjects -char KX_NetworkMessageSensor::GetSubjects_doc[] = +const char KX_NetworkMessageSensor::GetSubjects_doc[] = "\tgetSubjects()\n" "\tGet list of message subjects.\n"; -PyObject* KX_NetworkMessageSensor::PyGetSubjects( - PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_NetworkMessageSensor::PyGetSubjects( PyObject* ) { if (m_SubjectList) { - return ((PyObject*) m_SubjectList->AddRef()); - } - - Py_Return; + return ((PyObject*) m_SubjectList->AddRef()); + } else { + return ((PyObject*) new CListValue()); + } } diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h index 6fd92d17be3..8cdfd6cdb5a 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h @@ -74,11 +74,11 @@ public: virtual PyObject* _getattr(const STR_String& attr); - KX_PYMETHOD_DOC(KX_NetworkMessageSensor, SetSubjectFilterText); - KX_PYMETHOD_DOC(KX_NetworkMessageSensor, GetFrameMessageCount); - KX_PYMETHOD_DOC(KX_NetworkMessageSensor, GetBodies); - KX_PYMETHOD_DOC(KX_NetworkMessageSensor, GetSubject); - KX_PYMETHOD_DOC(KX_NetworkMessageSensor, GetSubjects); + KX_PYMETHOD_DOC_O(KX_NetworkMessageSensor, SetSubjectFilterText); + KX_PYMETHOD_DOC_NOARGS(KX_NetworkMessageSensor, GetFrameMessageCount); + KX_PYMETHOD_DOC_NOARGS(KX_NetworkMessageSensor, GetBodies); + KX_PYMETHOD_DOC_NOARGS(KX_NetworkMessageSensor, GetSubject); + KX_PYMETHOD_DOC_NOARGS(KX_NetworkMessageSensor, GetSubjects); }; diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index a67e5b26667..f92200780d5 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -19,13 +19,12 @@ #include "MT_Vector4.h" #include "MT_Matrix4x4.h" +#include "RAS_BucketManager.h" #include "RAS_MeshObject.h" #include "RAS_IRasterizer.h" #include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h" -extern "C" { -#include "BDR_drawmesh.h" -} +#include "GPU_draw.h" #include "STR_HashedString.h" @@ -48,7 +47,6 @@ KX_BlenderMaterial::KX_BlenderMaterial( BL_Material *data, bool skin, int lightlayer, - void *clientobject, PyTypeObject *T ) : PyObjectPlus(T), @@ -62,9 +60,7 @@ KX_BlenderMaterial::KX_BlenderMaterial( data->transp, ((data->ras_mode &ALPHA)!=0), ((data->ras_mode &ZSORT)!=0), - lightlayer, - ((data->ras_mode &TRIANGLE)!=0), - clientobject + lightlayer ), mMaterial(data), mShader(0), @@ -78,9 +74,10 @@ KX_BlenderMaterial::KX_BlenderMaterial( { // -------------------------------- // RAS_IPolyMaterial variables... - m_flag |=RAS_BLENDERMAT; - m_flag |=(mMaterial->IdMode>=ONETEX)?RAS_MULTITEX:0; - m_flag |=(mMaterial->ras_mode & USE_LIGHT)!=0?RAS_MULTILIGHT:0; + m_flag |= RAS_BLENDERMAT; + m_flag |= (mMaterial->IdMode>=ONETEX)? RAS_MULTITEX: 0; + m_flag |= ((mMaterial->ras_mode & USE_LIGHT)!=0)? RAS_MULTILIGHT: 0; + m_flag |= (mMaterial->glslmat)? RAS_BLENDERGLSL: 0; // figure max int enabled = mMaterial->num_enabled; @@ -97,7 +94,7 @@ KX_BlenderMaterial::KX_BlenderMaterial( mMaterial->blend_mode[i] ); } - m_multimode += mMaterial->IdMode+mMaterial->ras_mode; + m_multimode += mMaterial->IdMode+ (mMaterial->ras_mode & ~(COLLIDER|USE_LIGHT)); } @@ -204,7 +201,7 @@ void KX_BlenderMaterial::OnExit() } if( mMaterial->tface ) - set_tpage(mMaterial->tface); + GPU_set_tpage(mMaterial->tface); } @@ -256,25 +253,28 @@ void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras) void KX_BlenderMaterial::setBlenderShaderData( bool enable, RAS_IRasterizer *ras) { if( !enable || !mBlenderShader->Ok() ) { + ras->SetBlendingMode(TF_SOLID); + // frame cleanup. if(mLastBlenderShader) { mLastBlenderShader->SetProg(false); mLastBlenderShader= NULL; } + else + BL_Texture::DisableAllTextures(); - ras->SetBlendingMode(TF_SOLID); - BL_Texture::DisableAllTextures(); return; } if(!mBlenderShader->Equals(mLastBlenderShader)) { ras->SetBlendingMode(mMaterial->transp); - BL_Texture::DisableAllTextures(); if(mLastBlenderShader) mLastBlenderShader->SetProg(false); + else + BL_Texture::DisableAllTextures(); - mBlenderShader->SetProg(true); + mBlenderShader->SetProg(true, ras->GetTime()); mLastBlenderShader= mBlenderShader; } } @@ -354,21 +354,22 @@ KX_BlenderMaterial::ActivatShaders( if (GetCachingInfo() != cachingInfo) { if (!cachingInfo) - tmp->setShaderData( false, rasty); + tmp->setShaderData(false, rasty); cachingInfo = GetCachingInfo(); if(rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) - tmp->setShaderData( true, rasty); + tmp->setShaderData(true, rasty); else - tmp->setShaderData( false, rasty); + tmp->setShaderData(false, rasty); if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE) rasty->SetCullFace(false); else rasty->SetCullFace(true); - if (((mMaterial->ras_mode &WIRE)!=0) || mMaterial->mode & RAS_IRasterizer::KX_LINES) + if (((mMaterial->ras_mode &WIRE)!=0) || (mMaterial->mode & RAS_IRasterizer::KX_LINES) || + (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) { if((mMaterial->ras_mode &WIRE)!=0) rasty->SetCullFace(false); @@ -394,31 +395,24 @@ KX_BlenderMaterial::ActivateBlenderShaders( mLastShader= NULL; } - // reset... - if(tmp->mMaterial->IsShared()) - cachingInfo =0; - if (GetCachingInfo() != cachingInfo) { if (!cachingInfo) tmp->setBlenderShaderData(false, rasty); cachingInfo = GetCachingInfo(); - if(rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) { + if(rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) tmp->setBlenderShaderData(true, rasty); - rasty->EnableTextures(true); - } - else { + else tmp->setBlenderShaderData(false, rasty); - rasty->EnableTextures(false); - } if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE) rasty->SetCullFace(false); else rasty->SetCullFace(true); - if (((mMaterial->ras_mode &WIRE)!=0) || mMaterial->mode & RAS_IRasterizer::KX_LINES) + if (((mMaterial->ras_mode & WIRE)!=0) || (mMaterial->mode & RAS_IRasterizer::KX_LINES) || + (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) { if((mMaterial->ras_mode &WIRE)!=0) rasty->SetCullFace(false); @@ -426,10 +420,10 @@ KX_BlenderMaterial::ActivateBlenderShaders( } else rasty->SetLines(false); - } - ActivatGLMaterials(rasty); - mBlenderShader->SetAttribs(rasty, mMaterial); + ActivatGLMaterials(rasty); + mBlenderShader->SetAttribs(rasty, mMaterial); + } } void @@ -466,7 +460,8 @@ KX_BlenderMaterial::ActivateMat( else rasty->SetCullFace(true); - if (((mMaterial->ras_mode &WIRE)!=0) || mMaterial->mode & RAS_IRasterizer::KX_LINES) + if (((mMaterial->ras_mode &WIRE)!=0) || (mMaterial->mode & RAS_IRasterizer::KX_LINES) || + (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) { if((mMaterial->ras_mode &WIRE)!=0) rasty->SetCullFace(false); @@ -486,12 +481,10 @@ KX_BlenderMaterial::Activate( TCachingInfo& cachingInfo )const { - bool dopass = false; - if( GLEW_ARB_shader_objects && ( mShader && mShader->Ok() ) ) { - if( (mPass++) < mShader->getNumPass() ) { + if(GLEW_ARB_shader_objects && (mShader && mShader->Ok())) { + if((mPass++) < mShader->getNumPass() ) { ActivatShaders(rasty, cachingInfo); - dopass = true; - return dopass; + return true; } else { if(mShader == mLastShader) { @@ -499,36 +492,29 @@ KX_BlenderMaterial::Activate( mLastShader = NULL; } mPass = 0; - dopass = false; - return dopass; + return false; } } - else if( GLEW_ARB_shader_objects && ( mBlenderShader && mBlenderShader->Ok() ) ) { - if( (mPass++) == 0 ) { + else if( GLEW_ARB_shader_objects && (mBlenderShader && mBlenderShader->Ok() ) ) { + if(mPass++ == 0) { ActivateBlenderShaders(rasty, cachingInfo); - dopass = true; - return dopass; + return true; } else { mPass = 0; - dopass = false; - return dopass; + return false; } } else { - switch (mPass++) - { - case 0: - ActivateMat(rasty, cachingInfo); - dopass = true; - break; - default: - mPass = 0; - dopass = false; - break; + if(mPass++ == 0) { + ActivateMat(rasty, cachingInfo); + return true; + } + else { + mPass = 0; + return false; } } - return dopass; } bool KX_BlenderMaterial::UsesLighting(RAS_IRasterizer *rasty) const @@ -536,14 +522,15 @@ bool KX_BlenderMaterial::UsesLighting(RAS_IRasterizer *rasty) const if(!RAS_IPolyMaterial::UsesLighting(rasty)) return false; - if(mShader && mShader->Ok()); + if(mShader && mShader->Ok()) + return true; else if(mBlenderShader && mBlenderShader->Ok()) return false; - - return true; + else + return true; } -void KX_BlenderMaterial::ActivateMeshSlot(const KX_MeshSlot & ms, RAS_IRasterizer* rasty) const +void KX_BlenderMaterial::ActivateMeshSlot(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty) const { if(mShader && GLEW_ARB_shader_objects) { mShader->Update(ms, rasty); @@ -554,7 +541,7 @@ void KX_BlenderMaterial::ActivateMeshSlot(const KX_MeshSlot & ms, RAS_IRasterize mBlenderShader->Update(ms, rasty); /* we do blend modes here, because they can change per object - * with the same material due to obcolor */ + * with the same material due to obcolor/obalpha */ blendmode = mBlenderShader->GetBlendMode(); if((blendmode == TF_SOLID || blendmode == TF_ALPHA) && mMaterial->transp != TF_SOLID) blendmode = mMaterial->transp; @@ -633,11 +620,7 @@ void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const else ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_DISABLE, i); } - - ras->EnableTextures(true); } - else - ras->EnableTextures(false); } void KX_BlenderMaterial::setTexMatrixData(int i) @@ -712,8 +695,7 @@ void KX_BlenderMaterial::setObjectMatrixData(int i, RAS_IRasterizer *ras) glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_R); - MT_Matrix4x4 mvmat; - ras->GetViewMatrix(mvmat); + const MT_Matrix4x4& mvmat = ras->GetViewMatrix(); glMatrixMode(GL_TEXTURE); glLoadIdentity(); @@ -835,7 +817,9 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()") } if(mShader && !mShader->GetError()) { + m_flag &= ~RAS_BLENDERGLSL; mMaterial->SetSharedMaterial(true); + mScene->GetBucketManager()->ReleaseDisplayLists(this); Py_INCREF(mShader); return mShader; }else @@ -870,8 +854,6 @@ void KX_BlenderMaterial::SetBlenderGLSLShader(void) delete mBlenderShader; mBlenderShader = 0; } - else - m_flag |= RAS_BLENDERGLSL; } KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()") diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h index 0d7657b8cdb..4ddf5a924df 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.h +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h @@ -28,7 +28,6 @@ public: BL_Material* mat, bool skin, int lightlayer, - void* clientobject, PyTypeObject* T=&Type ); @@ -47,7 +46,7 @@ public: virtual void ActivateMeshSlot( - const KX_MeshSlot & ms, + const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) const; diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp index 539eaec4a7b..bf838e60210 100644 --- a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp +++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp @@ -14,6 +14,7 @@ #include "PHY_IPhysicsEnvironment.h" #include "CcdPhysicsEnvironment.h" +#include "BulletSoftBody/btSoftBody.h" KX_BulletPhysicsController::KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna) @@ -114,7 +115,7 @@ MT_Vector3 KX_BulletPhysicsController::GetAngularVelocity() MT_Vector3 KX_BulletPhysicsController::GetVelocity(const MT_Point3& pos) { float linVel[3]; - CcdPhysicsController::GetLinearVelocity(linVel[0],linVel[1],linVel[2]); + CcdPhysicsController::GetVelocity(pos[0], pos[1], pos[2], linVel[0],linVel[1],linVel[2]); return MT_Vector3(linVel[0],linVel[1],linVel[2]); } @@ -148,13 +149,23 @@ void KX_BulletPhysicsController::setScaling(const MT_Vector3& scaling) } MT_Scalar KX_BulletPhysicsController::GetMass() { - - MT_Scalar invmass = GetRigidBody()->getInvMass(); + if (GetSoftBody()) + return GetSoftBody()->getTotalMass(); + + MT_Scalar invmass = 0.f; + if (GetRigidBody()) + invmass = GetRigidBody()->getInvMass(); if (invmass) return 1.f/invmass; return 0.f; } + +MT_Scalar KX_BulletPhysicsController::GetRadius() +{ + return MT_Scalar(CcdPhysicsController::GetRadius()); +} + MT_Vector3 KX_BulletPhysicsController::getReactionForce() { assert(0); @@ -167,7 +178,7 @@ void KX_BulletPhysicsController::setRigidBody(bool rigid) void KX_BulletPhysicsController::SuspendDynamics(bool ghost) { btRigidBody *body = GetRigidBody(); - if (body->getActivationState() != DISABLE_SIMULATION) + if (body && body->getActivationState() != DISABLE_SIMULATION) { btBroadphaseProxy* handle = body->getBroadphaseHandle(); m_savedCollisionFlags = body->getCollisionFlags(); @@ -186,7 +197,7 @@ void KX_BulletPhysicsController::SuspendDynamics(bool ghost) void KX_BulletPhysicsController::RestoreDynamics() { btRigidBody *body = GetRigidBody(); - if (body->getActivationState() == DISABLE_SIMULATION) + if (body && body->getActivationState() == DISABLE_SIMULATION) { GetPhysicsEnvironment()->updateCcdPhysicsController(this, m_savedMass, @@ -206,6 +217,9 @@ SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode) //parentcontroller is here be able to avoid collisions between parent/child PHY_IPhysicsController* parentctrl = NULL; + KX_BulletPhysicsController* parentKxCtrl = NULL; + CcdPhysicsController* ccdParent = NULL; + if (destnode != destnode->GetRootSGParent()) { @@ -225,12 +239,15 @@ SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode) KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); if (clientgameobj) { - parentctrl = (KX_BulletPhysicsController*)clientgameobj->GetPhysicsController(); + parentKxCtrl = (KX_BulletPhysicsController*)clientgameobj->GetPhysicsController(); + parentctrl = parentKxCtrl; + ccdParent = parentKxCtrl; } } } } + physicsreplica->setParentCtrl(ccdParent); physicsreplica->PostProcessReplica(motionstate,parentctrl); physicsreplica->m_userdata = (PHY_IPhysicsController*)physicsreplica; return physicsreplica; @@ -241,18 +258,22 @@ SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode) void KX_BulletPhysicsController::SetSumoTransform(bool nondynaonly) { - GetRigidBody()->activate(true); + if (GetRigidBody()) + GetRigidBody()->activate(true); if (!m_bDyna) { - GetRigidBody()->setCollisionFlags(GetRigidBody()->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + GetCollisionObject()->setCollisionFlags(GetRigidBody()->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } else { if (!nondynaonly) { btTransform worldTrans; - GetRigidBody()->getMotionState()->getWorldTransform(worldTrans); - GetRigidBody()->setCenterOfMassTransform(worldTrans); + if (GetRigidBody()) + { + GetRigidBody()->getMotionState()->getWorldTransform(worldTrans); + GetRigidBody()->setCenterOfMassTransform(worldTrans); + } /* scaling? diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.h b/source/gameengine/Ketsji/KX_BulletPhysicsController.h index 2efe0474b30..cdcb82c87ca 100644 --- a/source/gameengine/Ketsji/KX_BulletPhysicsController.h +++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.h @@ -49,9 +49,7 @@ public: virtual SG_Controller* GetReplica(class SG_Node* destnode); - void SetDyna(bool isDynamic) { - m_bDyna = isDynamic; - } + virtual MT_Scalar GetRadius(); virtual void SetSumoTransform(bool nondynaonly); diff --git a/source/gameengine/Ketsji/KX_CameraActuator.cpp b/source/gameengine/Ketsji/KX_CameraActuator.cpp index 42b909927fd..4d24e83843e 100644 --- a/source/gameengine/Ketsji/KX_CameraActuator.cpp +++ b/source/gameengine/Ketsji/KX_CameraActuator.cpp @@ -35,6 +35,8 @@ #include <math.h> #include "KX_GameObject.h" +#include "PyObjectPlus.h" + STR_String KX_CameraActuator::X_AXIS_STRING = "x"; STR_String KX_CameraActuator::Y_AXIS_STRING = "y"; @@ -395,16 +397,16 @@ PyParentObject KX_CameraActuator::Parents[] = { }; PyMethodDef KX_CameraActuator::Methods[] = { - {"setObject",(PyCFunction) KX_CameraActuator::sPySetObject, METH_O, SetObject_doc}, - {"getObject",(PyCFunction) KX_CameraActuator::sPyGetObject, METH_VARARGS, GetObject_doc}, - {"setMin" ,(PyCFunction) KX_CameraActuator::sPySetMin, METH_VARARGS, SetMin_doc}, - {"getMin" ,(PyCFunction) KX_CameraActuator::sPyGetMin, METH_NOARGS, GetMin_doc}, - {"setMax" ,(PyCFunction) KX_CameraActuator::sPySetMax, METH_VARARGS, SetMax_doc}, - {"getMax" ,(PyCFunction) KX_CameraActuator::sPyGetMax, METH_NOARGS, GetMax_doc}, - {"setHeight",(PyCFunction) KX_CameraActuator::sPySetHeight, METH_VARARGS, SetHeight_doc}, - {"getHeight",(PyCFunction) KX_CameraActuator::sPyGetHeight, METH_NOARGS, GetHeight_doc}, - {"setXY" ,(PyCFunction) KX_CameraActuator::sPySetXY, METH_VARARGS, SetXY_doc}, - {"getXY" ,(PyCFunction) KX_CameraActuator::sPyGetXY, METH_VARARGS, GetXY_doc}, + {"setObject",(PyCFunction) KX_CameraActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc}, + {"getObject",(PyCFunction) KX_CameraActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc}, + {"setMin" ,(PyCFunction) KX_CameraActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetMin_doc}, + {"getMin" ,(PyCFunction) KX_CameraActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetMin_doc}, + {"setMax" ,(PyCFunction) KX_CameraActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetMax_doc}, + {"getMax" ,(PyCFunction) KX_CameraActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetMax_doc}, + {"setHeight",(PyCFunction) KX_CameraActuator::sPySetHeight, METH_VARARGS, (PY_METHODCHAR)SetHeight_doc}, + {"getHeight",(PyCFunction) KX_CameraActuator::sPyGetHeight, METH_NOARGS, (PY_METHODCHAR)GetHeight_doc}, + {"setXY" ,(PyCFunction) KX_CameraActuator::sPySetXY, METH_VARARGS, (PY_METHODCHAR)SetXY_doc}, + {"getXY" ,(PyCFunction) KX_CameraActuator::sPyGetXY, METH_VARARGS, (PY_METHODCHAR)GetXY_doc}, {NULL,NULL,NULL,NULL} //Sentinel }; @@ -412,7 +414,7 @@ PyObject* KX_CameraActuator::_getattr(const STR_String& attr) { _getattr_up(SCA_IActuator); } /* get obj ---------------------------------------------------------- */ -char KX_CameraActuator::GetObject_doc[] = +const char KX_CameraActuator::GetObject_doc[] = "getObject(name_only = 1)\n" "name_only - optional arg, when true will return the KX_GameObject rather then its name\n" "\tReturns the object this sensor reacts to.\n"; @@ -431,7 +433,7 @@ PyObject* KX_CameraActuator::PyGetObject(PyObject* self, PyObject* args) return m_ob->AddRef(); } /* set obj ---------------------------------------------------------- */ -char KX_CameraActuator::SetObject_doc[] = +const char KX_CameraActuator::SetObject_doc[] = "setObject(object)\n" "\t- object: KX_GameObject, string or None\n" "\tSets the object this sensor reacts to.\n"; @@ -453,7 +455,7 @@ PyObject* KX_CameraActuator::PySetObject(PyObject* self, PyObject* value) } /* get min ---------------------------------------------------------- */ -char KX_CameraActuator::GetMin_doc[] = +const char KX_CameraActuator::GetMin_doc[] = "getMin\n" "\tReturns the minimum value set in the Min: field.\n"; PyObject* KX_CameraActuator::PyGetMin(PyObject* self, @@ -463,7 +465,7 @@ PyObject* KX_CameraActuator::PyGetMin(PyObject* self, return PyFloat_FromDouble(m_minHeight); } /* set min ---------------------------------------------------------- */ -char KX_CameraActuator::SetMin_doc[] = +const char KX_CameraActuator::SetMin_doc[] = "setMin\n" "\tSets the minimum value.\n"; PyObject* KX_CameraActuator::PySetMin(PyObject* self, @@ -479,7 +481,7 @@ PyObject* KX_CameraActuator::PySetMin(PyObject* self, return NULL; } /* get min ---------------------------------------------------------- */ -char KX_CameraActuator::GetMax_doc[] = +const char KX_CameraActuator::GetMax_doc[] = "getMax\n" "\tReturns the maximum value set in the Max: field.\n"; PyObject* KX_CameraActuator::PyGetMax(PyObject* self, @@ -489,7 +491,7 @@ PyObject* KX_CameraActuator::PyGetMax(PyObject* self, return PyFloat_FromDouble(m_maxHeight); } /* set min ---------------------------------------------------------- */ -char KX_CameraActuator::SetMax_doc[] = +const char KX_CameraActuator::SetMax_doc[] = "setMax\n" "\tSets the maximum value.\n"; PyObject* KX_CameraActuator::PySetMax(PyObject* self, @@ -505,7 +507,7 @@ PyObject* KX_CameraActuator::PySetMax(PyObject* self, return NULL; } /* get height ---------------------------------------------------------- */ -char KX_CameraActuator::GetHeight_doc[] = +const char KX_CameraActuator::GetHeight_doc[] = "getHeight\n" "\tReturns the height value set in the height: field.\n"; PyObject* KX_CameraActuator::PyGetHeight(PyObject* self, @@ -515,7 +517,7 @@ PyObject* KX_CameraActuator::PyGetHeight(PyObject* self, return PyFloat_FromDouble(m_height); } /* set height ---------------------------------------------------------- */ -char KX_CameraActuator::SetHeight_doc[] = +const char KX_CameraActuator::SetHeight_doc[] = "setHeight\n" "\tSets the height value.\n"; PyObject* KX_CameraActuator::PySetHeight(PyObject* self, @@ -531,7 +533,7 @@ PyObject* KX_CameraActuator::PySetHeight(PyObject* self, return NULL; } /* set XY ---------------------------------------------------------- */ -char KX_CameraActuator::SetXY_doc[] = +const char KX_CameraActuator::SetXY_doc[] = "setXY\n" "\tSets axis the camera tries to get behind.\n" "\t1=x, 0=y\n"; @@ -549,7 +551,7 @@ PyObject* KX_CameraActuator::PySetXY(PyObject* self, } /* get XY -------------------------------------------------------------*/ -char KX_CameraActuator::GetXY_doc[] = +const char KX_CameraActuator::GetXY_doc[] = "getXY\n" "\tGets the axis the camera tries to get behind.\n" "\tTrue = X, False = Y\n"; diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp index e00ec68ad33..76357e9c58f 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp @@ -109,16 +109,11 @@ KX_ConstraintActuator::~KX_ConstraintActuator() // there's nothing to be done here, really.... } /* end of destructor */ -bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { - KX_GameObject* hitKXObj = client->m_gameobject; + m_hitObject = client->m_gameobject; - if (client->m_type > KX_ClientObjectInfo::ACTOR) - { - // false hit - return false; - } bool bFound = false; if (m_property[0] == 0) @@ -136,11 +131,29 @@ bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_p } else { - bFound = hitKXObj->GetProperty(m_property) != NULL; + bFound = m_hitObject->GetProperty(m_property) != NULL; } } + // update the hit status + result->m_hitFound = bFound; + // stop looking + return true; +} - return bFound; +/* this function is used to pre-filter the object before casting the ray on them. + This is useful for "X-Ray" option when we want to see "through" unwanted object. + */ +bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo* client) +{ + if (client->m_type > KX_ClientObjectInfo::ACTOR) + { + // Unknown type of object, skip it. + // Should not occur as the sensor objects are filtered in RayTest() + printf("Invalid client type %d found in ray casting\n", client->m_type); + return false; + } + // no X-Ray function yet + return true; } bool KX_ConstraintActuator::Update(double curtime, bool frame) @@ -159,13 +172,15 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) KX_GameObject *obj = (KX_GameObject*) GetParent(); MT_Point3 position = obj->NodeGetWorldPosition(); MT_Point3 newposition; - MT_Vector3 direction, refDirection; + MT_Vector3 normal, direction, refDirection; MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation(); MT_Scalar filter, newdistance, cosangle; int axis, sign; if (m_posDampTime) { filter = m_posDampTime/(1.0+m_posDampTime); + } else { + filter = 0.0; } switch (m_locrot) { case KX_ACT_CONSTRAINT_ORIX: @@ -225,12 +240,8 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) } else { refDirection = m_refDirection; } - if (m_posDampTime) { - // apply damping on the direction - direction = filter*direction + (1.0-filter)*refDirection; - } else { - direction = refDirection; - } + // apply damping on the direction + direction = filter*direction + (1.0-filter)*refDirection; obj->AlignAxisToVect(direction, axis); result = true; goto CHECK_TIME; @@ -242,53 +253,76 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) case KX_ACT_CONSTRAINT_DIRNZ: switch (m_locrot) { case KX_ACT_CONSTRAINT_DIRPX: - direction[0] = rotation[0][0]; - direction[1] = rotation[1][0]; - direction[2] = rotation[2][0]; + normal[0] = rotation[0][0]; + normal[1] = rotation[1][0]; + normal[2] = rotation[2][0]; axis = 0; // axis according to KX_GameObject::AlignAxisToVect() - sign = 1; // X axis will be anti parrallel to normal + sign = 0; // X axis will be parrallel to direction of ray break; case KX_ACT_CONSTRAINT_DIRPY: - direction[0] = rotation[0][1]; - direction[1] = rotation[1][1]; - direction[2] = rotation[2][1]; + normal[0] = rotation[0][1]; + normal[1] = rotation[1][1]; + normal[2] = rotation[2][1]; axis = 1; - sign = 1; + sign = 0; break; case KX_ACT_CONSTRAINT_DIRPZ: - direction[0] = rotation[0][2]; - direction[1] = rotation[1][2]; - direction[2] = rotation[2][2]; + normal[0] = rotation[0][2]; + normal[1] = rotation[1][2]; + normal[2] = rotation[2][2]; axis = 2; - sign = 1; + sign = 0; break; case KX_ACT_CONSTRAINT_DIRNX: - direction[0] = -rotation[0][0]; - direction[1] = -rotation[1][0]; - direction[2] = -rotation[2][0]; + normal[0] = -rotation[0][0]; + normal[1] = -rotation[1][0]; + normal[2] = -rotation[2][0]; axis = 0; - sign = 0; + sign = 1; break; case KX_ACT_CONSTRAINT_DIRNY: - direction[0] = -rotation[0][1]; - direction[1] = -rotation[1][1]; - direction[2] = -rotation[2][1]; + normal[0] = -rotation[0][1]; + normal[1] = -rotation[1][1]; + normal[2] = -rotation[2][1]; axis = 1; - sign = 0; + sign = 1; break; case KX_ACT_CONSTRAINT_DIRNZ: - direction[0] = -rotation[0][2]; - direction[1] = -rotation[1][2]; - direction[2] = -rotation[2][2]; + normal[0] = -rotation[0][2]; + normal[1] = -rotation[1][2]; + normal[2] = -rotation[2][2]; axis = 2; - sign = 0; + sign = 1; break; } - direction.normalize(); + normal.normalize(); + if (m_option & KX_ACT_CONSTRAINT_LOCAL) { + // direction of the ray is along the local axis + direction = normal; + } else { + switch (m_locrot) { + case KX_ACT_CONSTRAINT_DIRPX: + direction = MT_Vector3(1.0,0.0,0.0); + break; + case KX_ACT_CONSTRAINT_DIRPY: + direction = MT_Vector3(0.0,1.0,0.0); + break; + case KX_ACT_CONSTRAINT_DIRPZ: + direction = MT_Vector3(0.0,0.0,1.0); + break; + case KX_ACT_CONSTRAINT_DIRNX: + direction = MT_Vector3(-1.0,0.0,0.0); + break; + case KX_ACT_CONSTRAINT_DIRNY: + direction = MT_Vector3(0.0,-1.0,0.0); + break; + case KX_ACT_CONSTRAINT_DIRNZ: + direction = MT_Vector3(0.0,0.0,-1.0); + break; + } + } { MT_Point3 topoint = position + (m_maximumBound) * direction; - MT_Point3 resultpoint; - MT_Vector3 resultnormal; PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment(); KX_IPhysicsController *spc = obj->GetPhysicsController(); @@ -304,9 +338,10 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) parent->Release(); } } - result = KX_RayCast::RayTest(spc, pe, position, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_ConstraintActuator>(this)); - + KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc); + result = KX_RayCast::RayTest(pe, position, topoint, callback); if (result) { + MT_Vector3 newnormal = callback.m_hitNormal; // compute new position & orientation if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) { // if none option is set, the actuator does nothing but detect ray @@ -314,29 +349,40 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) goto CHECK_TIME; } if (m_option & KX_ACT_CONSTRAINT_NORMAL) { - // the new orientation must be so that the axis is parallel to normal - if (sign) - resultnormal = -resultnormal; + MT_Scalar rotFilter; // apply damping on the direction if (m_rotDampTime) { - MT_Scalar rotFilter = 1.0/(1.0+m_rotDampTime); - resultnormal = (-m_rotDampTime*rotFilter)*direction + rotFilter*resultnormal; - } else if (m_posDampTime) { - resultnormal = -filter*direction + (1.0-filter)*resultnormal; + rotFilter = m_rotDampTime/(1.0+m_rotDampTime); + } else { + rotFilter = filter; + } + newnormal = rotFilter*normal - (1.0-rotFilter)*newnormal; + obj->AlignAxisToVect((sign)?-newnormal:newnormal, axis); + if (m_option & KX_ACT_CONSTRAINT_LOCAL) { + direction = newnormal; + direction.normalize(); } - obj->AlignAxisToVect(resultnormal, axis); - direction = -resultnormal; } if (m_option & KX_ACT_CONSTRAINT_DISTANCE) { if (m_posDampTime) { - newdistance = filter*(position-resultpoint).length()+(1.0-filter)*m_minimumBound; + newdistance = filter*(position-callback.m_hitPoint).length()+(1.0-filter)*m_minimumBound; } else { newdistance = m_minimumBound; } + // logically we should cancel the speed along the ray direction as we set the + // position along that axis + spc = obj->GetPhysicsController(); + if (spc && spc->IsDyna()) { + MT_Vector3 linV = spc->GetLinearVelocity(); + // cancel the projection along the ray direction + MT_Scalar fallspeed = linV.dot(direction); + if (!MT_fuzzyZero(fallspeed)) + spc->SetLinearVelocity(linV-fallspeed*direction,false); + } } else { - newdistance = (position-resultpoint).length(); + newdistance = (position-callback.m_hitPoint).length(); } - newposition = resultpoint-newdistance*direction; + newposition = callback.m_hitPoint-newdistance*direction; } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) { // no contact but still keep running result = true; @@ -344,10 +390,114 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) } } break; + case KX_ACT_CONSTRAINT_FHPX: + case KX_ACT_CONSTRAINT_FHPY: + case KX_ACT_CONSTRAINT_FHPZ: + case KX_ACT_CONSTRAINT_FHNX: + case KX_ACT_CONSTRAINT_FHNY: + case KX_ACT_CONSTRAINT_FHNZ: + switch (m_locrot) { + case KX_ACT_CONSTRAINT_FHPX: + normal[0] = -rotation[0][0]; + normal[1] = -rotation[1][0]; + normal[2] = -rotation[2][0]; + direction = MT_Vector3(1.0,0.0,0.0); + break; + case KX_ACT_CONSTRAINT_FHPY: + normal[0] = -rotation[0][1]; + normal[1] = -rotation[1][1]; + normal[2] = -rotation[2][1]; + direction = MT_Vector3(0.0,1.0,0.0); + break; + case KX_ACT_CONSTRAINT_FHPZ: + normal[0] = -rotation[0][2]; + normal[1] = -rotation[1][2]; + normal[2] = -rotation[2][2]; + direction = MT_Vector3(0.0,0.0,1.0); + break; + case KX_ACT_CONSTRAINT_FHNX: + normal[0] = rotation[0][0]; + normal[1] = rotation[1][0]; + normal[2] = rotation[2][0]; + direction = MT_Vector3(-1.0,0.0,0.0); + break; + case KX_ACT_CONSTRAINT_FHNY: + normal[0] = rotation[0][1]; + normal[1] = rotation[1][1]; + normal[2] = rotation[2][1]; + direction = MT_Vector3(0.0,-1.0,0.0); + break; + case KX_ACT_CONSTRAINT_FHNZ: + normal[0] = rotation[0][2]; + normal[1] = rotation[1][2]; + normal[2] = rotation[2][2]; + direction = MT_Vector3(0.0,0.0,-1.0); + break; + } + normal.normalize(); + { + PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment(); + KX_IPhysicsController *spc = obj->GetPhysicsController(); + + if (!pe) { + std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no physics environment!" << std::endl; + goto CHECK_TIME; + } + if (!spc || !spc->IsDyna()) { + // the object is not dynamic, it won't support setting speed + goto CHECK_TIME; + } + m_hitObject = NULL; + // distance of Fh area is stored in m_minimum + MT_Point3 topoint = position + (m_minimumBound+spc->GetRadius()) * direction; + KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc); + result = KX_RayCast::RayTest(pe, position, topoint, callback); + // we expect a hit object + if (!m_hitObject) + result = false; + if (result) + { + MT_Vector3 newnormal = callback.m_hitNormal; + // compute new position & orientation + MT_Scalar distance = (callback.m_hitPoint-position).length()-spc->GetRadius(); + // estimate the velocity of the hit point + MT_Point3 relativeHitPoint; + relativeHitPoint = (callback.m_hitPoint-m_hitObject->NodeGetWorldPosition()); + MT_Vector3 velocityHitPoint = m_hitObject->GetVelocity(relativeHitPoint); + MT_Vector3 relativeVelocity = spc->GetLinearVelocity() - velocityHitPoint; + MT_Scalar relativeVelocityRay = direction.dot(relativeVelocity); + MT_Scalar springExtent = 1.0 - distance/m_minimumBound; + // Fh force is stored in m_maximum + MT_Scalar springForce = springExtent * m_maximumBound; + // damping is stored in m_refDirection [0] = damping, [1] = rot damping + MT_Scalar springDamp = relativeVelocityRay * m_refDirection[0]; + MT_Vector3 newVelocity = spc->GetLinearVelocity()-(springForce+springDamp)*direction; + if (m_option & KX_ACT_CONSTRAINT_NORMAL) + { + newVelocity+=(springForce+springDamp)*(newnormal-newnormal.dot(direction)*direction); + } + spc->SetLinearVelocity(newVelocity, false); + if (m_option & KX_ACT_CONSTRAINT_DOROTFH) + { + MT_Vector3 angSpring = (normal.cross(newnormal))*m_maximumBound; + MT_Vector3 angVelocity = spc->GetAngularVelocity(); + // remove component that is parallel to normal + angVelocity -= angVelocity.dot(newnormal)*newnormal; + MT_Vector3 angDamp = angVelocity * ((m_refDirection[1]>MT_EPSILON)?m_refDirection[1]:m_refDirection[0]); + spc->SetAngularVelocity(spc->GetAngularVelocity()+(angSpring-angDamp), false); + } + } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) { + // no contact but still keep running + result = true; + } + // don't set the position with this constraint + goto CHECK_TIME; + } + break; case KX_ACT_CONSTRAINT_LOCX: case KX_ACT_CONSTRAINT_LOCY: case KX_ACT_CONSTRAINT_LOCZ: - newposition = position; + newposition = position = obj->GetSGNode()->GetLocalPosition(); switch (m_locrot) { case KX_ACT_CONSTRAINT_LOCX: Clamp(newposition[0], m_minimumBound, m_maximumBound); @@ -363,7 +513,8 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) if (m_posDampTime) { newposition = filter*position + (1.0-filter)*newposition; } - break; + obj->NodeSetLocalPosition(newposition); + goto CHECK_TIME; } if (result) { // set the new position but take into account parent if any @@ -436,28 +587,28 @@ PyParentObject KX_ConstraintActuator::Parents[] = { }; PyMethodDef KX_ConstraintActuator::Methods[] = { - {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, SetDamp_doc}, - {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_NOARGS, GetDamp_doc}, - {"setRotDamp", (PyCFunction) KX_ConstraintActuator::sPySetRotDamp, METH_VARARGS, SetRotDamp_doc}, - {"getRotDamp", (PyCFunction) KX_ConstraintActuator::sPyGetRotDamp, METH_NOARGS, GetRotDamp_doc}, - {"setDirection", (PyCFunction) KX_ConstraintActuator::sPySetDirection, METH_VARARGS, SetDirection_doc}, - {"getDirection", (PyCFunction) KX_ConstraintActuator::sPyGetDirection, METH_NOARGS, GetDirection_doc}, - {"setOption", (PyCFunction) KX_ConstraintActuator::sPySetOption, METH_VARARGS, SetOption_doc}, - {"getOption", (PyCFunction) KX_ConstraintActuator::sPyGetOption, METH_NOARGS, GetOption_doc}, - {"setTime", (PyCFunction) KX_ConstraintActuator::sPySetTime, METH_VARARGS, SetTime_doc}, - {"getTime", (PyCFunction) KX_ConstraintActuator::sPyGetTime, METH_NOARGS, GetTime_doc}, - {"setProperty", (PyCFunction) KX_ConstraintActuator::sPySetProperty, METH_VARARGS, SetProperty_doc}, - {"getProperty", (PyCFunction) KX_ConstraintActuator::sPyGetProperty, METH_NOARGS, GetProperty_doc}, - {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetMin_doc}, - {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, GetMin_doc}, - {"setDistance", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetDistance_doc}, - {"getDistance", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, GetDistance_doc}, - {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetMax_doc}, - {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, GetMax_doc}, - {"setRayLength", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetRayLength_doc}, - {"getRayLength", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, GetRayLength_doc}, - {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, SetLimit_doc}, - {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_NOARGS, GetLimit_doc}, + {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, (PY_METHODCHAR)SetDamp_doc}, + {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_NOARGS, (PY_METHODCHAR)GetDamp_doc}, + {"setRotDamp", (PyCFunction) KX_ConstraintActuator::sPySetRotDamp, METH_VARARGS, (PY_METHODCHAR)SetRotDamp_doc}, + {"getRotDamp", (PyCFunction) KX_ConstraintActuator::sPyGetRotDamp, METH_NOARGS, (PY_METHODCHAR)GetRotDamp_doc}, + {"setDirection", (PyCFunction) KX_ConstraintActuator::sPySetDirection, METH_VARARGS, (PY_METHODCHAR)SetDirection_doc}, + {"getDirection", (PyCFunction) KX_ConstraintActuator::sPyGetDirection, METH_NOARGS, (PY_METHODCHAR)GetDirection_doc}, + {"setOption", (PyCFunction) KX_ConstraintActuator::sPySetOption, METH_VARARGS, (PY_METHODCHAR)SetOption_doc}, + {"getOption", (PyCFunction) KX_ConstraintActuator::sPyGetOption, METH_NOARGS, (PY_METHODCHAR)GetOption_doc}, + {"setTime", (PyCFunction) KX_ConstraintActuator::sPySetTime, METH_VARARGS, (PY_METHODCHAR)SetTime_doc}, + {"getTime", (PyCFunction) KX_ConstraintActuator::sPyGetTime, METH_NOARGS, (PY_METHODCHAR)GetTime_doc}, + {"setProperty", (PyCFunction) KX_ConstraintActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, + {"getProperty", (PyCFunction) KX_ConstraintActuator::sPyGetProperty, METH_NOARGS, (PY_METHODCHAR)GetProperty_doc}, + {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetMin_doc}, + {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetMin_doc}, + {"setDistance", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetDistance_doc}, + {"getDistance", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetDistance_doc}, + {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetMax_doc}, + {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetMax_doc}, + {"setRayLength", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetRayLength_doc}, + {"getRayLength", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetRayLength_doc}, + {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, (PY_METHODCHAR)SetLimit_doc}, + {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_NOARGS, (PY_METHODCHAR)GetLimit_doc}, {NULL,NULL} //Sentinel }; @@ -466,7 +617,7 @@ PyObject* KX_ConstraintActuator::_getattr(const STR_String& attr) { } /* 2. setDamp */ -char KX_ConstraintActuator::SetDamp_doc[] = +const char KX_ConstraintActuator::SetDamp_doc[] = "setDamp(duration)\n" "\t- duration: integer\n" "\tSets the time constant of the orientation and distance constraint.\n" @@ -485,7 +636,7 @@ PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self, Py_Return; } /* 3. getDamp */ -char KX_ConstraintActuator::GetDamp_doc[] = +const char KX_ConstraintActuator::GetDamp_doc[] = "getDamp()\n" "\tReturns the damping parameter.\n"; PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self){ @@ -493,7 +644,7 @@ PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self){ } /* 2. setRotDamp */ -char KX_ConstraintActuator::SetRotDamp_doc[] = +const char KX_ConstraintActuator::SetRotDamp_doc[] = "setRotDamp(duration)\n" "\t- duration: integer\n" "\tSets the time constant of the orientation constraint.\n" @@ -512,7 +663,7 @@ PyObject* KX_ConstraintActuator::PySetRotDamp(PyObject* self, Py_Return; } /* 3. getRotDamp */ -char KX_ConstraintActuator::GetRotDamp_doc[] = +const char KX_ConstraintActuator::GetRotDamp_doc[] = "getRotDamp()\n" "\tReturns the damping time for application of the constraint.\n"; PyObject* KX_ConstraintActuator::PyGetRotDamp(PyObject* self){ @@ -520,7 +671,7 @@ PyObject* KX_ConstraintActuator::PyGetRotDamp(PyObject* self){ } /* 2. setDirection */ -char KX_ConstraintActuator::SetDirection_doc[] = +const char KX_ConstraintActuator::SetDirection_doc[] = "setDirection(vector)\n" "\t- vector: 3-tuple\n" "\tSets the reference direction in world coordinate for the orientation constraint.\n"; @@ -547,7 +698,7 @@ PyObject* KX_ConstraintActuator::PySetDirection(PyObject* self, Py_Return; } /* 3. getDirection */ -char KX_ConstraintActuator::GetDirection_doc[] = +const char KX_ConstraintActuator::GetDirection_doc[] = "getDirection()\n" "\tReturns the reference direction of the orientation constraint as a 3-tuple.\n"; PyObject* KX_ConstraintActuator::PyGetDirection(PyObject* self){ @@ -560,7 +711,7 @@ PyObject* KX_ConstraintActuator::PyGetDirection(PyObject* self){ } /* 2. setOption */ -char KX_ConstraintActuator::SetOption_doc[] = +const char KX_ConstraintActuator::SetOption_doc[] = "setOption(option)\n" "\t- option: integer\n" "\tSets several options of the distance constraint.\n" @@ -582,7 +733,7 @@ PyObject* KX_ConstraintActuator::PySetOption(PyObject* self, Py_Return; } /* 3. getOption */ -char KX_ConstraintActuator::GetOption_doc[] = +const char KX_ConstraintActuator::GetOption_doc[] = "getOption()\n" "\tReturns the option parameter.\n"; PyObject* KX_ConstraintActuator::PyGetOption(PyObject* self){ @@ -590,7 +741,7 @@ PyObject* KX_ConstraintActuator::PyGetOption(PyObject* self){ } /* 2. setTime */ -char KX_ConstraintActuator::SetTime_doc[] = +const char KX_ConstraintActuator::SetTime_doc[] = "setTime(duration)\n" "\t- duration: integer\n" "\tSets the activation time of the actuator.\n" @@ -611,7 +762,7 @@ PyObject* KX_ConstraintActuator::PySetTime(PyObject* self, Py_Return; } /* 3. getTime */ -char KX_ConstraintActuator::GetTime_doc[] = +const char KX_ConstraintActuator::GetTime_doc[] = "getTime()\n" "\tReturns the time parameter.\n"; PyObject* KX_ConstraintActuator::PyGetTime(PyObject* self){ @@ -619,7 +770,7 @@ PyObject* KX_ConstraintActuator::PyGetTime(PyObject* self){ } /* 2. setProperty */ -char KX_ConstraintActuator::SetProperty_doc[] = +const char KX_ConstraintActuator::SetProperty_doc[] = "setProperty(property)\n" "\t- property: string\n" "\tSets the name of the property or material for the ray detection of the distance constraint.\n" @@ -641,7 +792,7 @@ PyObject* KX_ConstraintActuator::PySetProperty(PyObject* self, Py_Return; } /* 3. getProperty */ -char KX_ConstraintActuator::GetProperty_doc[] = +const char KX_ConstraintActuator::GetProperty_doc[] = "getProperty()\n" "\tReturns the property parameter.\n"; PyObject* KX_ConstraintActuator::PyGetProperty(PyObject* self){ @@ -649,12 +800,12 @@ PyObject* KX_ConstraintActuator::PyGetProperty(PyObject* self){ } /* 4. setDistance */ -char KX_ConstraintActuator::SetDistance_doc[] = +const char KX_ConstraintActuator::SetDistance_doc[] = "setDistance(distance)\n" "\t- distance: float\n" "\tSets the target distance in distance constraint\n"; /* 4. setMin */ -char KX_ConstraintActuator::SetMin_doc[] = +const char KX_ConstraintActuator::SetMin_doc[] = "setMin(lower_bound)\n" "\t- lower_bound: float\n" "\tSets the lower value of the interval to which the value\n" @@ -681,11 +832,11 @@ PyObject* KX_ConstraintActuator::PySetMin(PyObject* self, Py_Return; } /* 5. getDistance */ -char KX_ConstraintActuator::GetDistance_doc[] = +const char KX_ConstraintActuator::GetDistance_doc[] = "getDistance()\n" "\tReturns the distance parameter \n"; /* 5. getMin */ -char KX_ConstraintActuator::GetMin_doc[] = +const char KX_ConstraintActuator::GetMin_doc[] = "getMin()\n" "\tReturns the lower value of the interval to which the value\n" "\tis clipped.\n"; @@ -694,12 +845,12 @@ PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self) { } /* 6. setRayLength */ -char KX_ConstraintActuator::SetRayLength_doc[] = +const char KX_ConstraintActuator::SetRayLength_doc[] = "setRayLength(length)\n" "\t- length: float\n" "\tSets the maximum ray length of the distance constraint\n"; /* 6. setMax */ -char KX_ConstraintActuator::SetMax_doc[] = +const char KX_ConstraintActuator::SetMax_doc[] = "setMax(upper_bound)\n" "\t- upper_bound: float\n" "\tSets the upper value of the interval to which the value\n" @@ -726,11 +877,11 @@ PyObject* KX_ConstraintActuator::PySetMax(PyObject* self, Py_Return; } /* 7. getRayLength */ -char KX_ConstraintActuator::GetRayLength_doc[] = +const char KX_ConstraintActuator::GetRayLength_doc[] = "getRayLength()\n" "\tReturns the length of the ray\n"; /* 7. getMax */ -char KX_ConstraintActuator::GetMax_doc[] = +const char KX_ConstraintActuator::GetMax_doc[] = "getMax()\n" "\tReturns the upper value of the interval to which the value\n" "\tis clipped.\n"; @@ -741,7 +892,7 @@ PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self) { /* This setter/getter probably for the constraint type */ /* 8. setLimit */ -char KX_ConstraintActuator::SetLimit_doc[] = +const char KX_ConstraintActuator::SetLimit_doc[] = "setLimit(type)\n" "\t- type: integer\n" "\t 1 : LocX\n" @@ -770,7 +921,7 @@ PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self, Py_Return; } /* 9. getLimit */ -char KX_ConstraintActuator::GetLimit_doc[] = +const char KX_ConstraintActuator::GetLimit_doc[] = "getLimit()\n" "\tReturns the type of constraint.\n"; PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self) { diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.h b/source/gameengine/Ketsji/KX_ConstraintActuator.h index d9f39124cac..28b9b1e6a0b 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.h +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.h @@ -37,6 +37,9 @@ #include "MT_Vector3.h" #include "KX_ClientObjectInfo.h" +class KX_RayCast; +class KX_GameObject; + class KX_ConstraintActuator : public SCA_IActuator { Py_Header; @@ -63,6 +66,8 @@ protected: int m_option; // property to check char m_property[32]; + // hit object + KX_GameObject* m_hitObject; /** * Clamp <var> to <min>, <max>. Borders are included (in as far as @@ -90,6 +95,12 @@ protected: KX_ACT_CONSTRAINT_ORIX, KX_ACT_CONSTRAINT_ORIY, KX_ACT_CONSTRAINT_ORIZ, + KX_ACT_CONSTRAINT_FHPX, + KX_ACT_CONSTRAINT_FHPY, + KX_ACT_CONSTRAINT_FHPZ, + KX_ACT_CONSTRAINT_FHNX, + KX_ACT_CONSTRAINT_FHNY, + KX_ACT_CONSTRAINT_FHNZ, KX_ACT_CONSTRAINT_MAX }; // match ACT_CONST_... values from BIF_interface.h @@ -97,10 +108,13 @@ protected: KX_ACT_CONSTRAINT_NORMAL = 64, KX_ACT_CONSTRAINT_MATERIAL = 128, KX_ACT_CONSTRAINT_PERMANENT = 256, - KX_ACT_CONSTRAINT_DISTANCE = 512 + KX_ACT_CONSTRAINT_DISTANCE = 512, + KX_ACT_CONSTRAINT_LOCAL = 1024, + KX_ACT_CONSTRAINT_DOROTFH = 2048 }; bool IsValidMode(KX_CONSTRAINTTYPE m); - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo*); KX_ConstraintActuator(SCA_IObject* gameobj, int posDamptime, @@ -144,12 +158,12 @@ protected: KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetProperty); KX_PYMETHOD_DOC(KX_ConstraintActuator,SetMin); KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetMin); - static char SetDistance_doc[]; - static char GetDistance_doc[]; + static const char SetDistance_doc[]; + static const char GetDistance_doc[]; KX_PYMETHOD_DOC(KX_ConstraintActuator,SetMax); KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetMax); - static char SetRayLength_doc[]; - static char GetRayLength_doc[]; + static const char SetRayLength_doc[]; + static const char GetRayLength_doc[]; KX_PYMETHOD_DOC(KX_ConstraintActuator,SetLimit); KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetLimit); }; diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp index b54da6eb753..c9095ff34f6 100644 --- a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp @@ -27,6 +27,7 @@ * ***** END GPL LICENSE BLOCK ***** */ #include <Python.h> +#include "PyObjectPlus.h" #include "KX_ConstraintWrapper.h" #include "PHY_IPhysicsEnvironment.h" diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h b/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h index 6653026f28a..53486cecf73 100644 --- a/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h +++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h @@ -75,6 +75,7 @@ struct KX_CBounds struct KX_ObjectProperties { bool m_dyna; + bool m_softbody; double m_radius; bool m_angular_rigidbody; bool m_in_active_layer; @@ -86,6 +87,47 @@ struct KX_ObjectProperties bool m_disableSleeping; bool m_hasCompoundChildren; bool m_isCompoundChild; + + ///////////////////////// + + int m_gamesoftFlag; + float m_soft_linStiff; /* linear stiffness 0..1 */ + float m_soft_angStiff; /* angular stiffness 0..1 */ + float m_soft_volume; /* volume preservation 0..1 */ + + int m_soft_viterations; /* Velocities solver iterations */ + int m_soft_piterations; /* Positions solver iterations */ + int m_soft_diterations; /* Drift solver iterations */ + int m_soft_citerations; /* Cluster solver iterations */ + + float m_soft_kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */ + float m_soft_kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */ + float m_soft_kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */ + float m_soft_kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + + float m_soft_kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + float m_soft_kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + float m_soft_kVCF; /* Velocities correction factor (Baumgarte) */ + float m_soft_kDP; /* Damping coefficient [0,1] */ + + float m_soft_kDG; /* Drag coefficient [0,+inf] */ + float m_soft_kLF; /* Lift coefficient [0,+inf] */ + float m_soft_kPR; /* Pressure coefficient [-inf,+inf] */ + float m_soft_kVC; /* Volume conversation coefficient [0,+inf] */ + + float m_soft_kDF; /* Dynamic friction coefficient [0,1] */ + float m_soft_kMT; /* Pose matching coefficient [0,1] */ + float m_soft_kCHR; /* Rigid contacts hardness [0,1] */ + float m_soft_kKHR; /* Kinetic contacts hardness [0,1] */ + + float m_soft_kSHR; /* Soft contacts hardness [0,1] */ + float m_soft_kAHR; /* Anchors hardness [0,1] */ + int m_soft_collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */ + int m_soft_numclusteriterations; /* number of iterations to refine collision clusters*/ + + ///////////////////////// + + double m_margin; KX_BoundBoxClass m_boundclass; union { KX_BoxBounds box; diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp index e0cd5a3bc9e..0e7a6d92ec1 100644 --- a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp +++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp @@ -38,6 +38,8 @@ #include "RAS_MeshObject.h" #include "KX_Scene.h" #include "SYS_System.h" +#include "BL_SkinMeshObject.h" +#include "BulletSoftBody/btSoftBody.h" #include "PHY_Pro.h" //todo cleanup #include "KX_ClientObjectInfo.h" @@ -76,16 +78,16 @@ struct KX_PhysicsInstance { DT_VertexBaseHandle m_vertexbase; - int m_vtxarray; + RAS_DisplayArray* m_darray; RAS_IPolyMaterial* m_material; - - KX_PhysicsInstance(DT_VertexBaseHandle vertex_base, int vtxarray, RAS_IPolyMaterial* mat) + + KX_PhysicsInstance(DT_VertexBaseHandle vertex_base, RAS_DisplayArray *darray, RAS_IPolyMaterial* mat) : m_vertexbase(vertex_base), - m_vtxarray(vtxarray), - m_material(mat) + m_darray(darray), + m_material(mat) { } - + ~KX_PhysicsInstance() { DT_DeleteVertexBase(m_vertexbase); @@ -100,11 +102,11 @@ static void BL_RegisterSumoObject(KX_GameObject* gameobj,class SM_Scene* sumoSce static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope); void KX_ConvertSumoObject( KX_GameObject* gameobj, - RAS_MeshObject* meshobj, - KX_Scene* kxscene, - PHY_ShapeProps* kxshapeprops, - PHY_MaterialProps* kxmaterial, - struct KX_ObjectProperties* objprop) + RAS_MeshObject* meshobj, + KX_Scene* kxscene, + PHY_ShapeProps* kxshapeprops, + PHY_MaterialProps* kxmaterial, + struct KX_ObjectProperties* objprop) { @@ -150,23 +152,23 @@ void KX_ConvertSumoObject( KX_GameObject* gameobj, objprop->m_boundobject.box.m_extends[1], objprop->m_boundobject.box.m_extends[2]); smprop->m_inertia.scale(objprop->m_boundobject.box.m_extends[0]*objprop->m_boundobject.box.m_extends[0], - objprop->m_boundobject.box.m_extends[1]*objprop->m_boundobject.box.m_extends[1], - objprop->m_boundobject.box.m_extends[2]*objprop->m_boundobject.box.m_extends[2]); + objprop->m_boundobject.box.m_extends[1]*objprop->m_boundobject.box.m_extends[1], + objprop->m_boundobject.box.m_extends[2]*objprop->m_boundobject.box.m_extends[2]); smprop->m_inertia *= smprop->m_mass/MT_Vector3(objprop->m_boundobject.box.m_extends).length(); break; case KX_BOUNDCYLINDER: shape = DT_NewCylinder(smprop->m_radius, objprop->m_boundobject.c.m_height); smprop->m_inertia.scale(smprop->m_mass*smprop->m_radius*smprop->m_radius, - smprop->m_mass*smprop->m_radius*smprop->m_radius, - smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height); + smprop->m_mass*smprop->m_radius*smprop->m_radius, + smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height); break; case KX_BOUNDCONE: shape = DT_NewCone(objprop->m_radius, objprop->m_boundobject.c.m_height); smprop->m_inertia.scale(smprop->m_mass*smprop->m_radius*smprop->m_radius, - smprop->m_mass*smprop->m_radius*smprop->m_radius, - smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height); + smprop->m_mass*smprop->m_radius*smprop->m_radius, + smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height); break; - /* Dynamic mesh objects. WARNING! slow. */ + /* Dynamic mesh objects. WARNING! slow. */ case KX_BOUNDPOLYTOPE: polytope = true; // fall through @@ -186,15 +188,15 @@ void KX_ConvertSumoObject( KX_GameObject* gameobj, shape = DT_NewSphere(objprop->m_radius); smprop->m_inertia *= smprop->m_mass*smprop->m_radius*smprop->m_radius; break; - + } - + sumoObj = new SM_Object(shape, !objprop->m_ghost?smmaterial:NULL,smprop,NULL); - + sumoObj->setRigidBody(objprop->m_angular_rigidbody?true:false); - + BL_RegisterSumoObject(gameobj,sceneptr,sumoObj,"",true, true); - + } else { // non physics object @@ -320,12 +322,11 @@ static void BL_RegisterSumoObject( physicscontroller->SetObject(gameobj->GetSGNode()); } -static DT_ShapeHandle InstancePhysicsComplex(RAS_MeshObject* meshobj, int vtxarray, RAS_IPolyMaterial *mat) +static DT_ShapeHandle InstancePhysicsComplex(RAS_MeshObject* meshobj, RAS_DisplayArray *darray, RAS_IPolyMaterial *mat) { // instance a mesh from a single vertex array & material - const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(mat)[vtxarray])[0]); - //const KX_IndexArray &index_array = *meshobj->GetIndexCache(mat)[vtxarray]; - DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getLocalXYZ(), sizeof(RAS_TexVert)); + const RAS_TexVert *vertex_array = &darray->m_vertex[0]; + DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getXYZ(), sizeof(RAS_TexVert)); DT_ShapeHandle shape = DT_NewComplexShape(vertex_base); @@ -337,15 +338,19 @@ static DT_ShapeHandle InstancePhysicsComplex(RAS_MeshObject* meshobj, int vtxarr // only add polygons that have the collisionflag set if (poly->IsCollider()) { - DT_VertexIndices(3, poly->GetVertexIndexBase().m_indexarray); + DT_Begin(); + DT_VertexIndex(poly->GetVertexOffset(0)); + DT_VertexIndex(poly->GetVertexOffset(1)); + DT_VertexIndex(poly->GetVertexOffset(2)); + DT_End(); // tesselate if (poly->VertexCount() == 4) { DT_Begin(); - DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[0]); - DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[2]); - DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[3]); + DT_VertexIndex(poly->GetVertexOffset(0)); + DT_VertexIndex(poly->GetVertexOffset(2)); + DT_VertexIndex(poly->GetVertexOffset(3)); DT_End(); } } @@ -354,16 +359,15 @@ static DT_ShapeHandle InstancePhysicsComplex(RAS_MeshObject* meshobj, int vtxarr //DT_VertexIndices(indices.size(), &indices[0]); DT_EndComplexShape(); - map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, vtxarray, mat)); + map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, darray, mat)); return shape; } -static DT_ShapeHandle InstancePhysicsPolytope(RAS_MeshObject* meshobj, int vtxarray, RAS_IPolyMaterial *mat) +static DT_ShapeHandle InstancePhysicsPolytope(RAS_MeshObject* meshobj, RAS_DisplayArray *darray, RAS_IPolyMaterial *mat) { // instance a mesh from a single vertex array & material - const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(mat)[vtxarray])[0]); - //const KX_IndexArray &index_array = *meshobj->GetIndexCache(mat)[vtxarray]; - DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getLocalXYZ(), sizeof(RAS_TexVert)); + const RAS_TexVert *vertex_array = &darray->m_vertex[0]; + DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getXYZ(), sizeof(RAS_TexVert)); std::vector<DT_Index> indices; for (int p = 0; p < meshobj->NumPolygons(); p++) @@ -373,12 +377,12 @@ static DT_ShapeHandle InstancePhysicsPolytope(RAS_MeshObject* meshobj, int vtxar // only add polygons that have the collisionflag set if (poly->IsCollider()) { - indices.push_back(poly->GetVertexIndexBase().m_indexarray[0]); - indices.push_back(poly->GetVertexIndexBase().m_indexarray[1]); - indices.push_back(poly->GetVertexIndexBase().m_indexarray[2]); + indices.push_back(poly->GetVertexOffset(0)); + indices.push_back(poly->GetVertexOffset(1)); + indices.push_back(poly->GetVertexOffset(2)); if (poly->VertexCount() == 4) - indices.push_back(poly->GetVertexIndexBase().m_indexarray[3]); + indices.push_back(poly->GetVertexOffset(3)); } } @@ -386,7 +390,7 @@ static DT_ShapeHandle InstancePhysicsPolytope(RAS_MeshObject* meshobj, int vtxar DT_VertexIndices(indices.size(), &indices[0]); DT_EndPolytope(); - map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, vtxarray, mat)); + map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, darray, mat)); return shape; } @@ -398,8 +402,8 @@ bool KX_ReInstanceShapeFromMesh(RAS_MeshObject* meshobj) KX_PhysicsInstance *instance = *map_gamemesh_to_instance[GEN_HashedPtr(meshobj)]; if (instance) { - const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(instance->m_material)[instance->m_vtxarray])[0]); - DT_ChangeVertexBase(instance->m_vertexbase, vertex_array[0].getLocalXYZ()); + const RAS_TexVert *vertex_array = &instance->m_darray->m_vertex[0]; + DT_ChangeVertexBase(instance->m_vertexbase, vertex_array[0].getXYZ()); return true; } return false; @@ -425,7 +429,7 @@ static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope // Count the number of collision polygons and check they all come from the same // vertex array int numvalidpolys = 0; - int vtxarray = -1; + RAS_DisplayArray *darray = NULL; RAS_IPolyMaterial *poly_material = NULL; bool reinstance = true; @@ -437,14 +441,14 @@ static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope if (poly->IsCollider()) { // check polygon is from the same vertex array - if (poly->GetVertexIndexBase().m_vtxarray != vtxarray) + if (poly->GetDisplayArray() != darray) { - if (vtxarray < 0) - vtxarray = poly->GetVertexIndexBase().m_vtxarray; + if (darray == NULL) + darray = poly->GetDisplayArray(); else { reinstance = false; - vtxarray = -1; + darray = NULL; } } @@ -478,9 +482,9 @@ static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope if (reinstance) { if (polytope) - shape = InstancePhysicsPolytope(meshobj, vtxarray, poly_material); + shape = InstancePhysicsPolytope(meshobj, darray, poly_material); else - shape = InstancePhysicsComplex(meshobj, vtxarray, poly_material); + shape = InstancePhysicsComplex(meshobj, darray, poly_material); } else { @@ -489,7 +493,7 @@ static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope std::cout << "CreateShapeFromMesh: " << meshobj->GetName() << " is not suitable for polytope." << std::endl; if (!poly_material) std::cout << " Check mesh materials." << std::endl; - if (vtxarray < 0) + if (darray == NULL) std::cout << " Check number of vertices." << std::endl; } @@ -505,18 +509,10 @@ static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope if (poly->IsCollider()) { /* We have to tesselate here because SOLID can only raycast triangles */ DT_Begin(); - /* V1 */ - DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[2], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ()); - /* V2 */ - DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[1], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ()); - /* V3 */ - DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[0], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ()); + /* V1, V2, V3 */ + DT_Vertex(poly->GetVertex(2)->getXYZ()); + DT_Vertex(poly->GetVertex(1)->getXYZ()); + DT_Vertex(poly->GetVertex(0)->getXYZ()); numvalidpolys++; DT_End(); @@ -524,18 +520,10 @@ static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope if (poly->VertexCount() == 4) { DT_Begin(); - /* V1 */ - DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[3], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ()); - /* V3 */ - DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[2], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ()); - /* V4 */ - DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[0], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ()); + /* V1, V3, V4 */ + DT_Vertex(poly->GetVertex(3)->getXYZ()); + DT_Vertex(poly->GetVertex(2)->getXYZ()); + DT_Vertex(poly->GetVertex(0)->getXYZ()); numvalidpolys++; DT_End(); @@ -679,189 +667,107 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj, #endif //WIN32 -// forward declarations -static btCollisionShape* CreateBulletShapeFromMesh(RAS_MeshObject* meshobj, bool polytope) -{ - if (!meshobj) - return 0; - - btCollisionShape* collisionMeshShape = 0; - btConvexHullShape* convexHullShape = 0; - btTriangleMeshShape* concaveShape = 0; - - btTriangleMesh* collisionMeshData = 0; - - //see if there is any polygons, if not, bail out. - - int numPoints = 0; - btVector3* points = 0; - - // Mesh has no polygons! - int numpolys = meshobj->NumPolygons(); - if (!numpolys) + + class KX_SoftBodyDeformer : public RAS_Deformer { - return NULL; - } + class RAS_MeshObject* m_pMeshObject; + class KX_GameObject* m_gameobj; - // Count the number of collision polygons and check they all come from the same - // vertex array - int numvalidpolys = 0; - int vtxarray = -1; - RAS_IPolyMaterial *poly_material = NULL; - bool reinstance = true; - - for (int p=0; p<numpolys; p++) - { - RAS_Polygon* poly = meshobj->GetPolygon(p); - - // only add polygons that have the collisionflag set - if (poly->IsCollider()) + public: + KX_SoftBodyDeformer(RAS_MeshObject* pMeshObject,KX_GameObject* gameobj) + :m_pMeshObject(pMeshObject), + m_gameobj(gameobj) { - // check polygon is from the same vertex array - if (poly->GetVertexIndexBase().m_vtxarray != vtxarray) - { - if (vtxarray < 0) - vtxarray = poly->GetVertexIndexBase().m_vtxarray; - else - { - reinstance = false; - vtxarray = -1; - } - } - - // check poly is from the same material - if (poly->GetMaterial()->GetPolyMaterial() != poly_material) - { - if (poly_material) - { - reinstance = false; - poly_material = NULL; - } - else - poly_material = poly->GetMaterial()->GetPolyMaterial(); - } - - // count the number of collision polys - numvalidpolys++; + //printf("KX_SoftBodyDeformer\n"); + }; - // We have one collision poly, and we can't reinstance, so we - // might as well break here. - if (!reinstance) - break; + virtual ~KX_SoftBodyDeformer() + { + //printf("~KX_SoftBodyDeformer\n"); + }; + virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map) + { + //printf("relink\n"); } - } + virtual bool Apply(class RAS_IPolyMaterial *polymat) + { + KX_BulletPhysicsController* ctrl = (KX_BulletPhysicsController*) m_gameobj->GetPhysicsController(); + if (!ctrl) + return false; - // No collision polygons - if (numvalidpolys < 1) - return NULL; + btSoftBody* softBody= ctrl->GetSoftBody(); + if (!softBody) + return false; + //printf("apply\n"); + RAS_MeshSlot::iterator it; + RAS_MeshMaterial *mmat; + RAS_MeshSlot *slot; + size_t i; - if (polytope) - { - convexHullShape = new btConvexHullShape(&points[0].getX(),numPoints); - collisionMeshShape = convexHullShape; - } else - { - collisionMeshData = new btTriangleMesh(); -// concaveShape = new btTriangleMeshShape(collisionMeshData); - //collisionMeshShape = concaveShape; - - } + // update the vertex in m_transverts + Update(); - numvalidpolys = 0; - for (int p2=0; p2<numpolys; p2++) - { - RAS_Polygon* poly = meshobj->GetPolygon(p2); + // The vertex cache can only be updated for this deformer: + // Duplicated objects with more than one ploymaterial (=multiple mesh slot per object) + // share the same mesh (=the same cache). As the rendering is done per polymaterial + // cycling through the objects, the entire mesh cache cannot be updated in one shot. + mmat = m_pMeshObject->GetMeshMaterial(polymat); + if(!mmat->m_slots[(void*)m_gameobj]) + return true; - // only add polygons that have the collisionflag set - if (poly->IsCollider()) - { - //Bullet can raycast any shape, so - if (polytope) - { - for (int i=0;i<poly->VertexCount();i++) - { - const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[i], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 point(vtx[0],vtx[1],vtx[2]); - convexHullShape->addPoint(point); - } - if (poly->VertexCount()) - numvalidpolys++; + slot = *mmat->m_slots[(void*)m_gameobj]; - } else + // for each array + for(slot->begin(it); !slot->end(it); slot->next(it)) { - { - const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[2], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 vertex0(vtx[0],vtx[1],vtx[2]); - vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[1], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 vertex1(vtx[0],vtx[1],vtx[2]); - vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[0], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 vertex2(vtx[0],vtx[1],vtx[2]); - collisionMeshData->addTriangle(vertex0,vertex1,vertex2); - numvalidpolys++; - } - if (poly->VertexCount() == 4) - { - const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[3], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 vertex0(vtx[0],vtx[1],vtx[2]); - vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[2], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 vertex1(vtx[0],vtx[1],vtx[2]); - vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, - poly->GetVertexIndexBase().m_indexarray[0], - poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ(); - btPoint3 vertex2(vtx[0],vtx[1],vtx[2]); - collisionMeshData->addTriangle(vertex0,vertex1,vertex2); - numvalidpolys++; - } + btSoftBody::tNodeArray& nodes(softBody->m_nodes); - } - } - } + int index = 0; + for(i=it.startvertex; i<it.endvertex; i++,index++) { + RAS_TexVert& v = it.vertex[i]; + btAssert(v.getSoftBodyIndex() >= 0); + MT_Point3 pt ( + nodes[v.getSoftBodyIndex()].m_x.getX(), + nodes[v.getSoftBodyIndex()].m_x.getY(), + nodes[v.getSoftBodyIndex()].m_x.getZ()); + v.SetXYZ(pt); + MT_Vector3 normal ( + nodes[v.getSoftBodyIndex()].m_n.getX(), + nodes[v.getSoftBodyIndex()].m_n.getY(), + nodes[v.getSoftBodyIndex()].m_n.getZ()); + v.SetNormal(normal); - if (numvalidpolys > 0) - { - - if (!polytope) + } + } + return true; + } + virtual bool Update(void) { - bool useQuantization = true; - concaveShape = new btBvhTriangleMeshShape( collisionMeshData, useQuantization ); - //concaveShape = new btTriangleMeshShape( collisionMeshData ); - - concaveShape->recalcLocalAabb(); - if (collisionMeshShape) - delete collisionMeshShape; - collisionMeshShape = concaveShape; + //printf("update\n"); + return true;//?? + } + virtual RAS_Deformer *GetReplica(class KX_GameObject* replica) + { + KX_SoftBodyDeformer* deformer = new KX_SoftBodyDeformer(replica->GetMesh(0),replica); + return deformer; + } - } - - + virtual bool SkipVertexTransform() + { + return true; + } - return collisionMeshShape; - } - if (collisionMeshShape) - delete collisionMeshShape; - if (collisionMeshData) - delete collisionMeshData; - return NULL; + protected: + //class RAS_MeshObject *m_pMesh; + }; -} +// forward declarations void KX_ConvertBulletObject( class KX_GameObject* gameobj, class RAS_MeshObject* meshobj, @@ -878,6 +784,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, bool isbulletdyna = false; CcdConstructionInfo ci; class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode()); + class CcdShapeConstructionInfo *shapeInfo = new CcdShapeConstructionInfo(); @@ -894,120 +801,99 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, ci.m_gravity = btVector3(0,0,0); ci.m_localInertiaTensor =btVector3(0,0,0); ci.m_mass = objprop->m_dyna ? shapeprops->m_mass : 0.f; + ci.m_margin = objprop->m_margin; + shapeInfo->m_radius = objprop->m_radius; isbulletdyna = objprop->m_dyna; ci.m_localInertiaTensor = btVector3(ci.m_mass/3.f,ci.m_mass/3.f,ci.m_mass/3.f); - btTransform trans; - trans.setIdentity(); - btCollisionShape* bm = 0; switch (objprop->m_boundclass) { case KX_BOUNDSPHERE: { - float radius = objprop->m_radius; - btVector3 inertiaHalfExtents ( - radius, - radius, - radius); + //float radius = objprop->m_radius; + //btVector3 inertiaHalfExtents ( + // radius, + // radius, + // radius); //blender doesn't support multisphere, but for testing: //bm = new MultiSphereShape(inertiaHalfExtents,,&trans.getOrigin(),&radius,1); - bm = new btSphereShape(objprop->m_radius); - bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); + shapeInfo->m_shapeType = PHY_SHAPE_SPHERE; + bm = shapeInfo->CreateBulletShape(); break; }; case KX_BOUNDBOX: { - MT_Vector3 halfExtents ( + shapeInfo->m_halfExtend.setValue( objprop->m_boundobject.box.m_extends[0], - objprop->m_boundobject.box.m_extends[1], - objprop->m_boundobject.box.m_extends[2]); - - halfExtents /= 2.f; - - //btVector3 he (halfExtents[0]-CONVEX_DISTANCE_MARGIN ,halfExtents[1]-CONVEX_DISTANCE_MARGIN ,halfExtents[2]-CONVEX_DISTANCE_MARGIN ); - //he = he.absolute(); - - btVector3 he (halfExtents[0],halfExtents[1],halfExtents[2]); - he = he.absolute(); - + objprop->m_boundobject.box.m_extends[1], + objprop->m_boundobject.box.m_extends[2]); - bm = new btBoxShape(he); - bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); + shapeInfo->m_halfExtend /= 2.0; + shapeInfo->m_halfExtend = shapeInfo->m_halfExtend.absolute(); + shapeInfo->m_shapeType = PHY_SHAPE_BOX; + bm = shapeInfo->CreateBulletShape(); break; }; case KX_BOUNDCYLINDER: { - btVector3 halfExtents ( + shapeInfo->m_halfExtend.setValue( objprop->m_boundobject.c.m_radius, objprop->m_boundobject.c.m_radius, objprop->m_boundobject.c.m_height * 0.5f ); - bm = new btCylinderShapeZ(halfExtents); - bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); - + shapeInfo->m_shapeType = PHY_SHAPE_CYLINDER; + bm = shapeInfo->CreateBulletShape(); break; } - case KX_BOUNDCONE: + case KX_BOUNDCONE: { - btVector3 halfExtents (objprop->m_boundobject.box.m_extends[0], - objprop->m_boundobject.box.m_extends[1], - objprop->m_boundobject.box.m_extends[2]); - - - halfExtents /= 2.f; - - bm = new btConeShapeZ(objprop->m_boundobject.c.m_radius,objprop->m_boundobject.c.m_height); - bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); - + shapeInfo->m_radius = objprop->m_boundobject.c.m_radius; + shapeInfo->m_height = objprop->m_boundobject.c.m_height; + shapeInfo->m_shapeType = PHY_SHAPE_CONE; + bm = shapeInfo->CreateBulletShape(); break; } - case KX_BOUNDPOLYTOPE: - { - bm = CreateBulletShapeFromMesh(meshobj,true); - if (bm) + case KX_BOUNDPOLYTOPE: + { + shapeInfo->SetMesh(meshobj, true,false); + bm = shapeInfo->CreateBulletShape(); + break; + } + case KX_BOUNDMESH: + { + + if (!ci.m_mass ||objprop->m_softbody) + { + // mesh shapes can be shared, check first if we already have a shape on that mesh + class CcdShapeConstructionInfo *sharedShapeInfo = CcdShapeConstructionInfo::FindMesh(meshobj, false); + if (sharedShapeInfo != NULL) { - bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); - } - break; - } - case KX_BOUNDMESH: - { - if (!ci.m_mass) - { - bm = CreateBulletShapeFromMesh(meshobj,false); - ci.m_localInertiaTensor.setValue(0.f,0.f,0.f); - //no moving concave meshes, so don't bother calculating inertia - //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); + delete shapeInfo; + shapeInfo = sharedShapeInfo; + shapeInfo->AddRef(); + } else + { + shapeInfo->SetMesh(meshobj, false,false); } + if (objprop->m_softbody) + shapeInfo->setVertexWeldingThreshold(0.01f); //todo: expose this to the UI - break; - } - - default: - //interpret the shape as a concave triangle-mesh - { - if (meshobj) + bm = shapeInfo->CreateBulletShape(); + //no moving concave meshes, so don't bother calculating inertia + //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor); + } else { - bm = CreateBulletShapeFromMesh(meshobj,false); - ci.m_localInertiaTensor.setValue(0.f,0.f,0.f); - - // assert(0); - - /* - meshobj->ScheduleCollisionPolygons(); - - KX_DeformableMesh* gfxmesh = new KX_DeformableMesh(meshobj); - gfxmesh->sendFixedMapping(); - //trianglemesh - bm = new TriangleMeshInterface(gfxmesh,trans); - */ + shapeInfo->SetMesh(meshobj, false,true); + bm = shapeInfo->CreateBulletShape(); } + + break; } } @@ -1017,11 +903,11 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, if (!bm) { delete motionstate; + delete shapeInfo; return; } - bm->setMargin(0.06); - + bm->setMargin(ci.m_margin); if (objprop->m_isCompoundChild) @@ -1030,31 +916,46 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, //take relative transform into account! KX_BulletPhysicsController* parentCtrl = (KX_BulletPhysicsController*)objprop->m_dynamic_parent->GetPhysicsController(); assert(parentCtrl); + CcdShapeConstructionInfo* parentShapeInfo = parentCtrl->GetShapeInfo(); btRigidBody* rigidbody = parentCtrl->GetRigidBody(); btCollisionShape* colShape = rigidbody->getCollisionShape(); assert(colShape->isCompound()); btCompoundShape* compoundShape = (btCompoundShape*)colShape; - btTransform childTrans; - childTrans.setIdentity(); - NodeList& children = objprop->m_dynamic_parent->GetSGNode()->GetSGChildren(); - MT_Point3 childPos = gameobj->GetSGNode()->GetLocalPosition(); - MT_Matrix3x3 childRot = gameobj->GetSGNode()->GetLocalOrientation(); - MT_Vector3 childScale = gameobj->GetSGNode()->GetLocalScale(); + // compute the local transform from parent, this may include a parent inverse node + SG_Node* gameNode = gameobj->GetSGNode(); + SG_Node* parentInverseNode = gameNode->GetSGParent(); + if (parentInverseNode && parentInverseNode->GetSGClientObject() != NULL) + // this is not a parent inverse node, cancel it + parentInverseNode = NULL; + // now combine the parent inverse node and the game node + MT_Point3 childPos = gameNode->GetLocalPosition(); + MT_Matrix3x3 childRot = gameNode->GetLocalOrientation(); + MT_Vector3 childScale = gameNode->GetLocalScale(); + if (parentInverseNode) + { + const MT_Point3& parentInversePos = parentInverseNode->GetLocalPosition(); + const MT_Matrix3x3& parentInverseRot = parentInverseNode->GetLocalOrientation(); + const MT_Vector3& parentInverseScale = parentInverseNode->GetLocalScale(); + childRot = parentInverseRot * childRot; + childScale = parentInverseScale * childScale; + childPos = parentInversePos+parentInverseScale*(parentInverseRot*childPos); + } - bm->setLocalScaling(btVector3(childScale.x(),childScale.y(),childScale.z())); - childTrans.setOrigin(btVector3(childPos.x(),childPos.y(),childPos.z())); + shapeInfo->m_childScale.setValue(childScale.x(),childScale.y(),childScale.z()); + bm->setLocalScaling(shapeInfo->m_childScale); + + shapeInfo->m_childTrans.setOrigin(btVector3(childPos.x(),childPos.y(),childPos.z())); float rotval[12]; childRot.getValue(rotval); btMatrix3x3 newRot; newRot.setValue(rotval[0],rotval[1],rotval[2],rotval[4],rotval[5],rotval[6],rotval[8],rotval[9],rotval[10]); newRot = newRot.transpose(); - childTrans.setBasis(newRot); - - - compoundShape->addChildShape(childTrans,bm); - kxscene->AddShape(bm); + shapeInfo->m_childTrans.setBasis(newRot); + parentShapeInfo->AddShape(shapeInfo); + + compoundShape->addChildShape(shapeInfo->m_childTrans,bm); //do some recalc? //recalc inertia for rigidbody if (!rigidbody->isStaticOrKinematicObject()) @@ -1069,15 +970,16 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, if (objprop->m_hasCompoundChildren) { - //replace shape by compoundShape + // create a compound shape info + CcdShapeConstructionInfo *compoundShapeInfo = new CcdShapeConstructionInfo(); + compoundShapeInfo->m_shapeType = PHY_SHAPE_COMPOUND; + compoundShapeInfo->AddShape(shapeInfo); + // create the compound shape manually as we already have the child shape btCompoundShape* compoundShape = new btCompoundShape(); - btTransform identTrans; - identTrans.setIdentity(); - compoundShape->addChildShape(identTrans,bm); - //note abount compoundShape: Bullet does not delete the child shapes when - //the compound shape is deleted, so insert also the child shapes - kxscene->AddShape(bm); + compoundShape->addChildShape(shapeInfo->m_childTrans,bm); + // now replace the shape bm = compoundShape; + shapeInfo = compoundShapeInfo; } @@ -1113,6 +1015,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, ci.m_collisionShape = bm; + ci.m_shapeInfo = shapeInfo; ci.m_friction = smmaterial->m_friction;//tweak the friction a bit, so the default 0.5 works nice ci.m_restitution = smmaterial->m_restitution; ci.m_physicsEnv = env; @@ -1121,12 +1024,70 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, ci.m_angularDamping = 1.f - shapeprops->m_ang_drag; //need a bit of damping, else system doesn't behave well ci.m_inertiaFactor = shapeprops->m_inertia/0.4f;//defaults to 0.4, don't want to change behaviour + + ci.m_do_anisotropic = shapeprops->m_do_anisotropic; + ci.m_anisotropicFriction.setValue(shapeprops->m_friction_scaling[0],shapeprops->m_friction_scaling[1],shapeprops->m_friction_scaling[2]); + + +////////// + //do Fh, do Rot Fh + ci.m_do_fh = shapeprops->m_do_fh; + ci.m_do_rot_fh = shapeprops->m_do_rot_fh ; + ci.m_fh_damping = smmaterial->m_fh_damping; + ci.m_fh_distance = smmaterial->m_fh_distance; + ci.m_fh_normal = smmaterial->m_fh_normal; + ci.m_fh_spring = smmaterial->m_fh_spring; + ci.m_radius = objprop->m_radius; + + + /////////////////// + ci.m_gamesoftFlag = objprop->m_gamesoftFlag; + ci.m_soft_linStiff = objprop->m_soft_linStiff; + ci.m_soft_angStiff = objprop->m_soft_angStiff; /* angular stiffness 0..1 */ + ci.m_soft_volume= objprop->m_soft_volume; /* volume preservation 0..1 */ + + ci.m_soft_viterations= objprop->m_soft_viterations; /* Velocities solver iterations */ + ci.m_soft_piterations= objprop->m_soft_piterations; /* Positions solver iterations */ + ci.m_soft_diterations= objprop->m_soft_diterations; /* Drift solver iterations */ + ci.m_soft_citerations= objprop->m_soft_citerations; /* Cluster solver iterations */ + + ci.m_soft_kSRHR_CL= objprop->m_soft_kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */ + ci.m_soft_kSKHR_CL= objprop->m_soft_kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */ + ci.m_soft_kSSHR_CL= objprop->m_soft_kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */ + ci.m_soft_kSR_SPLT_CL= objprop->m_soft_kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + + ci.m_soft_kSK_SPLT_CL= objprop->m_soft_kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + ci.m_soft_kSS_SPLT_CL= objprop->m_soft_kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + ci.m_soft_kVCF= objprop->m_soft_kVCF; /* Velocities correction factor (Baumgarte) */ + ci.m_soft_kDP= objprop->m_soft_kDP; /* Damping coefficient [0,1] */ + + ci.m_soft_kDG= objprop->m_soft_kDG; /* Drag coefficient [0,+inf] */ + ci.m_soft_kLF= objprop->m_soft_kLF; /* Lift coefficient [0,+inf] */ + ci.m_soft_kPR= objprop->m_soft_kPR; /* Pressure coefficient [-inf,+inf] */ + ci.m_soft_kVC= objprop->m_soft_kVC; /* Volume conversation coefficient [0,+inf] */ + + ci.m_soft_kDF= objprop->m_soft_kDF; /* Dynamic friction coefficient [0,1] */ + ci.m_soft_kMT= objprop->m_soft_kMT; /* Pose matching coefficient [0,1] */ + ci.m_soft_kCHR= objprop->m_soft_kCHR; /* Rigid contacts hardness [0,1] */ + ci.m_soft_kKHR= objprop->m_soft_kKHR; /* Kinetic contacts hardness [0,1] */ + + ci.m_soft_kSHR= objprop->m_soft_kSHR; /* Soft contacts hardness [0,1] */ + ci.m_soft_kAHR= objprop->m_soft_kAHR; /* Anchors hardness [0,1] */ + ci.m_soft_collisionflags= objprop->m_soft_collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */ + ci.m_soft_numclusteriterations= objprop->m_soft_numclusteriterations; /* number of iterations to refine collision clusters*/ + + //////////////////// + ci.m_collisionFilterGroup = (isbulletdyna) ? short(CcdConstructionInfo::DefaultFilter) : short(CcdConstructionInfo::StaticFilter); ci.m_collisionFilterMask = (isbulletdyna) ? short(CcdConstructionInfo::AllFilter) : short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter); ci.m_bRigid = objprop->m_dyna && objprop->m_angular_rigidbody; + ci.m_bSoft = objprop->m_softbody; + MT_Vector3 scaling = gameobj->NodeGetWorldScaling(); + ci.m_scaling.setValue(scaling[0], scaling[1], scaling[2]); KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna); - //remember that we created a shape so that we can delete it when the scene is removed (bullet will not delete it) - kxscene->AddShape(bm); + // shapeInfo is reference counted, decrement now as we don't use it anymore + if (shapeInfo) + shapeInfo->Release(); if (objprop->m_in_active_layer) { @@ -1137,10 +1098,16 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, gameobj->SetPhysicsController(physicscontroller,isbulletdyna); physicscontroller->setNewClientInfo(gameobj->getClientInfo()); - btRigidBody* rbody = physicscontroller->GetRigidBody(); + { + btRigidBody* rbody = physicscontroller->GetRigidBody(); + + if (rbody && objprop->m_disableSleeping) + rbody->setActivationState(DISABLE_DEACTIVATION); + } + + CcdPhysicsController* parentCtrl = objprop->m_dynamic_parent ? (KX_BulletPhysicsController*)objprop->m_dynamic_parent->GetPhysicsController() : 0; + physicscontroller->setParentCtrl(parentCtrl); - if (objprop->m_disableSleeping) - rbody->setActivationState(DISABLE_DEACTIVATION); //Now done directly in ci.m_collisionFlags so that it propagates to replica //if (objprop->m_ghost) @@ -1189,6 +1156,20 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, physicscontroller->SetObject(gameobj->GetSGNode()); + + ///test for soft bodies + if (objprop->m_softbody && physicscontroller) + { + btSoftBody* softBody = physicscontroller->GetSoftBody(); + if (softBody && gameobj->GetMesh(0))//only the first mesh, if any + { + //should be a mesh then, so add a soft body deformer + KX_SoftBodyDeformer* softbodyDeformer = new KX_SoftBodyDeformer( gameobj->GetMesh(0),gameobj); + gameobj->SetDeformer(softbodyDeformer); + + } + } + } diff --git a/source/gameengine/Ketsji/KX_GameActuator.cpp b/source/gameengine/Ketsji/KX_GameActuator.cpp index fcd32d5f4fe..76459e46731 100644 --- a/source/gameengine/Ketsji/KX_GameActuator.cpp +++ b/source/gameengine/Ketsji/KX_GameActuator.cpp @@ -34,6 +34,7 @@ //#include <iostream> #include "KX_Scene.h" #include "KX_KetsjiEngine.h" +#include "KX_PythonInit.h" /* for config load/saving */ #ifdef HAVE_CONFIG_H #include <config.h> @@ -125,6 +126,71 @@ bool KX_GameActuator::Update() } break; } + case KX_GAME_SAVECFG: + { + if (m_ketsjiengine) + { + char mashal_path[512]; + char *marshal_buffer = NULL; + int marshal_length; + FILE *fp = NULL; + + pathGamePythonConfig(mashal_path); + marshal_length = saveGamePythonConfig(&marshal_buffer); + + if (marshal_length && marshal_buffer) { + fp = fopen(mashal_path, "wb"); + if (fp) { + if (fwrite(marshal_buffer, 1, marshal_length, fp) != marshal_length) { + printf("Warning: could not write marshal data\n"); + } + fclose(fp); + } else { + printf("Warning: could not open marshal file\n"); + } + } else { + printf("Warning: could not create marshal buffer\n"); + } + } + break; + } + case KX_GAME_LOADCFG: + { + if (m_ketsjiengine) + { + char mashal_path[512]; + char *marshal_buffer; + int marshal_length; + FILE *fp = NULL; + int result; + + pathGamePythonConfig(mashal_path); + + fp = fopen(mashal_path, "rb"); + if (fp) { + // obtain file size: + fseek (fp , 0 , SEEK_END); + marshal_length = ftell(fp); + rewind(fp); + + marshal_buffer = (char*) malloc (sizeof(char)*marshal_length); + + result = fread (marshal_buffer, 1, marshal_length, fp); + + if (result == marshal_length) { + loadGamePythonConfig(marshal_buffer, marshal_length); + } else { + printf("warning: could not read all of '%s'\n", mashal_path); + } + + free(marshal_buffer); + fclose(fp); + } else { + printf("warning: could not open '%s'\n", mashal_path); + } + } + break; + } default: ; /* do nothing? this is an internal error !!! */ } @@ -175,13 +241,13 @@ PyParentObject KX_GameActuator::Parents[] = PyMethodDef KX_GameActuator::Methods[] = { - {"getFile", (PyCFunction) KX_GameActuator::sPyGetFile, METH_VARARGS, GetFile_doc}, - {"setFile", (PyCFunction) KX_GameActuator::sPySetFile, METH_VARARGS, SetFile_doc}, + {"getFile", (PyCFunction) KX_GameActuator::sPyGetFile, METH_VARARGS, (PY_METHODCHAR)GetFile_doc}, + {"setFile", (PyCFunction) KX_GameActuator::sPySetFile, METH_VARARGS, (PY_METHODCHAR)SetFile_doc}, {NULL,NULL} //Sentinel }; /* getFile */ -char KX_GameActuator::GetFile_doc[] = +const char KX_GameActuator::GetFile_doc[] = "getFile()\n" "get the name of the file to start.\n"; PyObject* KX_GameActuator::PyGetFile(PyObject* self, PyObject* args, PyObject* kwds) @@ -190,7 +256,7 @@ PyObject* KX_GameActuator::PyGetFile(PyObject* self, PyObject* args, PyObject* k } /* setFile */ -char KX_GameActuator::SetFile_doc[] = +const char KX_GameActuator::SetFile_doc[] = "setFile(name)\n" "set the name of the file to start.\n"; PyObject* KX_GameActuator::PySetFile(PyObject* self, PyObject* args, PyObject* kwds) diff --git a/source/gameengine/Ketsji/KX_GameActuator.h b/source/gameengine/Ketsji/KX_GameActuator.h index 8565dc46caa..bb3448995dc 100644 --- a/source/gameengine/Ketsji/KX_GameActuator.h +++ b/source/gameengine/Ketsji/KX_GameActuator.h @@ -54,6 +54,8 @@ protected: KX_GAME_START, KX_GAME_RESTART, KX_GAME_QUIT, + KX_GAME_SAVECFG, + KX_GAME_LOADCFG, KX_GAME_MAX }; diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 700cc00e996..1b57b9acc1d 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -51,6 +51,7 @@ typedef unsigned long uint_ptr; #include "KX_GameObject.h" #include "RAS_MeshObject.h" #include "KX_MeshProxy.h" +#include "KX_PolyProxy.h" #include <stdio.h> // printf #include "SG_Controller.h" #include "KX_IPhysicsController.h" @@ -64,6 +65,8 @@ typedef unsigned long uint_ptr; #include "SCA_IActuator.h" #include "SCA_ISensor.h" +#include "PyObjectPlus.h" /* python stuff */ + // This file defines relationships between parents and children // in the game engine. @@ -78,12 +81,15 @@ KX_GameObject::KX_GameObject( m_bDyna(false), m_layer(0), m_pBlenderObject(NULL), + m_pBlenderGroupObject(NULL), m_bSuspendDynamics(false), m_bUseObjectColor(false), m_bIsNegativeScaling(false), m_bVisible(true), + m_bCulled(true), m_pPhysicsController1(NULL), m_pPhysicsEnvironment(NULL), + m_xray(false), m_pHitObject(NULL), m_isDeformable(false) { @@ -99,8 +105,11 @@ KX_GameObject::KX_GameObject( }; + KX_GameObject::~KX_GameObject() { + RemoveMeshes(); + // is this delete somewhere ? //if (m_sumoObj) // delete m_sumoObj; @@ -162,7 +171,6 @@ STR_String KX_GameObject::GetName() void KX_GameObject::SetName(STR_String name) { m_name = name; - }; // Set the name of the value @@ -227,11 +235,12 @@ void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj) m_pPhysicsController1->SuspendDynamics(true); } // Set us to our new scale, position, and orientation - scale1[0] = scale1[0]/scale2[0]; - scale1[1] = scale1[1]/scale2[1]; - scale1[2] = scale1[2]/scale2[2]; + scale2[0] = 1.0/scale2[0]; + scale2[1] = 1.0/scale2[1]; + scale2[2] = 1.0/scale2[2]; + scale1 = scale1 * scale2; MT_Matrix3x3 invori = obj->NodeGetWorldOrientation().inverse(); - MT_Vector3 newpos = invori*(NodeGetWorldPosition()-obj->NodeGetWorldPosition())*scale1; + MT_Vector3 newpos = invori*(NodeGetWorldPosition()-obj->NodeGetWorldPosition())*scale2; NodeSetLocalScale(scale1); NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2])); @@ -283,11 +292,11 @@ void KX_GameObject::ProcessReplica(KX_GameObject* replica) CValue* KX_GameObject::GetReplica() { KX_GameObject* replica = new KX_GameObject(*this); - + // this will copy properties and so on... CValue::AddDataToReplica(replica); ProcessReplica(replica); - + return replica; } @@ -353,24 +362,47 @@ double* KX_GameObject::GetOpenGLMatrix() return fl; } +void KX_GameObject::AddMeshUser() +{ + for (size_t i=0;i<m_meshes.size();i++) + m_meshes[i]->AddMeshUser(this); + + UpdateBuckets(false); +} +static void UpdateBuckets_recursive(SG_Node* node) +{ + NodeList& children = node->GetSGChildren(); -void KX_GameObject::Bucketize() + for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) + { + SG_Node* childnode = (*childit); + KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); + if (clientgameobj != NULL) // This is a GameObject + clientgameobj->UpdateBuckets(0); + + // if the childobj is NULL then this may be an inverse parent link + // so a non recursive search should still look down this node. + UpdateBuckets_recursive(childnode); + } +} + +void KX_GameObject::UpdateBuckets( bool recursive ) { double* fl = GetOpenGLMatrix(); for (size_t i=0;i<m_meshes.size();i++) - m_meshes[i]->Bucketize(fl, this, m_bUseObjectColor, m_objectColor); + m_meshes[i]->UpdateBuckets(this, fl, m_bUseObjectColor, m_objectColor, m_bVisible, m_bCulled); + + if (recursive) { + UpdateBuckets_recursive(m_pSGNode); + } } - - void KX_GameObject::RemoveMeshes() { - double* fl = GetOpenGLMatrix(); - for (size_t i=0;i<m_meshes.size();i++) - m_meshes[i]->RemoveFromBuckets(fl, this); + m_meshes[i]->RemoveFromBuckets(this); //note: meshes can be shared, and are deleted by KX_BlenderSceneConverter @@ -453,13 +485,14 @@ KX_GameObject::UpdateMaterialData( ) { int mesh = 0; - if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0) { - RAS_MaterialBucket::Set::iterator mit = m_meshes[mesh]->GetFirstMaterial(); + list<RAS_MeshMaterial>::iterator mit = m_meshes[mesh]->GetFirstMaterial(); + for(; mit != m_meshes[mesh]->GetLastMaterial(); ++mit) { - RAS_IPolyMaterial* poly = (*mit)->GetPolyMaterial(); - if(poly->GetFlag() & RAS_BLENDERMAT) + RAS_IPolyMaterial* poly = mit->m_bucket->GetPolyMaterial(); + + if(poly->GetFlag() & RAS_BLENDERMAT ) { KX_BlenderMaterial *m = static_cast<KX_BlenderMaterial*>(poly); @@ -467,8 +500,7 @@ KX_GameObject::UpdateMaterialData( { m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha); // if mesh has only one material attached to it then use original hack with no need to edit vertices (better performance) - if(!(poly->GetFlag() & RAS_BLENDERGLSL)) - SetObjectColor(rgba); + SetObjectColor(rgba); } else { @@ -494,72 +526,75 @@ KX_GameObject::GetVisible( return m_bVisible; } +static void setVisible_recursive(SG_Node* node, bool v) +{ + NodeList& children = node->GetSGChildren(); + + for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) + { + SG_Node* childnode = (*childit); + KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); + if (clientgameobj != NULL) // This is a GameObject + clientgameobj->SetVisible(v, 0); + + // if the childobj is NULL then this may be an inverse parent link + // so a non recursive search should still look down this node. + setVisible_recursive(childnode, v); + } +} + + void KX_GameObject::SetVisible( - bool v + bool v, + bool recursive ) { m_bVisible = v; + if (recursive) + setVisible_recursive(m_pSGNode, v); } -void -KX_GameObject::SetLayer( - int l +bool +KX_GameObject::GetCulled( + void ) { - m_layer = l; + return m_bCulled; } -int -KX_GameObject::GetLayer( - void +void +KX_GameObject::SetCulled( + bool c ) { - return m_layer; + m_bCulled = c; } -// used by Python, and the actuatorshould _not_ be misused by the -// scene! -void -KX_GameObject::MarkVisible( - bool visible + +void +KX_GameObject::SetLayer( + int l ) { - /* If explicit visibility settings are used, this is - * determined on this level. Maybe change this to mesh level - * later on? */ - - double* fl = GetOpenGLMatrixPtr()->getPointer(); - for (size_t i=0;i<m_meshes.size();i++) - { - m_meshes[i]->MarkVisible(fl,this,visible,m_bUseObjectColor,m_objectColor); - } + m_layer = l; } - -// Always use the flag? -void -KX_GameObject::MarkVisible( +int +KX_GameObject::GetLayer( void ) { - double* fl = GetOpenGLMatrixPtr()->getPointer(); - for (size_t i=0;i<m_meshes.size();i++) - { - m_meshes[i]->MarkVisible(fl, - this, - m_bVisible, - m_bUseObjectColor, - m_objectColor - ); - } + return m_layer; } - void KX_GameObject::addLinearVelocity(const MT_Vector3& lin_vel,bool local) { - if (m_pPhysicsController1) - m_pPhysicsController1->SetLinearVelocity(lin_vel + m_pPhysicsController1->GetLinearVelocity(),local); + if (m_pPhysicsController1) + { + MT_Vector3 lv = local ? NodeGetWorldOrientation() * lin_vel : lin_vel; + m_pPhysicsController1->SetLinearVelocity(lv + m_pPhysicsController1->GetLinearVelocity(), 0); + } } @@ -737,7 +772,14 @@ MT_Vector3 KX_GameObject::GetAngularVelocity(bool local) return velocity; } - +MT_Vector3 KX_GameObject::GetVelocity(const MT_Point3& point) +{ + if (m_pPhysicsController1) + { + return m_pPhysicsController1->GetVelocity(point); + } + return MT_Vector3(0.0,0.0,0.0); +} // scenegraph node stuff @@ -788,7 +830,17 @@ void KX_GameObject::NodeSetLocalScale(const MT_Vector3& scale) void KX_GameObject::NodeSetRelativeScale(const MT_Vector3& scale) { if (GetSGNode()) + { GetSGNode()->RelativeScale(scale); + if (m_pPhysicsController1 && (!GetSGNode()->GetSGParent())) + { + // see note above + // we can use the local scale: it's the same thing for a root object + // and the world scale is not yet updated + MT_Vector3 newscale = GetSGNode()->GetLocalScale(); + m_pPhysicsController1->setScaling(newscale); + } + } } void KX_GameObject::NodeSetWorldPosition(const MT_Point3& trans) @@ -883,15 +935,18 @@ void KX_GameObject::Suspend() PyMethodDef KX_GameObject::Methods[] = { {"getPosition", (PyCFunction) KX_GameObject::sPyGetPosition, METH_NOARGS}, {"setPosition", (PyCFunction) KX_GameObject::sPySetPosition, METH_O}, + {"setWorldPosition", (PyCFunction) KX_GameObject::sPySetWorldPosition, METH_O}, {"getLinearVelocity", (PyCFunction) KX_GameObject::sPyGetLinearVelocity, METH_VARARGS}, {"setLinearVelocity", (PyCFunction) KX_GameObject::sPySetLinearVelocity, METH_VARARGS}, + {"getAngularVelocity", (PyCFunction) KX_GameObject::sPyGetAngularVelocity, METH_VARARGS}, + {"setAngularVelocity", (PyCFunction) KX_GameObject::sPySetAngularVelocity, METH_VARARGS}, {"getVelocity", (PyCFunction) KX_GameObject::sPyGetVelocity, METH_VARARGS}, {"getMass", (PyCFunction) KX_GameObject::sPyGetMass, METH_NOARGS}, {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_NOARGS}, {"getOrientation", (PyCFunction) KX_GameObject::sPyGetOrientation, METH_NOARGS}, {"setOrientation", (PyCFunction) KX_GameObject::sPySetOrientation, METH_O}, {"getVisible",(PyCFunction) KX_GameObject::sPyGetVisible, METH_NOARGS}, - {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_O}, + {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS}, {"getState",(PyCFunction) KX_GameObject::sPyGetState, METH_NOARGS}, {"setState",(PyCFunction) KX_GameObject::sPySetState, METH_O}, {"alignAxisToVect",(PyCFunction) KX_GameObject::sPyAlignAxisToVect, METH_VARARGS}, @@ -1032,18 +1087,23 @@ PyObject* KX_GameObject::_getattr(const STR_String& attr) int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr method { - if (attr == "mass") + if (attr == "mass") { + PyErr_SetString(PyExc_AttributeError, "attribute \"mass\" is read only"); return 1; + } - if (attr == "parent") + if (attr == "parent") { + PyErr_SetString(PyExc_AttributeError, "attribute \"mass\" is read only\nUse setParent()"); return 1; + } if (PyInt_Check(value)) { int val = PyInt_AsLong(value); if (attr == "visible") { - SetVisible(val != 0); + SetVisible(val != 0, false); + UpdateBuckets(false); return 0; } } @@ -1102,7 +1162,7 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr } return 1; } - + PyErr_SetString(PyExc_AttributeError, "could not set the orientation from a 3x3 matrix, quaternion or euler sequence"); return 1; } @@ -1146,9 +1206,7 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr } -PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self, PyObject* args) { // only can get the velocity if we have a physics object connected to us... int local = 0; @@ -1162,9 +1220,7 @@ PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self, } } -PyObject* KX_GameObject::PySetLinearVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PySetLinearVelocity(PyObject* self, PyObject* args) { int local = 0; PyObject* pyvect; @@ -1179,17 +1235,43 @@ PyObject* KX_GameObject::PySetLinearVelocity(PyObject* self, return NULL; } -PyObject* KX_GameObject::PySetVisible(PyObject* self, PyObject* value) +PyObject* KX_GameObject::PyGetAngularVelocity(PyObject* self, PyObject* args) { - int visible = PyInt_AsLong(value); - - if (visible==-1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "expected 0 or 1"); + // only can get the velocity if we have a physics object connected to us... + int local = 0; + if (PyArg_ParseTuple(args,"|i",&local)) + { + return PyObjectFrom(GetAngularVelocity((local!=0))); + } + else + { return NULL; } +} + +PyObject* KX_GameObject::PySetAngularVelocity(PyObject* self, PyObject* args) +{ + int local = 0; + PyObject* pyvect; + + if (PyArg_ParseTuple(args,"O|i",&pyvect,&local)) { + MT_Vector3 velocity; + if (PyVecTo(pyvect, velocity)) { + setAngularVelocity(velocity, (local!=0)); + Py_RETURN_NONE; + } + } + return NULL; +} + +PyObject* KX_GameObject::PySetVisible(PyObject* self, PyObject* args) +{ + int visible, recursive = 0; + if (!PyArg_ParseTuple(args,"i|i",&visible, &recursive)) + return NULL; - MarkVisible(visible!=0); - m_bVisible = (visible!=0); + SetVisible(visible ? true:false, recursive ? true:false); + UpdateBuckets(recursive ? true:false); Py_RETURN_NONE; } @@ -1228,9 +1310,7 @@ PyObject* KX_GameObject::PySetState(PyObject* self, PyObject* value) -PyObject* KX_GameObject::PyGetVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyGetVelocity(PyObject* self, PyObject* args) { // only can get the velocity if we have a physics object connected to us... MT_Vector3 velocity(0.0,0.0,0.0); @@ -1362,9 +1442,7 @@ PyObject* KX_GameObject::PyGetChildrenRecursive(PyObject* self) return list; } -PyObject* KX_GameObject::PyGetMesh(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyGetMesh(PyObject* self, PyObject* args) { int mesh = 0; @@ -1404,9 +1482,7 @@ PyObject* KX_GameObject::PySetCollisionMargin(PyObject* self, PyObject* value) -PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, PyObject* args) { PyObject* pyattach; PyObject* pyimpulse; @@ -1477,9 +1553,7 @@ PyObject* KX_GameObject::PySetOrientation(PyObject* self, PyObject* value) return NULL; } -PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* self, PyObject* args) { PyObject* pyvect; int axis = 2; //z axis is the default @@ -1524,6 +1598,19 @@ PyObject* KX_GameObject::PySetPosition(PyObject* self, PyObject* value) return NULL; } +PyObject* KX_GameObject::PySetWorldPosition(PyObject* self, PyObject* value) +{ + MT_Point3 pos; + if (PyVecTo(value, pos)) + { + NodeSetWorldPosition(pos); + NodeUpdateGS(0.f,true); + Py_RETURN_NONE; + } + + return NULL; +} + PyObject* KX_GameObject::PyGetPhysicsId(PyObject* self) { KX_IPhysicsController* ctrl = GetPhysicsController(); @@ -1609,25 +1696,45 @@ KX_PYMETHODDEF_DOC(KX_GameObject, getVectTo, return returnValue; } -bool KX_GameObject::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_GameObject::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { + KX_GameObject* hitKXObj = client->m_gameobject; + + // if X-ray option is selected, the unwnted objects were not tested, so get here only with true hit + // if not, all objects were tested and the front one may not be the correct one. + if (m_xray || m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL) + { + m_pHitObject = hitKXObj; + return true; + } + // return true to stop RayCast::RayTest from looping, the above test was decisive + // We would want to loop only if we want to get more than one hit point + return true; +} +/* this function is used to pre-filter the object before casting the ray on them. + This is useful for "X-Ray" option when we want to see "through" unwanted object. + */ +bool KX_GameObject::NeedRayCast(KX_ClientObjectInfo* client) +{ KX_GameObject* hitKXObj = client->m_gameobject; if (client->m_type > KX_ClientObjectInfo::ACTOR) { - // false hit + // Unknown type of object, skip it. + // Should not occur as the sensor objects are filtered in RayTest() + printf("Invalid client type %d found in ray casting\n", client->m_type); return false; } - - if (m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL) + + // if X-Ray option is selected, skip object that don't match the criteria as we see through them + // if not, test all objects because we don't know yet which one will be on front + if (!m_xray || m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL) { - m_pHitObject = hitKXObj; return true; } - + // skip the object return false; - } KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, @@ -1667,8 +1774,6 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, toPoint = fromPoint + (dist) * toDir; } - MT_Point3 resultPoint; - MT_Vector3 resultNormal; PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment(); KX_IPhysicsController *spc = GetPhysicsController(); KX_GameObject *parent = GetParent(); @@ -1682,7 +1787,8 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, m_testPropName = propName; else m_testPropName.SetLength(0); - KX_RayCast::RayTest(spc, pe, fromPoint, toPoint, resultPoint, resultNormal, KX_RayCast::Callback<KX_GameObject>(this)); + KX_RayCast::Callback<KX_GameObject> callback(this,spc); + KX_RayCast::RayTest(pe, fromPoint, toPoint, callback); if (m_pHitObject) { @@ -1693,13 +1799,24 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, } KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, - "rayCast(to,from,dist,prop): cast a ray and return tuple (object,hit,normal) of contact point with object within dist that matches prop or (None,None,None) tuple if no hit\n" -" prop = property name that object must have; can be omitted => detect any object\n" -" dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to to\n" + "rayCast(to,from,dist,prop,face,xray,poly): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) of contact point with object within dist that matches prop.\n" + " If no hit, return (None,None,None) or (None,None,None,None).\n" +" to = 3-tuple or object reference for destination of ray (if object, use center of object)\n" " from = 3-tuple or object reference for origin of ray (if object, use center of object)\n" " Can be None or omitted => start from self object center\n" -" to = 3-tuple or object reference for destination of ray (if object, use center of object)\n" -"Note: the object on which you call this method matters: the ray will ignore it if it goes through it\n") +" dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to to\n" +" prop = property name that object must have; can be omitted => detect any object\n" +" face = normal option: 1=>return face normal; 0 or omitted => normal is oriented towards origin\n" +" xray = X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object\n" +" poly = polygon option: 1=>return value is a 4-tuple and the 4th element is a KX_PolyProxy object\n" +" which can be None if hit object has no mesh or if there is no hit\n" +" If 0 or omitted, return value is a 3-tuple\n" +"Note: The object on which you call this method matters: the ray will ignore it.\n" +" prop and xray option interact as follow:\n" +" prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray\n" +" prop off, xray on : idem\n" +" prop on, xray off: return closest hit if it matches prop, no hit otherwise\n" +" prop on, xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray\n") { MT_Point3 toPoint; MT_Point3 fromPoint; @@ -1708,8 +1825,9 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, float dist = 0.0f; char *propName = NULL; KX_GameObject *other; + int face=0, xray=0, poly=0; - if (!PyArg_ParseTuple(args,"O|Ofs", &pyto, &pyfrom, &dist, &propName)) { + if (!PyArg_ParseTuple(args,"O|Ofsiii", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly)) { return NULL; // Python sets a simple error } @@ -1755,8 +1873,6 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, return Py_BuildValue("OOO", Py_None, Py_None, Py_None); } - MT_Point3 resultPoint; - MT_Vector3 resultNormal; PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment(); KX_IPhysicsController *spc = GetPhysicsController(); KX_GameObject *parent = GetParent(); @@ -1770,20 +1886,41 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, m_testPropName = propName; else m_testPropName.SetLength(0); - KX_RayCast::RayTest(spc, pe, fromPoint, toPoint, resultPoint, resultNormal, KX_RayCast::Callback<KX_GameObject>(this)); + m_xray = xray; + // to get the hit results + KX_RayCast::Callback<KX_GameObject> callback(this,spc,NULL,face); + KX_RayCast::RayTest(pe, fromPoint, toPoint, callback); - if (m_pHitObject) + if (m_pHitObject) { - PyObject* returnValue = PyTuple_New(3); + PyObject* returnValue = (poly) ? PyTuple_New(4) : PyTuple_New(3); if (returnValue) { // unlikely this would ever fail, if it does python sets an error PyTuple_SET_ITEM(returnValue, 0, m_pHitObject->AddRef()); - PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(resultPoint)); - PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(resultNormal)); + PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(callback.m_hitPoint)); + PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(callback.m_hitNormal)); + if (poly) + { + if (callback.m_hitMesh) + { + // if this field is set, then we can trust that m_hitPolygon is a valid polygon + RAS_Polygon* poly = callback.m_hitMesh->GetPolygon(callback.m_hitPolygon); + KX_PolyProxy* polyproxy = new KX_PolyProxy(callback.m_hitMesh, poly); + PyTuple_SET_ITEM(returnValue, 3, polyproxy); + } + else + { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(returnValue, 3, Py_None); + } + } } return returnValue; } - return Py_BuildValue("OOO", Py_None, Py_None, Py_None); - //Py_RETURN_NONE; + // no hit + if (poly) + return Py_BuildValue("OOOO", Py_None, Py_None, Py_None, Py_None); + else + return Py_BuildValue("OOO", Py_None, Py_None, Py_None); } /* --------------------------------------------------------------------- diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index a7ac2d75a93..472d31362dd 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -54,6 +54,7 @@ //Forward declarations. struct KX_ClientObjectInfo; +class KX_RayCast; class RAS_MeshObject; class KX_IPhysicsController; class PHY_IPhysicsEnvironment; @@ -74,20 +75,23 @@ protected: int m_layer; std::vector<RAS_MeshObject*> m_meshes; struct Object* m_pBlenderObject; + struct Object* m_pBlenderGroupObject; bool m_bSuspendDynamics; bool m_bUseObjectColor; bool m_bIsNegativeScaling; MT_Vector4 m_objectColor; - // Is this object set to be visible? Only useful for the - // visibility subsystem right now. - bool m_bVisible; + // visible = user setting + // culled = while rendering, depending on camera + bool m_bVisible; + bool m_bCulled; KX_IPhysicsController* m_pPhysicsController1; // used for ray casting PHY_IPhysicsEnvironment* m_pPhysicsEnvironment; STR_String m_testPropName; + bool m_xray; KX_GameObject* m_pHitObject; SG_Node* m_pSGNode; @@ -260,6 +264,15 @@ public: bool local=false ); + /** + * Return the linear velocity of a given point in world coordinate + * but relative to center of object ([0,0,0]=center of object) + */ + MT_Vector3 + GetVelocity( + const MT_Point3& position + ); + /** * Return the mass of the object */ @@ -328,6 +341,14 @@ public: m_pPhysicsController1 = physicscontroller; } + virtual class RAS_Deformer* GetDeformer() + { + return 0; + } + virtual void SetDeformer(class RAS_Deformer* deformer) + { + + } /** * @section Coordinate system manipulation functions @@ -393,6 +414,16 @@ public: { m_pBlenderObject = obj; } + + struct Object* GetBlenderGroupObject( ) + { + return m_pBlenderGroupObject; + } + + void SetBlenderGroupObject( struct Object* obj) + { + m_pBlenderGroupObject = obj; + } bool IsDupliGroup() { @@ -428,7 +459,8 @@ public: return (m_pSGNode && m_pSGNode->GetSGParent() && m_pSGNode->GetSGParent()->IsVertexParent()); } - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo* client); /** @@ -535,18 +567,23 @@ public: /** * @section Mesh accessor functions. */ + + /** + * Update buckets to indicate that there is a new + * user of this object's meshes. + */ + void + AddMeshUser( + ); /** - * Run through the meshes associated with this - * object and bucketize them. See RAS_Mesh for - * more details on this function. Interesting to - * note that polygon bucketizing seems to happen on a per - * object basis. Which may explain why there is such - * a big performance gain when all static objects - * are joined into 1. + * Update buckets with data about the mesh after + * creating or duplicating the object, changing + * visibility, object color, .. . */ void - Bucketize( + UpdateBuckets( + bool recursive ); /** @@ -607,38 +644,38 @@ public: ResetDebugColor( ); - /** - * Set the visibility of the meshes associated with this - * object. + /** + * Was this object marked visible? (only for the explicit + * visibility system). */ - void - MarkVisible( - bool visible + bool + GetVisible( + void ); - /** - * Set the visibility according to the visibility flag. + /** + * Set visibility flag of this object */ - void - MarkVisible( void + SetVisible( + bool b, + bool recursive ); /** - * Was this object marked visible? (only for the ewxplicit - * visibility system). + * Was this object culled? */ bool - GetVisible( + GetCulled( void ); /** - * Set visibility flag of this object + * Set culled flag of this object */ void - SetVisible( - bool b + SetCulled( + bool c ); /** @@ -667,6 +704,14 @@ public: ) { return m_bIsNegativeScaling; } /** + * Is this a light? + */ + virtual bool + IsLight( + void + ) { return false; } + + /** * @section Logic bubbling methods. */ @@ -726,31 +771,34 @@ public: KX_PYMETHOD_NOARGS(KX_GameObject,GetPosition); KX_PYMETHOD_O(KX_GameObject,SetPosition); - KX_PYMETHOD(KX_GameObject,GetLinearVelocity); - KX_PYMETHOD(KX_GameObject,SetLinearVelocity); - KX_PYMETHOD(KX_GameObject,GetVelocity); + KX_PYMETHOD_O(KX_GameObject,SetWorldPosition); + KX_PYMETHOD_VARARGS(KX_GameObject,GetLinearVelocity); + KX_PYMETHOD_VARARGS(KX_GameObject,SetLinearVelocity); + KX_PYMETHOD_VARARGS(KX_GameObject,GetAngularVelocity); + KX_PYMETHOD_VARARGS(KX_GameObject,SetAngularVelocity); + KX_PYMETHOD_VARARGS(KX_GameObject,GetVelocity); KX_PYMETHOD_NOARGS(KX_GameObject,GetMass); KX_PYMETHOD_NOARGS(KX_GameObject,GetReactionForce); KX_PYMETHOD_NOARGS(KX_GameObject,GetOrientation); KX_PYMETHOD_O(KX_GameObject,SetOrientation); KX_PYMETHOD_NOARGS(KX_GameObject,GetVisible); - KX_PYMETHOD_O(KX_GameObject,SetVisible); + KX_PYMETHOD_VARARGS(KX_GameObject,SetVisible); KX_PYMETHOD_NOARGS(KX_GameObject,GetState); KX_PYMETHOD_O(KX_GameObject,SetState); - KX_PYMETHOD(KX_GameObject,AlignAxisToVect); + KX_PYMETHOD_VARARGS(KX_GameObject,AlignAxisToVect); KX_PYMETHOD_O(KX_GameObject,GetAxisVect); KX_PYMETHOD_NOARGS(KX_GameObject,SuspendDynamics); KX_PYMETHOD_NOARGS(KX_GameObject,RestoreDynamics); KX_PYMETHOD_NOARGS(KX_GameObject,EnableRigidBody); KX_PYMETHOD_NOARGS(KX_GameObject,DisableRigidBody); - KX_PYMETHOD(KX_GameObject,ApplyImpulse); + KX_PYMETHOD_VARARGS(KX_GameObject,ApplyImpulse); KX_PYMETHOD_O(KX_GameObject,SetCollisionMargin); KX_PYMETHOD_NOARGS(KX_GameObject,GetParent); KX_PYMETHOD_O(KX_GameObject,SetParent); KX_PYMETHOD_NOARGS(KX_GameObject,RemoveParent); KX_PYMETHOD_NOARGS(KX_GameObject,GetChildren); KX_PYMETHOD_NOARGS(KX_GameObject,GetChildrenRecursive); - KX_PYMETHOD(KX_GameObject,GetMesh); + KX_PYMETHOD_VARARGS(KX_GameObject,GetMesh); KX_PYMETHOD_NOARGS(KX_GameObject,GetPhysicsId); KX_PYMETHOD_NOARGS(KX_GameObject,GetPropertyNames); KX_PYMETHOD_NOARGS(KX_GameObject,EndObject); diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.cpp b/source/gameengine/Ketsji/KX_IPO_SGController.cpp index d3aa924665e..67d54cf0b0b 100644 --- a/source/gameengine/Ketsji/KX_IPO_SGController.cpp +++ b/source/gameengine/Ketsji/KX_IPO_SGController.cpp @@ -59,7 +59,9 @@ KX_IpoSGController::KX_IpoSGController() m_ipo_local(false), m_modified(true), m_ipo_start_initialized(false), - m_ipotime(1.0) + m_ipotime(1.0), + m_ipo_start_euler(0.0,0.0,0.0), + m_ipo_euler_initialized(false) { m_game_object = NULL; for (int i=0; i < KX_MAX_IPO_CHANNELS; i++) @@ -136,6 +138,11 @@ bool KX_IpoSGController::Update(double currentTime) m_ipo_start_orient = ob->GetLocalOrientation(); m_ipo_start_scale = ob->GetLocalScale(); m_ipo_start_initialized = true; + if (!m_ipo_euler_initialized) { + // do it only once to avoid angle discontinuities + m_ipo_start_orient.getEuler(m_ipo_start_euler[0], m_ipo_start_euler[1], m_ipo_start_euler[2]); + m_ipo_euler_initialized = true; + } } //modifies position? @@ -143,7 +150,7 @@ bool KX_IpoSGController::Update(double currentTime) { if (m_ipo_as_force == true) { - if (m_game_object && ob) + if (m_game_object && ob && m_game_object->GetPhysicsController()) { m_game_object->GetPhysicsController()->ApplyForce(m_ipo_local ? ob->GetWorldOrientation() * m_ipo_xform.GetPosition() : @@ -199,51 +206,87 @@ bool KX_IpoSGController::Update(double currentTime) ob->GetWorldOrientation() * m_ipo_xform.GetEulerAngles() : m_ipo_xform.GetEulerAngles(), false); } - } else { - double yaw=0, pitch=0, roll=0; //final Euler angles - double tempYaw=0, tempPitch=0, tempRoll=0; //temp holders - if (!m_ipo_add) - ob->GetLocalOrientation().getEuler(yaw, pitch, roll); + } else if (m_ipo_add) { + if (m_ipo_start_initialized) { + double yaw=0, pitch=0, roll=0; //delta Euler angles - //RotX and dRotX - if (m_ipo_channels_active[OB_ROT_X]) { - yaw = (m_ipo_channels_active[OB_DROT_X] ? (m_ipo_xform.GetEulerAngles()[0] + m_ipo_xform.GetDeltaEulerAngles()[0]) : m_ipo_xform.GetEulerAngles()[0] ); - } - else if (m_ipo_channels_active[OB_DROT_X] && m_ipo_start_initialized) { - if (!m_ipo_add) - m_ipo_start_orient.getEuler(tempYaw, tempPitch, tempRoll); - yaw = tempYaw + m_ipo_xform.GetDeltaEulerAngles()[0]; - } + //RotX and dRotX + if (m_ipo_channels_active[OB_ROT_X]) + yaw += m_ipo_xform.GetEulerAngles()[0]; + if (m_ipo_channels_active[OB_DROT_X]) + yaw += m_ipo_xform.GetDeltaEulerAngles()[0]; + + //RotY dRotY + if (m_ipo_channels_active[OB_ROT_Y]) + pitch += m_ipo_xform.GetEulerAngles()[1]; + if (m_ipo_channels_active[OB_DROT_Y]) + pitch += m_ipo_xform.GetDeltaEulerAngles()[1]; + + //RotZ and dRotZ + if (m_ipo_channels_active[OB_ROT_Z]) + roll += m_ipo_xform.GetEulerAngles()[2]; + if (m_ipo_channels_active[OB_DROT_Z]) + roll += m_ipo_xform.GetDeltaEulerAngles()[2]; - //RotY dRotY - if (m_ipo_channels_active[OB_ROT_Y]) { - pitch = (m_ipo_channels_active[OB_DROT_Y] ? (m_ipo_xform.GetEulerAngles()[1] + m_ipo_xform.GetDeltaEulerAngles()[1]) : m_ipo_xform.GetEulerAngles()[1] ); - } - else if (m_ipo_channels_active[OB_DROT_Y] && m_ipo_start_initialized) { - if (!m_ipo_add) - m_ipo_start_orient.getEuler(tempYaw, tempPitch, tempRoll); - pitch = tempPitch + m_ipo_xform.GetDeltaEulerAngles()[1]; - } - - //RotZ and dRotZ - if (m_ipo_channels_active[OB_ROT_Z]) { - roll = (m_ipo_channels_active[OB_DROT_Z] ? (m_ipo_xform.GetEulerAngles()[2] + m_ipo_xform.GetDeltaEulerAngles()[2]) : m_ipo_xform.GetEulerAngles()[2] ); - } - else if (m_ipo_channels_active[OB_DROT_Z] && m_ipo_start_initialized) { - if (!m_ipo_add) - m_ipo_start_orient.getEuler(tempYaw, tempPitch, tempRoll); - roll = tempRoll + m_ipo_xform.GetDeltaEulerAngles()[2]; - } - if (m_ipo_add) { MT_Matrix3x3 rotation(MT_Vector3(yaw, pitch, roll)); if (m_ipo_local) rotation = m_ipo_start_orient * rotation; else rotation = rotation * m_ipo_start_orient; ob->SetLocalOrientation(rotation); - } else { + } + } else if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z]) { + if (m_ipo_euler_initialized) { + // assume all channel absolute + // All 3 channels should be specified but if they are not, we will take + // the value at the start of the game to avoid angle sign reversal + double yaw=m_ipo_start_euler[0], pitch=m_ipo_start_euler[1], roll=m_ipo_start_euler[2]; + + //RotX and dRotX + if (m_ipo_channels_active[OB_ROT_X]) { + yaw = (m_ipo_channels_active[OB_DROT_X] ? (m_ipo_xform.GetEulerAngles()[0] + m_ipo_xform.GetDeltaEulerAngles()[0]) : m_ipo_xform.GetEulerAngles()[0] ); + } + else if (m_ipo_channels_active[OB_DROT_X]) { + yaw += m_ipo_xform.GetDeltaEulerAngles()[0]; + } + + //RotY dRotY + if (m_ipo_channels_active[OB_ROT_Y]) { + pitch = (m_ipo_channels_active[OB_DROT_Y] ? (m_ipo_xform.GetEulerAngles()[1] + m_ipo_xform.GetDeltaEulerAngles()[1]) : m_ipo_xform.GetEulerAngles()[1] ); + } + else if (m_ipo_channels_active[OB_DROT_Y]) { + pitch += m_ipo_xform.GetDeltaEulerAngles()[1]; + } + + //RotZ and dRotZ + if (m_ipo_channels_active[OB_ROT_Z]) { + roll = (m_ipo_channels_active[OB_DROT_Z] ? (m_ipo_xform.GetEulerAngles()[2] + m_ipo_xform.GetDeltaEulerAngles()[2]) : m_ipo_xform.GetEulerAngles()[2] ); + } + else if (m_ipo_channels_active[OB_DROT_Z]) { + roll += m_ipo_xform.GetDeltaEulerAngles()[2]; + } ob->SetLocalOrientation(MT_Vector3(yaw, pitch, roll)); } + } else if (m_ipo_start_initialized) { + // only DROT, treat as Add + double yaw=0, pitch=0, roll=0; //delta Euler angles + + //dRotX + if (m_ipo_channels_active[OB_DROT_X]) + yaw = m_ipo_xform.GetDeltaEulerAngles()[0]; + + //dRotY + if (m_ipo_channels_active[OB_DROT_Y]) + pitch = m_ipo_xform.GetDeltaEulerAngles()[1]; + + //dRotZ + if (m_ipo_channels_active[OB_DROT_Z]) + roll = m_ipo_xform.GetDeltaEulerAngles()[2]; + + // dRot are always local + MT_Matrix3x3 rotation(MT_Vector3(yaw, pitch, roll)); + rotation = m_ipo_start_orient * rotation; + ob->SetLocalOrientation(rotation); } } //modifies scale? diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.h b/source/gameengine/Ketsji/KX_IPO_SGController.h index 0bd8980f11c..031b74294ce 100644 --- a/source/gameengine/Ketsji/KX_IPO_SGController.h +++ b/source/gameengine/Ketsji/KX_IPO_SGController.h @@ -72,6 +72,12 @@ class KX_IpoSGController : public SG_Controller /** if IPO initial position has been set for local normal IPO */ bool m_ipo_start_initialized; + /** Euler angles at the start of the game, needed for incomplete ROT Ipo curves */ + class MT_Vector3 m_ipo_start_euler; + + /** true is m_ipo_start_euler has been initialized */ + bool m_ipo_euler_initialized; + /** A reference to the original game object. */ class KX_GameObject* m_game_object; diff --git a/source/gameengine/Ketsji/KX_IPhysicsController.h b/source/gameengine/Ketsji/KX_IPhysicsController.h index ecfdb8c4275..4ea283e9f98 100644 --- a/source/gameengine/Ketsji/KX_IPhysicsController.h +++ b/source/gameengine/Ketsji/KX_IPhysicsController.h @@ -88,7 +88,11 @@ public: m_bDyna = isDynamic; } + bool IsDyna(void) { + return m_bDyna; + } + virtual MT_Scalar GetRadius()=0; virtual void SetSumoTransform(bool nondynaonly)=0; // todo: remove next line ! virtual void SetSimulatedTime(double time)=0; diff --git a/source/gameengine/Ketsji/KX_ISceneConverter.h b/source/gameengine/Ketsji/KX_ISceneConverter.h index f069048cd3d..3709fa8c784 100644 --- a/source/gameengine/Ketsji/KX_ISceneConverter.h +++ b/source/gameengine/Ketsji/KX_ISceneConverter.h @@ -32,6 +32,8 @@ #include "STR_String.h" #include "KX_Python.h" +struct Scene; + class KX_ISceneConverter { @@ -77,6 +79,8 @@ public: // use blender glsl materials virtual void SetGLSLMaterials(bool val) =0; virtual bool GetGLSLMaterials()=0; + + virtual struct Scene* GetBlenderSceneForName(const STR_String& name)=0; }; #endif //__KX_ISCENECONVERTER_H diff --git a/source/gameengine/Ketsji/KX_IpoActuator.cpp b/source/gameengine/Ketsji/KX_IpoActuator.cpp index a203ea6a6ff..f5e17118ffb 100644 --- a/source/gameengine/Ketsji/KX_IpoActuator.cpp +++ b/source/gameengine/Ketsji/KX_IpoActuator.cpp @@ -37,6 +37,7 @@ #include "KX_IpoActuator.h" #include "KX_GameObject.h" +#include "FloatValue.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -62,6 +63,7 @@ STR_String KX_IpoActuator::S_KX_ACT_IPO_FROM_PROP_STRING = "FromProp"; KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj, const STR_String& propname, + const STR_String& framePropname, float starttime, float endtime, bool recurse, @@ -78,6 +80,7 @@ KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj, m_localtime(starttime), m_direction(1), m_propname(propname), + m_framepropname(framePropname), m_ipo_as_force(ipo_as_force), m_ipo_add(ipo_add), m_ipo_local(ipo_local), @@ -130,7 +133,6 @@ void KX_IpoActuator::SetStartTime(float curtime) { float direction = m_startframe < m_endframe ? 1.0f : -1.0f; - curtime = curtime - KX_KetsjiEngine::GetSuspendedDelta(); if (m_direction > 0) m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate(); else @@ -139,7 +141,7 @@ void KX_IpoActuator::SetStartTime(float curtime) void KX_IpoActuator::SetLocalTime(float curtime) { - float delta_time = ((curtime - m_starttime) - KX_KetsjiEngine::GetSuspendedDelta())*KX_KetsjiEngine::GetAnimFrameRate(); + float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate(); // negative delta_time is caused by floating point inaccuracy // perhaps the inaccuracy could be reduced a bit @@ -165,6 +167,8 @@ bool KX_IpoActuator::Update(double curtime, bool frame) int numevents = 0; bool bIpoStart = false; + curtime -= KX_KetsjiEngine::GetSuspendedDelta(); + if (frame) { numevents = m_events.size(); @@ -180,7 +184,7 @@ bool KX_IpoActuator::Update(double curtime, bool frame) if (m_starttime < -2.0f*start_smaller_then_end*(m_endframe - m_startframe)) { // start for all Ipo, initial start for LOOP_STOP - m_starttime = curtime - KX_KetsjiEngine::GetSuspendedDelta(); + m_starttime = curtime; m_bIpoPlaying = true; bIpoStart = true; } @@ -355,7 +359,20 @@ bool KX_IpoActuator::Update(double curtime, bool frame) default: result = false; } - + + /* Set the property if its defined */ + if (m_framepropname[0] != '\0') { + CValue* propowner = GetParent(); + CValue* oldprop = propowner->GetProperty(m_framepropname); + CValue* newval = new CFloatValue(m_localtime); + if (oldprop) { + oldprop->SetValue(newval); + } else { + propowner->SetProperty(m_framepropname, newval); + } + newval->Release(); + } + if (!result) { if (m_type != KX_ACT_IPO_LOOPSTOP) @@ -423,34 +440,20 @@ PyParentObject KX_IpoActuator::Parents[] = { }; PyMethodDef KX_IpoActuator::Methods[] = { - {"set", (PyCFunction) KX_IpoActuator::sPySet, - METH_VARARGS, Set_doc}, - {"setProperty", (PyCFunction) KX_IpoActuator::sPySetProperty, - METH_VARARGS, SetProperty_doc}, - {"setStart", (PyCFunction) KX_IpoActuator::sPySetStart, - METH_VARARGS, SetStart_doc}, - {"getStart", (PyCFunction) KX_IpoActuator::sPyGetStart, - METH_NOARGS, GetStart_doc}, - {"setEnd", (PyCFunction) KX_IpoActuator::sPySetEnd, - METH_VARARGS, SetEnd_doc}, - {"getEnd", (PyCFunction) KX_IpoActuator::sPyGetEnd, - METH_NOARGS, GetEnd_doc}, - {"setIpoAsForce", (PyCFunction) KX_IpoActuator::sPySetIpoAsForce, - METH_VARARGS, SetIpoAsForce_doc}, - {"getIpoAsForce", (PyCFunction) KX_IpoActuator::sPyGetIpoAsForce, - METH_NOARGS, GetIpoAsForce_doc}, - {"setIpoAdd", (PyCFunction) KX_IpoActuator::sPySetIpoAdd, - METH_VARARGS, SetIpoAdd_doc}, - {"getIpoAdd", (PyCFunction) KX_IpoActuator::sPyGetIpoAdd, - METH_NOARGS, GetIpoAdd_doc}, - {"setType", (PyCFunction) KX_IpoActuator::sPySetType, - METH_VARARGS, SetType_doc}, - {"getType", (PyCFunction) KX_IpoActuator::sPyGetType, - METH_NOARGS, GetType_doc}, - {"setForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPySetForceIpoActsLocal, - METH_VARARGS, SetForceIpoActsLocal_doc}, - {"getForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPyGetForceIpoActsLocal, - METH_NOARGS, GetForceIpoActsLocal_doc}, + {"set", (PyCFunction) KX_IpoActuator::sPySet, METH_VARARGS, (PY_METHODCHAR)Set_doc}, + {"setProperty", (PyCFunction) KX_IpoActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, + {"setStart", (PyCFunction) KX_IpoActuator::sPySetStart, METH_VARARGS, (PY_METHODCHAR)SetStart_doc}, + {"getStart", (PyCFunction) KX_IpoActuator::sPyGetStart, METH_NOARGS, (PY_METHODCHAR)GetStart_doc}, + {"setEnd", (PyCFunction) KX_IpoActuator::sPySetEnd, METH_VARARGS, (PY_METHODCHAR)SetEnd_doc}, + {"getEnd", (PyCFunction) KX_IpoActuator::sPyGetEnd, METH_NOARGS, (PY_METHODCHAR)GetEnd_doc}, + {"setIpoAsForce", (PyCFunction) KX_IpoActuator::sPySetIpoAsForce, METH_VARARGS, (PY_METHODCHAR)SetIpoAsForce_doc}, + {"getIpoAsForce", (PyCFunction) KX_IpoActuator::sPyGetIpoAsForce, METH_NOARGS, (PY_METHODCHAR)GetIpoAsForce_doc}, + {"setIpoAdd", (PyCFunction) KX_IpoActuator::sPySetIpoAdd, METH_VARARGS, (PY_METHODCHAR)SetIpoAdd_doc}, + {"getIpoAdd", (PyCFunction) KX_IpoActuator::sPyGetIpoAdd, METH_NOARGS, (PY_METHODCHAR)GetIpoAdd_doc}, + {"setType", (PyCFunction) KX_IpoActuator::sPySetType, METH_VARARGS, (PY_METHODCHAR)SetType_doc}, + {"getType", (PyCFunction) KX_IpoActuator::sPyGetType, METH_NOARGS, (PY_METHODCHAR)GetType_doc}, + {"setForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPySetForceIpoActsLocal, METH_VARARGS, (PY_METHODCHAR)SetForceIpoActsLocal_doc}, + {"getForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPyGetForceIpoActsLocal, METH_NOARGS, (PY_METHODCHAR)GetForceIpoActsLocal_doc}, {NULL,NULL} //Sentinel }; @@ -461,7 +464,7 @@ PyObject* KX_IpoActuator::_getattr(const STR_String& attr) { /* set --------------------------------------------------------------------- */ -char KX_IpoActuator::Set_doc[] = +const char KX_IpoActuator::Set_doc[] = "set(type, startframe, endframe, mode?)\n" "\t - type: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n" "\t - startframe: first frame to use (int)\n" @@ -504,7 +507,7 @@ PyObject* KX_IpoActuator::PySet(PyObject* self, } /* set property ----------------------------------------------------------- */ -char KX_IpoActuator::SetProperty_doc[] = +const char KX_IpoActuator::SetProperty_doc[] = "setProperty(propname)\n" "\t - propname: name of the property (string)\n" "\tSet the property to be used in FromProp mode.\n"; @@ -524,7 +527,7 @@ PyObject* KX_IpoActuator::PySetProperty(PyObject* self, } /* 4. setStart: */ -char KX_IpoActuator::SetStart_doc[] = +const char KX_IpoActuator::SetStart_doc[] = "setStart(frame)\n" "\t - frame: first frame to use (int)\n" "\tSet the frame from which the ipo starts playing.\n"; @@ -541,7 +544,7 @@ PyObject* KX_IpoActuator::PySetStart(PyObject* self, Py_Return; } /* 5. getStart: */ -char KX_IpoActuator::GetStart_doc[] = +const char KX_IpoActuator::GetStart_doc[] = "getStart()\n" "\tReturns the frame from which the ipo starts playing.\n"; PyObject* KX_IpoActuator::PyGetStart(PyObject* self) { @@ -549,7 +552,7 @@ PyObject* KX_IpoActuator::PyGetStart(PyObject* self) { } /* 6. setEnd: */ -char KX_IpoActuator::SetEnd_doc[] = +const char KX_IpoActuator::SetEnd_doc[] = "setEnd(frame)\n" "\t - frame: last frame to use (int)\n" "\tSet the frame at which the ipo stops playing.\n"; @@ -566,7 +569,7 @@ PyObject* KX_IpoActuator::PySetEnd(PyObject* self, Py_Return; } /* 7. getEnd: */ -char KX_IpoActuator::GetEnd_doc[] = +const char KX_IpoActuator::GetEnd_doc[] = "getEnd()\n" "\tReturns the frame at which the ipo stops playing.\n"; PyObject* KX_IpoActuator::PyGetEnd(PyObject* self) { @@ -574,7 +577,7 @@ PyObject* KX_IpoActuator::PyGetEnd(PyObject* self) { } /* 6. setIpoAsForce: */ -char KX_IpoActuator::SetIpoAsForce_doc[] = +const char KX_IpoActuator::SetIpoAsForce_doc[] = "setIpoAsForce(force?)\n" "\t - force? : interpret this ipo as a force? (KX_TRUE, KX_FALSE)\n" "\tSet whether to interpret the ipo as a force rather than a displacement.\n"; @@ -594,7 +597,7 @@ PyObject* KX_IpoActuator::PySetIpoAsForce(PyObject* self, Py_Return; } /* 7. getIpoAsForce: */ -char KX_IpoActuator::GetIpoAsForce_doc[] = +const char KX_IpoActuator::GetIpoAsForce_doc[] = "getIpoAsForce()\n" "\tReturns whether to interpret the ipo as a force rather than a displacement.\n"; PyObject* KX_IpoActuator::PyGetIpoAsForce(PyObject* self) { @@ -602,7 +605,7 @@ PyObject* KX_IpoActuator::PyGetIpoAsForce(PyObject* self) { } /* 6. setIpoAsForce: */ -char KX_IpoActuator::SetIpoAdd_doc[] = +const char KX_IpoActuator::SetIpoAdd_doc[] = "setIpoAdd(add?)\n" "\t - add? : add flag (KX_TRUE, KX_FALSE)\n" "\tSet whether to interpret the ipo as additive rather than absolute.\n"; @@ -622,7 +625,7 @@ PyObject* KX_IpoActuator::PySetIpoAdd(PyObject* self, Py_Return; } /* 7. getIpoAsForce: */ -char KX_IpoActuator::GetIpoAdd_doc[] = +const char KX_IpoActuator::GetIpoAdd_doc[] = "getIpoAsAdd()\n" "\tReturns whether to interpret the ipo as additive rather than absolute.\n"; PyObject* KX_IpoActuator::PyGetIpoAdd(PyObject* self) { @@ -630,7 +633,7 @@ PyObject* KX_IpoActuator::PyGetIpoAdd(PyObject* self) { } /* 8. setType: */ -char KX_IpoActuator::SetType_doc[] = +const char KX_IpoActuator::SetType_doc[] = "setType(mode)\n" "\t - mode: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n" "\tSet the operation mode of the actuator.\n"; @@ -651,7 +654,7 @@ PyObject* KX_IpoActuator::PySetType(PyObject* self, Py_Return; } /* 9. getType: */ -char KX_IpoActuator::GetType_doc[] = +const char KX_IpoActuator::GetType_doc[] = "getType()\n" "\tReturns the operation mode of the actuator.\n"; PyObject* KX_IpoActuator::PyGetType(PyObject* self) { @@ -659,7 +662,7 @@ PyObject* KX_IpoActuator::PyGetType(PyObject* self) { } /* 10. setForceIpoActsLocal: */ -char KX_IpoActuator::SetForceIpoActsLocal_doc[] = +const char KX_IpoActuator::SetForceIpoActsLocal_doc[] = "setForceIpoActsLocal(local?)\n" "\t - local? : Apply the ipo-as-force in the object's local\n" "\t coordinates? (KX_TRUE, KX_FALSE)\n" @@ -679,7 +682,7 @@ PyObject* KX_IpoActuator::PySetForceIpoActsLocal(PyObject* self, Py_Return; } /* 11. getForceIpoActsLocal: */ -char KX_IpoActuator::GetForceIpoActsLocal_doc[] = +const char KX_IpoActuator::GetForceIpoActsLocal_doc[] = "getForceIpoActsLocal()\n" "\tReturn whether to apply the force in the object's local\n" "\tcoordinates rather than the world global coordinates.\n"; diff --git a/source/gameengine/Ketsji/KX_IpoActuator.h b/source/gameengine/Ketsji/KX_IpoActuator.h index d6f52f8d59d..8e5baed0530 100644 --- a/source/gameengine/Ketsji/KX_IpoActuator.h +++ b/source/gameengine/Ketsji/KX_IpoActuator.h @@ -72,6 +72,9 @@ protected: /** Name of the property (only used in from_prop mode). */ STR_String m_propname; + /** Name of the property where we write the current frame number */ + STR_String m_framepropname; + /** Interpret the ipo as a force? */ bool m_ipo_as_force; @@ -111,6 +114,7 @@ public: KX_IpoActuator(SCA_IObject* gameobj, const STR_String& propname, + const STR_String& framePropname, float starttime, float endtime, bool recurse, diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 1d6cc975ab5..b1ab8e3e7de 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -96,6 +96,7 @@ double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE; double KX_KetsjiEngine::m_anim_framerate = 25.0; double KX_KetsjiEngine::m_suspendedtime = 0.0; double KX_KetsjiEngine::m_suspendeddelta = 0.0; +double KX_KetsjiEngine::m_average_framerate = 0.0; /** @@ -134,6 +135,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_overrideCam(false), m_overrideCamUseOrtho(false), + m_overrideCamNear(0.0), + m_overrideCamFar(0.0), m_stereo(false), m_curreye(0), @@ -275,30 +278,73 @@ void KX_KetsjiEngine::StartEngine(bool clearIpo) } -bool KX_KetsjiEngine::BeginFrame() +void KX_KetsjiEngine::ClearFrame() { - bool result = false; + // clear unless we're drawing overlapping stereo + if(m_rasterizer->InterlacedStereo() && + m_rasterizer->GetEye() == RAS_IRasterizer::RAS_STEREO_RIGHTEYE) + return; - RAS_Rect vp; - KX_Scene* firstscene = *m_scenes.begin(); - const RAS_FrameSettings &framesettings = firstscene->GetFramingType(); + // clear the viewports with the background color of the first scene + bool doclear = false; + KX_SceneList::iterator sceneit; + RAS_Rect clearvp, area, viewport; - // set the area used for rendering - m_rasterizer->SetRenderArea(); + for (sceneit = m_scenes.begin(); sceneit != m_scenes.end(); sceneit++) + { + KX_Scene* scene = *sceneit; + //const RAS_FrameSettings &framesettings = scene->GetFramingType(); + list<class KX_Camera*>* cameras = scene->GetCameras(); + + list<KX_Camera*>::iterator it; + for(it = cameras->begin(); it != cameras->end(); it++) + { + GetSceneViewport(scene, (*it), area, viewport); + + if(!doclear) { + clearvp = viewport; + doclear = true; + } + else { + if(viewport.GetLeft() < clearvp.GetLeft()) + clearvp.SetLeft(viewport.GetLeft()); + if(viewport.GetBottom() < clearvp.GetBottom()) + clearvp.SetBottom(viewport.GetBottom()); + if(viewport.GetRight() > clearvp.GetRight()) + clearvp.SetRight(viewport.GetRight()); + if(viewport.GetTop() > clearvp.GetTop()) + clearvp.SetTop(viewport.GetTop()); + + } + } + } + + if(doclear) { + KX_Scene* firstscene = *m_scenes.begin(); + SetBackGround(firstscene->GetWorldInfo()); + + m_canvas->SetViewPort(clearvp.GetLeft(), clearvp.GetBottom(), + clearvp.GetRight(), clearvp.GetTop()); + m_rasterizer->ClearColorBuffer(); + } +} - RAS_FramingManager::ComputeViewport(framesettings, m_canvas->GetDisplayArea(), vp); +bool KX_KetsjiEngine::BeginFrame() +{ + // set the area used for rendering (stereo can assign only a subset) + m_rasterizer->SetRenderArea(); if (m_canvas->BeginDraw()) { - result = true; + ClearFrame(); - m_canvas->SetViewPort(vp.GetLeft(), vp.GetBottom(), vp.GetRight(), vp.GetTop()); - SetBackGround( firstscene->GetWorldInfo() ); - m_rasterizer->BeginFrame( m_drawingmode , m_kxsystem->GetTimeInSeconds()); - m_rendertools->BeginFrame( m_rasterizer); + m_rasterizer->BeginFrame(m_drawingmode , m_kxsystem->GetTimeInSeconds()); + m_rendertools->BeginFrame(m_rasterizer); + + return true; } - return result; + return false; } @@ -310,6 +356,12 @@ void KX_KetsjiEngine::EndFrame() { RenderDebugProperties(); } + + m_average_framerate = m_logger->GetAverage(); + if (m_average_framerate < 1e-6) + m_average_framerate = 1e-6; + m_average_framerate = 1.0/m_average_framerate; + // Go to next profiling measurement, time spend after this call is shown in the next frame. m_logger->NextMeasurement(m_kxsystem->GetTimeInSeconds()); @@ -321,8 +373,6 @@ void KX_KetsjiEngine::EndFrame() m_canvas->EndDraw(); - - } //#include "PIL_time.h" @@ -601,7 +651,7 @@ void KX_KetsjiEngine::Render() ); } // clear the -whole- viewport - m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER); + m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER); } m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE); @@ -630,9 +680,6 @@ void KX_KetsjiEngine::Render() m_rendertools->SetAuxilaryClientInfo(scene); - //Initialize scene viewport. - SetupRenderFrame(scene, cam); - // do the rendering RenderFrame(scene, cam); } @@ -650,9 +697,6 @@ void KX_KetsjiEngine::Render() m_rendertools->SetAuxilaryClientInfo(scene); - //Initialize scene viewport. - SetupRenderFrame(scene, (*it)); - // do the rendering RenderFrame(scene, (*it)); } @@ -685,10 +729,6 @@ void KX_KetsjiEngine::Render() //pass the scene, for picking and raycasting (shadows) m_rendertools->SetAuxilaryClientInfo(scene); - //Initialize scene viewport. - //SetupRenderFrame(scene); - SetupRenderFrame(scene, cam); - // do the rendering //RenderFrame(scene); RenderFrame(scene, cam); @@ -848,8 +888,13 @@ void KX_KetsjiEngine::SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat) m_overrideCamViewMat = mat; } - -void KX_KetsjiEngine::SetupRenderFrame(KX_Scene *scene, KX_Camera* cam) +void KX_KetsjiEngine::SetCameraOverrideClipping(float near, float far) +{ + m_overrideCamNear = near; + m_overrideCamFar = far; +} + +void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport) { // In this function we make sure the rasterizer settings are upto // date. We compute the viewport so that logic @@ -857,17 +902,26 @@ void KX_KetsjiEngine::SetupRenderFrame(KX_Scene *scene, KX_Camera* cam) // Note we postpone computation of the projection matrix // so that we are using the latest camera position. + if (cam->GetViewport()) { + RAS_Rect userviewport; - RAS_Rect viewport; + userviewport.SetLeft(cam->GetViewportLeft()); + userviewport.SetBottom(cam->GetViewportBottom()); + userviewport.SetRight(cam->GetViewportRight()); + userviewport.SetTop(cam->GetViewportTop()); - if (!cam) - return; + // Don't do bars on user specified viewport + RAS_FrameSettings settings = scene->GetFramingType(); + if(settings.FrameType() == RAS_FrameSettings::e_frame_bars) + settings.SetFrameType(RAS_FrameSettings::e_frame_extend); - if (cam->GetViewport()) { - viewport.SetLeft(cam->GetViewportLeft()); - viewport.SetBottom(cam->GetViewportBottom()); - viewport.SetRight(cam->GetViewportRight()); - viewport.SetTop(cam->GetViewportTop()); + RAS_FramingManager::ComputeViewport( + scene->GetFramingType(), + userviewport, + viewport + ); + + area = userviewport; } else if ( m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho ) { RAS_FramingManager::ComputeViewport( @@ -875,33 +929,32 @@ void KX_KetsjiEngine::SetupRenderFrame(KX_Scene *scene, KX_Camera* cam) m_canvas->GetDisplayArea(), viewport ); + + area = m_canvas->GetDisplayArea(); } else { viewport.SetLeft(0); viewport.SetBottom(0); viewport.SetRight(int(m_canvas->GetWidth())); viewport.SetTop(int(m_canvas->GetHeight())); - } - // store the computed viewport in the scene - - scene->SetSceneViewport(viewport); - - // set the viewport for this frame and scene - m_canvas->SetViewPort( - viewport.GetLeft(), - viewport.GetBottom(), - viewport.GetRight(), - viewport.GetTop() - ); + area = m_canvas->GetDisplayArea(); + } } void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) { - CListValue *lightlist = scene->GetLightList(); + CListValue *objectlist = scene->GetObjectList(); int i, drawmode; - for(i=0; i<lightlist->GetCount(); i++) { - KX_LightObject *light = (KX_LightObject*)lightlist->GetValue(i); + m_rendertools->SetAuxilaryClientInfo(scene); + + for(i=0; i<objectlist->GetCount(); i++) { + KX_GameObject *gameobj = (KX_GameObject*)objectlist->GetValue(i); + + if(!gameobj->IsLight()) + continue; + + KX_LightObject *light = (KX_LightObject*)gameobj; light->Update(); @@ -939,18 +992,32 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) // update graphics void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) { + bool override_camera; + RAS_Rect viewport, area; float left, right, bottom, top, nearfrust, farfrust, focallength; const float ortho = 100.0; // KX_Camera* cam = scene->GetActiveCamera(); if (!cam) return; + + GetSceneViewport(scene, cam, area, viewport); + + // store the computed viewport in the scene + scene->SetSceneViewport(viewport); + + // set the viewport for this frame and scene + m_canvas->SetViewPort(viewport.GetLeft(), viewport.GetBottom(), + viewport.GetRight(), viewport.GetTop()); // see KX_BlenderMaterial::Activate //m_rasterizer->SetAmbient(); m_rasterizer->DisplayFog(); - if (m_overrideCam && (scene->GetName() == m_overrideSceneName) && m_overrideCamUseOrtho) { + override_camera = m_overrideCam && (scene->GetName() == m_overrideSceneName); + override_camera = override_camera && (cam->GetName() == "__default__cam__"); + + if (override_camera && m_overrideCamUseOrtho) { MT_CmMatrix4x4 projmat = m_overrideCamProjMat; m_rasterizer->SetProjectionMatrix(projmat); } else if (cam->hasValidProjectionMatrix() && !cam->GetViewport() ) @@ -960,12 +1027,17 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) { RAS_FrameFrustum frustum; float lens = cam->GetLens(); + bool orthographic = !cam->GetCameraData()->m_perspective; nearfrust = cam->GetCameraNear(); farfrust = cam->GetCameraFar(); focallength = cam->GetFocalLength(); - if (!cam->GetCameraData()->m_perspective) - { + if(override_camera) { + nearfrust = m_overrideCamNear; + farfrust = m_overrideCamFar; + } + + if (orthographic) { lens *= ortho; nearfrust = (nearfrust + 1.0)*ortho; farfrust *= ortho; @@ -973,8 +1045,8 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) RAS_FramingManager::ComputeFrustum( scene->GetFramingType(), - m_canvas->GetDisplayArea(), - scene->GetSceneViewport(), + area, + viewport, lens, nearfrust, farfrust, @@ -990,7 +1062,7 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix( left, right, bottom, top, nearfrust, farfrust, focallength); - + cam->SetProjectionMatrix(projmat); // Otherwise the projection matrix for each eye will be the same... @@ -1171,19 +1243,49 @@ void KX_KetsjiEngine::RenderDebugProperties() CValue* propobj = (*it)->m_obj; STR_String objname = propobj->GetName(); STR_String propname = (*it)->m_name; - CValue* propval = propobj->GetProperty(propname); - if (propval) + if (propname == "__state__") { - STR_String text = propval->GetText(); - debugtxt = objname + "." + propname + " = " + text; + // reserve name for object state + KX_GameObject* gameobj = static_cast<KX_GameObject*>(propobj); + unsigned int state = gameobj->GetState(); + debugtxt = objname + "." + propname + " = "; + bool first = true; + for (int statenum=1;state;state >>= 1, statenum++) + { + if (state & 1) + { + if (!first) + { + debugtxt += ","; + } + debugtxt += STR_String(statenum); + first = false; + } + } m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, - debugtxt.Ptr(), - xcoord, - ycoord, - m_canvas->GetWidth(), - m_canvas->GetHeight()); + debugtxt.Ptr(), + xcoord, + ycoord, + m_canvas->GetWidth(), + m_canvas->GetHeight()); ycoord += 14; } + else + { + CValue* propval = propobj->GetProperty(propname); + if (propval) + { + STR_String text = propval->GetText(); + debugtxt = objname + "." + propname + " = " + text; + m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED, + debugtxt.Ptr(), + xcoord, + ycoord, + m_canvas->GetWidth(), + m_canvas->GetHeight()); + ycoord += 14; + } + } } } } @@ -1281,12 +1383,13 @@ void KX_KetsjiEngine::RemoveScheduledScenes() KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename) { - + Scene *scene = m_sceneconverter->GetBlenderSceneForName(scenename); KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice, m_mousedevice, m_networkdevice, m_audiodevice, - scenename); + scenename, + scene); m_sceneconverter->ConvertScene(scenename, tmpscene, @@ -1442,6 +1545,11 @@ void KX_KetsjiEngine::SetAnimFrameRate(double framerate) m_anim_framerate = framerate; } +double KX_KetsjiEngine::GetAverageFrameRate() +{ + return m_average_framerate; +} + void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties) { m_show_framerate = frameRate; diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index 77b69ec2d9e..1aa067a9962 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -124,6 +124,8 @@ private: bool m_overrideCamUseOrtho; MT_CmMatrix4x4 m_overrideCamProjMat; MT_CmMatrix4x4 m_overrideCamViewMat; + float m_overrideCamNear; + float m_overrideCamFar; bool m_stereo; int m_curreye; @@ -149,6 +151,8 @@ private: /** Labels for profiling display. */ static const char m_profileLabels[tc_numCategories][15]; + /** Last estimated framerate */ + static double m_average_framerate; /** Show the framerate on the game display? */ bool m_show_framerate; /** Show profiling info on the game display? */ @@ -175,7 +179,6 @@ private: /** Blue component of framing bar color. */ float m_overrideFrameColorB; - void SetupRenderFrame(KX_Scene *scene, KX_Camera* cam); void RenderFrame(KX_Scene* scene, KX_Camera* cam); void PostRenderFrame(); void RenderDebugProperties(); @@ -226,6 +229,8 @@ public: void SuspendScene(const STR_String& scenename); void ResumeScene(const STR_String& scenename); + void GetSceneViewport(KX_Scene* scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport); + void SetDrawType(int drawingtype); void SetCameraZoom(float camzoom); @@ -234,6 +239,7 @@ public: void SetCameraOverrideUseOrtho(bool useOrtho); void SetCameraOverrideProjectionMatrix(const MT_CmMatrix4x4& mat); void SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat); + void SetCameraOverrideClipping(float near, float far); /** * Sets display of all frames. @@ -272,6 +278,11 @@ public: static void SetAnimFrameRate(double framerate); /** + * Gets the last estimated average framerate + */ + static double GetAverageFrameRate(); + + /** * Activates or deactivates timing information display. * @param frameRate Display for frame rate on or off. * @param profile Display for individual components on or off. @@ -348,6 +359,7 @@ protected: KX_Scene* CreateScene(const STR_String& scenename); bool BeginFrame(); + void ClearFrame(); void EndFrame(); }; diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp index 4e3d6180d22..e0f171e78e0 100644 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ b/source/gameengine/Ketsji/KX_Light.cpp @@ -42,14 +42,13 @@ #include "KX_PyMath.h" -#ifdef BLENDER_GLSL +#include "DNA_object_types.h" #include "GPU_material.h" -#endif KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks, class RAS_IRenderTools* rendertools, const RAS_LightObject& lightobj, - struct GPULamp *gpulamp, + bool glsl, PyTypeObject* T ) : @@ -59,12 +58,20 @@ KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks, m_lightobj = lightobj; m_lightobj.m_worldmatrix = GetOpenGLMatrixPtr(); m_rendertools->AddLight(&m_lightobj); - m_gpulamp = gpulamp; + m_glsl = glsl; + m_blenderscene = ((KX_Scene*)sgReplicationInfo)->GetBlenderScene(); }; KX_LightObject::~KX_LightObject() { + GPULamp *lamp; + + if((lamp = GetGPULamp())) { + float obmat[4][4] = {{0}}; + GPU_lamp_update(lamp, 0, obmat); + } + m_rendertools->RemoveLight(&m_lightobj); } @@ -73,7 +80,7 @@ CValue* KX_LightObject::GetReplica() { KX_LightObject* replica = new KX_LightObject(*this); - + // this will copy properties and so on... CValue::AddDataToReplica(replica); @@ -81,13 +88,23 @@ CValue* KX_LightObject::GetReplica() replica->m_lightobj.m_worldmatrix = replica->GetOpenGLMatrixPtr(); m_rendertools->AddLight(&replica->m_lightobj); + return replica; } +GPULamp *KX_LightObject::GetGPULamp() +{ + if(m_glsl) + return GPU_lamp_from_blender(m_blenderscene, GetBlenderObject(), GetBlenderGroupObject()); + else + return false; +} + void KX_LightObject::Update() { -#ifdef BLENDER_GLSL - if(m_gpulamp) { + GPULamp *lamp; + + if((lamp = GetGPULamp())) { float obmat[4][4]; double *dobmat = GetOpenGLMatrixPtr()->getPointer(); @@ -95,38 +112,39 @@ void KX_LightObject::Update() for(int j=0; j<4; j++, dobmat++) obmat[i][j] = (float)*dobmat; - GPU_lamp_update(m_gpulamp, obmat); + GPU_lamp_update(lamp, m_lightobj.m_layer, obmat); } -#endif } bool KX_LightObject::HasShadowBuffer() { -#ifdef BLENDER_GLSL - return (m_gpulamp && GPU_lamp_has_shadow_buffer(m_gpulamp)); -#else - return false; -#endif + GPULamp *lamp; + + if((lamp = GetGPULamp())) + return GPU_lamp_has_shadow_buffer(lamp); + else + return false; } int KX_LightObject::GetShadowLayer() { -#ifdef BLENDER_GLSL - if(m_gpulamp) - return GPU_lamp_shadow_layer(m_gpulamp); + GPULamp *lamp; + + if((lamp = GetGPULamp())) + return GPU_lamp_shadow_layer(lamp); else -#endif return 0; } void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_Transform& camtrans) { -#ifdef BLENDER_GLSL + GPULamp *lamp; float viewmat[4][4], winmat[4][4]; int winsize; /* bind framebuffer */ - GPU_lamp_shadow_buffer_bind(m_gpulamp, viewmat, &winsize, winmat); + lamp = GetGPULamp(); + GPU_lamp_shadow_buffer_bind(lamp, viewmat, &winsize, winmat); /* setup camera transformation */ MT_Matrix4x4 modelviewmat((float*)viewmat); @@ -146,14 +164,12 @@ void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_T ras->SetProjectionMatrix(projectionmat); ras->SetViewMatrix(modelviewmat, cam->NodeGetWorldPosition(), cam->GetCameraLocation(), cam->GetCameraOrientation()); -#endif } void KX_LightObject::UnbindShadowBuffer(RAS_IRasterizer *ras) { -#ifdef BLENDER_GLSL - GPU_lamp_shadow_buffer_unbind(m_gpulamp); -#endif + GPULamp *lamp = GetGPULamp(); + GPU_lamp_shadow_buffer_unbind(lamp); } PyObject* KX_LightObject::_getattr(const STR_String& attr) diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h index 62eb26c61a8..e5dbf0b7f4a 100644 --- a/source/gameengine/Ketsji/KX_Light.h +++ b/source/gameengine/Ketsji/KX_Light.h @@ -33,6 +33,7 @@ #include "KX_GameObject.h" struct GPULamp; +struct Scene; class KX_Camera; class RAS_IRasterizer; class RAS_IRenderTools; @@ -44,16 +45,18 @@ class KX_LightObject : public KX_GameObject protected: RAS_LightObject m_lightobj; class RAS_IRenderTools* m_rendertools; //needed for registering and replication of lightobj - struct GPULamp *m_gpulamp; - static char doc[]; + bool m_glsl; + Scene* m_blenderscene; + static char doc[]; public: - KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,class RAS_IRenderTools* rendertools,const struct RAS_LightObject& lightobj, struct GPULamp *gpulamp, PyTypeObject *T = &Type); + KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,class RAS_IRenderTools* rendertools,const struct RAS_LightObject& lightobj, bool glsl, PyTypeObject *T = &Type); virtual ~KX_LightObject(); virtual CValue* GetReplica(); RAS_LightObject* GetLightData() { return &m_lightobj;} /* GLSL shadow */ + struct GPULamp *GetGPULamp(); bool HasShadowBuffer(); int GetShadowLayer(); void BindShadowBuffer(class RAS_IRasterizer *ras, class KX_Camera *cam, class MT_Transform& camtrans); @@ -62,6 +65,8 @@ public: virtual PyObject* _getattr(const STR_String& attr); /* lens, near, far, projection_matrix */ virtual int _setattr(const STR_String& attr, PyObject *pyvalue); + + virtual bool IsLight(void) { return true; } }; #endif //__KX_LIGHT diff --git a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp index 2ce5d469380..85d514bd22f 100644 --- a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp +++ b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp @@ -3,6 +3,8 @@ #include "KX_ScalarInterpolator.h" #include "KX_GameObject.h" +#include "BLO_sys_types.h" // for intptr_t support + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -76,10 +78,10 @@ SG_Controller* KX_MaterialIpoController::GetReplica(class SG_Node* destnode) iporeplica->AddInterpolator(copyipo); MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget(); - long orgbase = (long)this; - long orgloc = (long)scaal; - long offset = orgloc-orgbase; - long newaddrbase = (long)iporeplica + offset; + intptr_t orgbase = (intptr_t)this; + intptr_t orgloc = (intptr_t)scaal; + intptr_t offset = orgloc-orgbase; + intptr_t newaddrbase = (intptr_t)iporeplica + offset; MT_Scalar* blaptr = (MT_Scalar*) newaddrbase; copyipo->SetNewTarget((MT_Scalar*)blaptr); } diff --git a/source/gameengine/Ketsji/KX_MeshProxy.cpp b/source/gameengine/Ketsji/KX_MeshProxy.cpp index a0ac9cfd4ff..5cc102248f2 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.cpp +++ b/source/gameengine/Ketsji/KX_MeshProxy.cpp @@ -35,6 +35,7 @@ #include "RAS_MeshObject.h" #include "KX_VertexProxy.h" +#include "KX_PolyProxy.h" #include "KX_PolygonMaterial.h" #include "KX_BlenderMaterial.h" @@ -42,6 +43,8 @@ #include "KX_PyMath.h" #include "KX_ConvertPhysicsObject.h" +#include "PyObjectPlus.h" + PyTypeObject KX_MeshProxy::Type = { PyObject_HEAD_INIT(&PyType_Type) 0, @@ -71,10 +74,12 @@ PyParentObject KX_MeshProxy::Parents[] = { PyMethodDef KX_MeshProxy::Methods[] = { {"getNumMaterials", (PyCFunction)KX_MeshProxy::sPyGetNumMaterials,METH_VARARGS}, +{"getNumPolygons", (PyCFunction)KX_MeshProxy::sPyGetNumPolygons,METH_NOARGS}, {"getMaterialName", (PyCFunction)KX_MeshProxy::sPyGetMaterialName,METH_VARARGS}, {"getTextureName", (PyCFunction)KX_MeshProxy::sPyGetTextureName,METH_VARARGS}, {"getVertexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetVertexArrayLength,METH_VARARGS}, {"getVertex", (PyCFunction)KX_MeshProxy::sPyGetVertex,METH_VARARGS}, +{"getPolygon", (PyCFunction)KX_MeshProxy::sPyGetPolygon,METH_VARARGS}, KX_PYMETHODTABLE(KX_MeshProxy, reinstancePhysicsMesh), //{"getIndexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetIndexArrayLength,METH_VARARGS}, @@ -93,10 +98,11 @@ KX_MeshProxy::_getattr(const STR_String& attr) if (attr == "materials") { PyObject *materials = PyList_New(0); - RAS_MaterialBucket::Set::iterator mit = m_meshobj->GetFirstMaterial(); + list<RAS_MeshMaterial>::iterator mit = m_meshobj->GetFirstMaterial(); for(; mit != m_meshobj->GetLastMaterial(); ++mit) { - RAS_IPolyMaterial *polymat = (*mit)->GetPolyMaterial(); + RAS_IPolyMaterial *polymat = mit->m_bucket->GetPolyMaterial(); + if(polymat->GetFlag() & RAS_BLENDERMAT) { KX_BlenderMaterial *mat = static_cast<KX_BlenderMaterial*>(polymat); @@ -146,6 +152,12 @@ PyObject* KX_MeshProxy::PyGetNumMaterials(PyObject* self, return PyInt_FromLong(num); } +PyObject* KX_MeshProxy::PyGetNumPolygons(PyObject* self) +{ + int num = m_meshobj->NumPolygons(); + return PyInt_FromLong(num); +} + PyObject* KX_MeshProxy::PyGetMaterialName(PyObject* self, PyObject* args, PyObject* kwds) @@ -195,11 +207,11 @@ PyObject* KX_MeshProxy::PyGetVertexArrayLength(PyObject* self, if (PyArg_ParseTuple(args,"i",&matid)) { - RAS_IPolyMaterial* mat = m_meshobj->GetMaterialBucket(matid)->GetPolyMaterial(); + RAS_MeshMaterial *mmat = m_meshobj->GetMeshMaterial(matid); + RAS_IPolyMaterial* mat = mmat->m_bucket->GetPolyMaterial(); + if (mat) - { - length = m_meshobj->GetVertexArrayLength(mat); - } + length = m_meshobj->NumVertices(mat); } else { return NULL; @@ -234,6 +246,28 @@ PyObject* KX_MeshProxy::PyGetVertex(PyObject* self, } +PyObject* KX_MeshProxy::PyGetPolygon(PyObject* self, + PyObject* args, + PyObject* kwds) +{ + int polyindex= 1; + PyObject* polyob = NULL; + + if (!PyArg_ParseTuple(args,"i",&polyindex)) + return NULL; + + RAS_Polygon* polygon = m_meshobj->GetPolygon(polyindex); + if (polygon) + { + polyob = new KX_PolyProxy(m_meshobj, polygon); + } + else + { + PyErr_SetString(PyExc_AttributeError, "Invalid polygon index"); + } + return polyob; +} + KX_PYMETHODDEF_DOC(KX_MeshProxy, reinstancePhysicsMesh, "Reinstance the physics mesh.") { diff --git a/source/gameengine/Ketsji/KX_MeshProxy.h b/source/gameengine/Ketsji/KX_MeshProxy.h index 7c6202c15a4..3335c349673 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.h +++ b/source/gameengine/Ketsji/KX_MeshProxy.h @@ -57,10 +57,12 @@ public: KX_PYMETHOD(KX_MeshProxy,GetNumMaterials); KX_PYMETHOD(KX_MeshProxy,GetMaterialName); KX_PYMETHOD(KX_MeshProxy,GetTextureName); + KX_PYMETHOD_NOARGS(KX_MeshProxy,GetNumPolygons); // both take materialid (int) KX_PYMETHOD(KX_MeshProxy,GetVertexArrayLength); KX_PYMETHOD(KX_MeshProxy,GetVertex); + KX_PYMETHOD(KX_MeshProxy,GetPolygon); KX_PYMETHOD_DOC(KX_MeshProxy, reinstancePhysicsMesh); }; diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp index db0bef8b7e1..28279b9a6b8 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -62,12 +62,14 @@ KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager* eventmgr, int focusmode, RAS_ICanvas* canvas, KX_Scene* kxscene, + KX_KetsjiEngine *kxengine, SCA_IObject* gameobj, PyTypeObject* T) : SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj, T), m_focusmode(focusmode), m_gp_canvas(canvas), - m_kxscene(kxscene) + m_kxscene(kxscene), + m_kxengine(kxengine) { Init(); } @@ -122,16 +124,10 @@ bool KX_MouseFocusSensor::Evaluate(CValue* event) return result; } -bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, KX_RayCast* result, void * const data) { KX_GameObject* hitKXObj = client_info->m_gameobject; - if (client_info->m_type > KX_ClientObjectInfo::ACTOR) - { - // false hit - return false; - } - /* Is this me? In the ray test, there are a lot of extra checks * for aliasing artefacts from self-hits. That doesn't happen * here, so a simple test suffices. Or does the camera also get @@ -142,8 +138,8 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, MT_Point3& hi if ((m_focusmode == 2) || hitKXObj == thisObj) { m_hitObject = hitKXObj; - m_hitPosition = hit_point; - m_hitNormal = hit_normal; + m_hitPosition = result->m_hitPoint; + m_hitNormal = result->m_hitNormal; return true; } @@ -158,8 +154,6 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) m_hitObject = 0; m_hitPosition = MT_Vector3(0,0,0); m_hitNormal = MT_Vector3(1,0,0); - MT_Point3 resultpoint; - MT_Vector3 resultnormal; /* All screen handling in the gameengine is done by GL, * specifically the model/view and projection parts. The viewport @@ -201,11 +195,14 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) * calculations don't bomb. Maybe we should explicitly guard for * division by 0.0...*/ - /** - * Get the scenes current viewport. - */ + KX_Camera* cam = m_kxscene->GetActiveCamera(); - const RAS_Rect & viewport = m_kxscene->GetSceneViewport(); + /* get the scenes current viewport. we recompute it because there + * may be multiple cameras and m_kxscene->GetSceneViewport() only + * has the one that was last drawn */ + + RAS_Rect area, viewport; + m_kxengine->GetSceneViewport(m_kxscene, cam, area, viewport); float height = float(viewport.m_y2 - viewport.m_y1 + 1); float width = float(viewport.m_x2 - viewport.m_x1 + 1); @@ -213,9 +210,9 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) float x_lb = float(viewport.m_x1); float y_lb = float(viewport.m_y1); - KX_Camera* cam = m_kxscene->GetActiveCamera(); /* There's some strangeness I don't fully get here... These values * _should_ be wrong! */ + /* old: */ float nearclip = 0.0; @@ -280,7 +277,8 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void) bool result = false; - result = KX_RayCast::RayTest(physics_controller, physics_environment, frompoint3, topoint3, resultpoint, resultnormal, KX_RayCast::Callback<KX_MouseFocusSensor>(this)); + KX_RayCast::Callback<KX_MouseFocusSensor> callback(this,physics_controller); + KX_RayCast::RayTest(physics_environment, frompoint3, topoint3, callback); result = (m_hitObject!=0); @@ -322,14 +320,12 @@ PyParentObject KX_MouseFocusSensor::Parents[] = { }; PyMethodDef KX_MouseFocusSensor::Methods[] = { - {"getRayTarget", (PyCFunction) KX_MouseFocusSensor::sPyGetRayTarget, - METH_VARARGS, GetRayTarget_doc}, - {"getRaySource", (PyCFunction) KX_MouseFocusSensor::sPyGetRaySource, - METH_VARARGS, GetRaySource_doc}, - {"getHitObject",(PyCFunction) KX_MouseFocusSensor::sPyGetHitObject,METH_VARARGS, GetHitObject_doc}, - {"getHitPosition",(PyCFunction) KX_MouseFocusSensor::sPyGetHitPosition,METH_VARARGS, GetHitPosition_doc}, - {"getHitNormal",(PyCFunction) KX_MouseFocusSensor::sPyGetHitNormal,METH_VARARGS, GetHitNormal_doc}, - {"getRayDirection",(PyCFunction) KX_MouseFocusSensor::sPyGetRayDirection,METH_VARARGS, GetRayDirection_doc}, + {"getRayTarget", (PyCFunction) KX_MouseFocusSensor::sPyGetRayTarget, METH_VARARGS, (PY_METHODCHAR)GetRayTarget_doc}, + {"getRaySource", (PyCFunction) KX_MouseFocusSensor::sPyGetRaySource, METH_VARARGS, (PY_METHODCHAR)GetRaySource_doc}, + {"getHitObject",(PyCFunction) KX_MouseFocusSensor::sPyGetHitObject,METH_VARARGS, (PY_METHODCHAR)GetHitObject_doc}, + {"getHitPosition",(PyCFunction) KX_MouseFocusSensor::sPyGetHitPosition,METH_VARARGS, (PY_METHODCHAR)GetHitPosition_doc}, + {"getHitNormal",(PyCFunction) KX_MouseFocusSensor::sPyGetHitNormal,METH_VARARGS, (PY_METHODCHAR)GetHitNormal_doc}, + {"getRayDirection",(PyCFunction) KX_MouseFocusSensor::sPyGetRayDirection,METH_VARARGS, (PY_METHODCHAR)GetRayDirection_doc}, {NULL,NULL} //Sentinel @@ -340,7 +336,7 @@ PyObject* KX_MouseFocusSensor::_getattr(const STR_String& attr) { } -char KX_MouseFocusSensor::GetHitObject_doc[] = +const char KX_MouseFocusSensor::GetHitObject_doc[] = "getHitObject()\n" "\tReturns the name of the object that was hit by this ray.\n"; PyObject* KX_MouseFocusSensor::PyGetHitObject(PyObject* self, @@ -355,7 +351,7 @@ PyObject* KX_MouseFocusSensor::PyGetHitObject(PyObject* self, } -char KX_MouseFocusSensor::GetHitPosition_doc[] = +const char KX_MouseFocusSensor::GetHitPosition_doc[] = "getHitPosition()\n" "\tReturns the position (in worldcoordinates) where the object was hit by this ray.\n"; PyObject* KX_MouseFocusSensor::PyGetHitPosition(PyObject* self, @@ -375,7 +371,7 @@ PyObject* KX_MouseFocusSensor::PyGetHitPosition(PyObject* self, } -char KX_MouseFocusSensor::GetRayDirection_doc[] = +const char KX_MouseFocusSensor::GetRayDirection_doc[] = "getRayDirection()\n" "\tReturns the direction from the ray (in worldcoordinates) .\n"; PyObject* KX_MouseFocusSensor::PyGetRayDirection(PyObject* self, @@ -396,7 +392,7 @@ PyObject* KX_MouseFocusSensor::PyGetRayDirection(PyObject* self, } -char KX_MouseFocusSensor::GetHitNormal_doc[] = +const char KX_MouseFocusSensor::GetHitNormal_doc[] = "getHitNormal()\n" "\tReturns the normal (in worldcoordinates) of the object at the location where the object was hit by this ray.\n"; PyObject* KX_MouseFocusSensor::PyGetHitNormal(PyObject* self, @@ -417,7 +413,7 @@ PyObject* KX_MouseFocusSensor::PyGetHitNormal(PyObject* self, /* getRayTarget */ -char KX_MouseFocusSensor::GetRayTarget_doc[] = +const char KX_MouseFocusSensor::GetRayTarget_doc[] = "getRayTarget()\n" "\tReturns the target of the ray that seeks the focus object,\n" "\tin worldcoordinates."; @@ -434,7 +430,7 @@ PyObject* KX_MouseFocusSensor::PyGetRayTarget(PyObject* self, } /* getRayTarget */ -char KX_MouseFocusSensor::GetRaySource_doc[] = +const char KX_MouseFocusSensor::GetRaySource_doc[] = "getRaySource()\n" "\tReturns the source of the ray that seeks the focus object,\n" "\tin worldcoordinates."; diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h index b011ebe1288..6731444699b 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h @@ -33,6 +33,8 @@ #include "SCA_MouseSensor.h" +class KX_RayCast; + /** * The mouse focus sensor extends the basic SCA_MouseSensor. It has * been placed in KX because it needs access to the rasterizer and @@ -54,6 +56,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor int focusmode, RAS_ICanvas* canvas, KX_Scene* kxscene, + KX_KetsjiEngine* kxengine, SCA_IObject* gameobj, PyTypeObject* T=&Type ); @@ -76,7 +79,9 @@ class KX_MouseFocusSensor : public SCA_MouseSensor return result; }; - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo* client) { return true; } + /* --------------------------------------------------------------------- */ @@ -139,12 +144,6 @@ class KX_MouseFocusSensor : public SCA_MouseSensor /** - * Ref to the engine, for retrieving a reference to the current - * scene. */ - class KX_KetsjiEngine* m_engine; - - - /** * The active canvas. The size of this canvas determines a part of * the start position of the picking ray. */ RAS_ICanvas* m_gp_canvas; @@ -154,6 +153,9 @@ class KX_MouseFocusSensor : public SCA_MouseSensor * determines a part of the start location of the picking ray. */ KX_Scene* m_kxscene; + /** + * The KX engine is needed for computing the viewport */ + KX_KetsjiEngine* m_kxengine; }; #endif //__KX_MOUSESENSOR diff --git a/source/gameengine/Ketsji/KX_NearSensor.cpp b/source/gameengine/Ketsji/KX_NearSensor.cpp index 140dd37f5c6..397aedb3fa3 100644 --- a/source/gameengine/Ketsji/KX_NearSensor.cpp +++ b/source/gameengine/Ketsji/KX_NearSensor.cpp @@ -190,13 +190,13 @@ bool KX_NearSensor::Evaluate(CValue* event) { if (m_physCtrl) { - m_physCtrl->SetMargin(m_ResetMargin); + m_physCtrl->SetRadius(m_ResetMargin); } } else { if (m_physCtrl) { - m_physCtrl->SetMargin(m_Margin); + m_physCtrl->SetRadius(m_Margin); } } @@ -309,14 +309,10 @@ PyParentObject KX_NearSensor::Parents[] = { PyMethodDef KX_NearSensor::Methods[] = { - {"setProperty", - (PyCFunction) KX_NearSensor::sPySetProperty, METH_VARARGS, SetProperty_doc}, - {"getProperty", - (PyCFunction) KX_NearSensor::sPyGetProperty, METH_VARARGS, GetProperty_doc}, - {"getHitObject", - (PyCFunction) KX_NearSensor::sPyGetHitObject, METH_VARARGS, GetHitObject_doc}, - {"getHitObjectList", - (PyCFunction) KX_NearSensor::sPyGetHitObjectList, METH_VARARGS, GetHitObjectList_doc}, + {"setProperty", (PyCFunction) KX_NearSensor::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, + {"getProperty", (PyCFunction) KX_NearSensor::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, + {"getHitObject",(PyCFunction) KX_NearSensor::sPyGetHitObject, METH_VARARGS, (PY_METHODCHAR)GetHitObject_doc}, + {"getHitObjectList", (PyCFunction) KX_NearSensor::sPyGetHitObjectList, METH_VARARGS, (PY_METHODCHAR)GetHitObjectList_doc}, {NULL,NULL} //Sentinel }; diff --git a/source/gameengine/Ketsji/KX_OdePhysicsController.cpp b/source/gameengine/Ketsji/KX_OdePhysicsController.cpp index 05feb11a2bc..6a701a5f25b 100644 --- a/source/gameengine/Ketsji/KX_OdePhysicsController.cpp +++ b/source/gameengine/Ketsji/KX_OdePhysicsController.cpp @@ -169,6 +169,11 @@ MT_Scalar KX_OdePhysicsController::GetMass() return ODEPhysicsController::getMass(); } +MT_Scalar KX_OdePhysicsController::GetRadius() +{ + return MT_Scalar(0.f); +} + MT_Vector3 KX_OdePhysicsController::getReactionForce() { return MT_Vector3(0,0,0); diff --git a/source/gameengine/Ketsji/KX_OdePhysicsController.h b/source/gameengine/Ketsji/KX_OdePhysicsController.h index 18f9edc6835..53050f6ce3e 100644 --- a/source/gameengine/Ketsji/KX_OdePhysicsController.h +++ b/source/gameengine/Ketsji/KX_OdePhysicsController.h @@ -76,7 +76,7 @@ public: virtual void SuspendDynamics(bool); virtual void RestoreDynamics(); - + virtual MT_Scalar GetRadius(); virtual SG_Controller* GetReplica(class SG_Node* destnode); diff --git a/source/gameengine/Ketsji/KX_ParentActuator.cpp b/source/gameengine/Ketsji/KX_ParentActuator.cpp index 344e0fccc35..eb56e8de679 100644 --- a/source/gameengine/Ketsji/KX_ParentActuator.cpp +++ b/source/gameengine/Ketsji/KX_ParentActuator.cpp @@ -36,6 +36,8 @@ #include "KX_GameObject.h" #include "KX_PythonInit.h" +#include "PyObjectPlus.h" + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -164,8 +166,8 @@ PyParentObject KX_ParentActuator::Parents[] = { }; PyMethodDef KX_ParentActuator::Methods[] = { - {"setObject", (PyCFunction) KX_ParentActuator::sPySetObject, METH_O, SetObject_doc}, - {"getObject", (PyCFunction) KX_ParentActuator::sPyGetObject, METH_VARARGS, GetObject_doc}, + {"setObject", (PyCFunction) KX_ParentActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc}, + {"getObject", (PyCFunction) KX_ParentActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc}, {NULL,NULL} //Sentinel }; @@ -174,7 +176,7 @@ PyObject* KX_ParentActuator::_getattr(const STR_String& attr) { } /* 1. setObject */ -char KX_ParentActuator::SetObject_doc[] = +const char KX_ParentActuator::SetObject_doc[] = "setObject(object)\n" "\t- object: KX_GameObject, string or None\n" "\tSet the object to set as parent.\n"; @@ -197,7 +199,7 @@ PyObject* KX_ParentActuator::PySetObject(PyObject* self, PyObject* value) { /* 2. getObject */ /* get obj ---------------------------------------------------------- */ -char KX_ParentActuator::GetObject_doc[] = +const char KX_ParentActuator::GetObject_doc[] = "getObject(name_only = 1)\n" "name_only - optional arg, when true will return the KX_GameObject rather then its name\n" "\tReturns the object that is set to.\n"; diff --git a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp index 9291199d859..da4f05ced7c 100644 --- a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp +++ b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp @@ -27,6 +27,8 @@ * ***** END GPL LICENSE BLOCK ***** */ #include <Python.h> +#include "PyObjectPlus.h" + #include "KX_PhysicsObjectWrapper.h" #include "PHY_IPhysicsEnvironment.h" #include "PHY_IPhysicsController.h" diff --git a/source/gameengine/Ketsji/KX_PolyProxy.cpp b/source/gameengine/Ketsji/KX_PolyProxy.cpp new file mode 100644 index 00000000000..c6f6bc2db01 --- /dev/null +++ b/source/gameengine/Ketsji/KX_PolyProxy.cpp @@ -0,0 +1,265 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "KX_PolyProxy.h" +#include "KX_MeshProxy.h" +#include "RAS_MeshObject.h" +#include "KX_BlenderMaterial.h" +#include "KX_PolygonMaterial.h" + +#include "KX_PyMath.h" + +PyTypeObject KX_PolyProxy::Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "KX_PolyProxy", + sizeof(KX_PolyProxy), + 0, + PyDestructor, + 0, + __getattr, + __setattr, + 0, //&MyPyCompare, + __repr, + 0, //&cvalue_as_number, + 0, + 0, + 0, + 0 +}; + +PyParentObject KX_PolyProxy::Parents[] = { + &KX_PolyProxy::Type, + &SCA_IObject::Type, + &CValue::Type, + NULL +}; + +PyMethodDef KX_PolyProxy::Methods[] = { + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterialIndex), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getNumVertex), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,isVisible), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,isCollider), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterialName), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getTextureName), + KX_PYMETHODTABLE(KX_PolyProxy,getVertexIndex), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMesh), + KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterial), + {NULL,NULL} //Sentinel +}; + +PyObject* +KX_PolyProxy::_getattr(const STR_String& attr) +{ + if (attr == "matname") + { + return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName()); + } + if (attr == "texture") + { + return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName()); + } + if (attr == "material") + { + RAS_IPolyMaterial *polymat = m_polygon->GetMaterial()->GetPolyMaterial(); + if(polymat->GetFlag() & RAS_BLENDERMAT) + { + KX_BlenderMaterial* mat = static_cast<KX_BlenderMaterial*>(polymat); + Py_INCREF(mat); + return mat; + } + else + { + KX_PolygonMaterial* mat = static_cast<KX_PolygonMaterial*>(polymat); + Py_INCREF(mat); + return mat; + } + } + if (attr == "matid") + { + // we'll have to scan through the material bucket of the mes and compare with + // the one of the polygon + RAS_MaterialBucket* polyBucket = m_polygon->GetMaterial(); + unsigned int matid; + for (matid=0; matid<m_mesh->NumMaterials(); matid++) + { + RAS_MeshMaterial* meshMat = m_mesh->GetMeshMaterial(matid); + if (meshMat->m_bucket == polyBucket) + // found it + break; + } + return PyInt_FromLong(matid); + } + if (attr == "v1") + { + return PyInt_FromLong(m_polygon->GetVertexOffset(0)); + } + if (attr == "v2") + { + return PyInt_FromLong(m_polygon->GetVertexOffset(1)); + } + if (attr == "v3") + { + return PyInt_FromLong(m_polygon->GetVertexOffset(2)); + } + if (attr == "v4") + { + return PyInt_FromLong(((m_polygon->VertexCount()>3)?m_polygon->GetVertexOffset(3):0)); + } + if (attr == "visible") + { + return PyInt_FromLong(m_polygon->IsVisible()); + } + if (attr == "collide") + { + return PyInt_FromLong(m_polygon->IsCollider()); + } + _getattr_up(SCA_IObject); +} + +KX_PolyProxy::KX_PolyProxy(const RAS_MeshObject*mesh, RAS_Polygon* polygon) +: m_mesh((RAS_MeshObject*)mesh), + m_polygon(polygon) +{ +} + +KX_PolyProxy::~KX_PolyProxy() +{ +} + + +// stuff for cvalue related things +CValue* KX_PolyProxy::Calc(VALUE_OPERATOR, CValue *) { return NULL;} +CValue* KX_PolyProxy::CalcFinal(VALUE_DATA_TYPE, VALUE_OPERATOR, CValue *) { return NULL;} +STR_String sPolyName="polygone"; +const STR_String & KX_PolyProxy::GetText() {return sPolyName;}; +float KX_PolyProxy::GetNumber() { return -1;} +STR_String KX_PolyProxy::GetName() { return sPolyName;} +void KX_PolyProxy::SetName(STR_String) { }; +CValue* KX_PolyProxy::GetReplica() { return NULL;} +void KX_PolyProxy::ReplicaSetName(STR_String) {}; + + +// stuff for python integration + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterialIndex, +"getMaterialIndex() : return the material index of the polygon in the mesh\n") +{ + RAS_MaterialBucket* polyBucket = m_polygon->GetMaterial(); + unsigned int matid; + for (matid=0; matid<m_mesh->NumMaterials(); matid++) + { + RAS_MeshMaterial* meshMat = m_mesh->GetMeshMaterial(matid); + if (meshMat->m_bucket == polyBucket) + // found it + break; + } + return PyInt_FromLong(matid); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getNumVertex, +"getNumVertex() : returns the number of vertex of the polygon, 3 or 4\n") +{ + return PyInt_FromLong(m_polygon->VertexCount()); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, isVisible, +"isVisible() : returns whether the polygon is visible or not\n") +{ + return PyInt_FromLong(m_polygon->IsVisible()); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, isCollider, +"isCollider() : returns whether the polygon is receives collision or not\n") +{ + return PyInt_FromLong(m_polygon->IsCollider()); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterialName, +"getMaterialName() : returns the polygon material name, \"NoMaterial\" if no material\n") +{ + return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName()); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getTextureName, +"getTexturelName() : returns the polygon texture name, \"NULL\" if no texture\n") +{ + return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName()); +} + +KX_PYMETHODDEF_DOC(KX_PolyProxy, getVertexIndex, +"getVertexIndex(vertex) : returns the mesh vertex index of a polygon vertex\n" +"vertex: index of the vertex in the polygon: 0->3\n" +"return value can be used to retrieve the vertex details through mesh proxy\n" +"Note: getVertexIndex(3) on a triangle polygon returns 0\n") +{ + int index; + if (!PyArg_ParseTuple(args,"i",&index)) + { + return NULL; + } + if (index < 0 || index > 3) + { + PyErr_SetString(PyExc_AttributeError, "Valid range for index is 0-3"); + return NULL; + } + if (index < m_polygon->VertexCount()) + { + return PyInt_FromLong(m_polygon->GetVertexOffset(index)); + } + return PyInt_FromLong(0); +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMesh, +"getMesh() : returns a mesh proxy\n") +{ + KX_MeshProxy* meshproxy = new KX_MeshProxy((RAS_MeshObject*)m_mesh); + return meshproxy; +} + +KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterial, +"getMaterial() : returns a material\n") +{ + RAS_IPolyMaterial *polymat = m_polygon->GetMaterial()->GetPolyMaterial(); + if(polymat->GetFlag() & RAS_BLENDERMAT) + { + KX_BlenderMaterial* mat = static_cast<KX_BlenderMaterial*>(polymat); + Py_INCREF(mat); + return mat; + } + else + { + KX_PolygonMaterial* mat = static_cast<KX_PolygonMaterial*>(polymat); + Py_INCREF(mat); + return mat; + } +} diff --git a/source/gameengine/Ketsji/KX_PolyProxy.h b/source/gameengine/Ketsji/KX_PolyProxy.h new file mode 100644 index 00000000000..506e2c2a656 --- /dev/null +++ b/source/gameengine/Ketsji/KX_PolyProxy.h @@ -0,0 +1,71 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __KX_POLYROXY +#define __KX_POLYPROXY + +#include "SCA_IObject.h" + +class KX_PolyProxy : public SCA_IObject +{ + Py_Header; +protected: + class RAS_Polygon* m_polygon; + class RAS_MeshObject* m_mesh; +public: + KX_PolyProxy(const class RAS_MeshObject*mesh, class RAS_Polygon* polygon); + virtual ~KX_PolyProxy(); + + // stuff for cvalue related things + CValue* Calc(VALUE_OPERATOR op, CValue *val) ; + CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); + const STR_String & GetText(); + float GetNumber(); + STR_String GetName(); + void SetName(STR_String name); // Set the name of the value + void ReplicaSetName(STR_String name); + CValue* GetReplica(); + + +// stuff for python integration + virtual PyObject* _getattr(const STR_String& attr); + + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterialIndex) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getNumVertex) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,isVisible) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,isCollider) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterialName) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getTextureName) + KX_PYMETHOD_DOC(KX_PolyProxy,getVertexIndex) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMesh) + KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterial) + +}; + +#endif //__KX_POLYPROXY + diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp index 144f74a1a4c..c9180bf3a80 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp @@ -35,10 +35,6 @@ #include "BKE_global.h" #include "BKE_image.h" -extern "C" { -#include "BDR_drawmesh.h" -} - #include "DNA_material_types.h" #include "DNA_texture_types.h" #include "DNA_image_types.h" @@ -46,6 +42,8 @@ extern "C" { #include "IMB_imbuf_types.h" +#include "GPU_draw.h" + #include "MEM_guardedalloc.h" #include "RAS_LightObject.h" @@ -63,8 +61,6 @@ KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname, bool alpha, bool zsort, int lightlayer, - bool bIsTriangle, - void* clientobject, struct MTFace* tface, unsigned int* mcol, PyTypeObject *T) @@ -78,9 +74,7 @@ KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname, transp, alpha, zsort, - lightlayer, - bIsTriangle, - clientobject), + lightlayer), m_tface(tface), m_mcol(mcol), m_material(material), @@ -140,38 +134,29 @@ void KX_PolygonMaterial::DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& c if (GetCachingInfo() != cachingInfo) { if (!cachingInfo) - { - set_tpage(NULL); - } + GPU_set_tpage(NULL); + cachingInfo = GetCachingInfo(); if ((m_drawingmode & 4)&& (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)) { - update_realtime_texture((struct MTFace*) m_tface, rasty->GetTime()); - set_tpage(m_tface); - rasty->EnableTextures(true); + Image *ima = (Image*)m_tface->tpage; + GPU_update_image_time(ima, rasty->GetTime()); + GPU_set_tpage(m_tface); } else - { - set_tpage(NULL); - rasty->EnableTextures(false); - } + GPU_set_tpage(NULL); if(m_drawingmode & RAS_IRasterizer::KX_TWOSIDE) - { rasty->SetCullFace(false); - } else - { rasty->SetCullFace(true); - } - if (m_drawingmode & RAS_IRasterizer::KX_LINES) { + if ((m_drawingmode & RAS_IRasterizer::KX_LINES) || + (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) rasty->SetLines(true); - } - else { + else rasty->SetLines(false); - } } rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity); @@ -253,7 +238,8 @@ PyObject* KX_PolygonMaterial::_getattr(const STR_String& attr) if (attr == "lightlayer") return PyInt_FromLong(m_lightlayer); if (attr == "triangle") - return PyInt_FromLong(m_bIsTriangle); + // deprecated, triangle/quads shouldn't have been a material property + return 0; if (attr == "diffuse") return PyObjectFrom(m_diffuse); @@ -333,7 +319,7 @@ int KX_PolygonMaterial::_setattr(const STR_String &attr, PyObject *pyvalue) // This probably won't work... if (attr == "triangle") { - m_bIsTriangle = value; + // deprecated, triangle/quads shouldn't have been a material property return 0; } } @@ -386,7 +372,9 @@ KX_PYMETHODDEF_DOC(KX_PolygonMaterial, updateTexture, "updateTexture(tface, rast { MTFace *tface = (MTFace*) PyCObject_AsVoidPtr(pytface); RAS_IRasterizer *rasty = (RAS_IRasterizer*) PyCObject_AsVoidPtr(pyrasty); - update_realtime_texture(tface, rasty->GetTime()); + Image *ima = (Image*)tface->tpage; + GPU_update_image_time(ima, rasty->GetTime()); + Py_Return; } @@ -399,7 +387,7 @@ KX_PYMETHODDEF_DOC(KX_PolygonMaterial, setTexture, "setTexture(tface)") if (PyArg_ParseTuple(args, "O!", &PyCObject_Type, &pytface)) { MTFace *tface = (MTFace*) PyCObject_AsVoidPtr(pytface); - set_tpage(tface); + GPU_set_tpage(tface); Py_Return; } diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.h b/source/gameengine/Ketsji/KX_PolygonMaterial.h index 11c8baa8b1f..fe116f757db 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.h +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.h @@ -68,8 +68,6 @@ public: bool alpha, bool zsort, int lightlayer, - bool bIsTriangle, - void* clientobject, struct MTFace* tface, unsigned int* mcol, PyTypeObject *T = &Type); diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp index 26243c7dba1..dea6225edc2 100644 --- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp +++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp @@ -34,6 +34,8 @@ #include "PHY_IPhysicsController.h" #include "PHY_IVehicle.h" +#include "PyObjectPlus.h" + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -508,54 +510,54 @@ static PyObject* gPyRemoveConstraint(PyObject* self, static struct PyMethodDef physicsconstraints_methods[] = { {"setGravity",(PyCFunction) gPySetGravity, - METH_VARARGS, gPySetGravity__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetGravity__doc__}, {"setDebugMode",(PyCFunction) gPySetDebugMode, - METH_VARARGS, gPySetDebugMode__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetDebugMode__doc__}, /// settings that influence quality of the rigidbody dynamics {"setNumIterations",(PyCFunction) gPySetNumIterations, - METH_VARARGS, gPySetNumIterations__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetNumIterations__doc__}, {"setNumTimeSubSteps",(PyCFunction) gPySetNumTimeSubSteps, - METH_VARARGS, gPySetNumTimeSubSteps__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetNumTimeSubSteps__doc__}, {"setDeactivationTime",(PyCFunction) gPySetDeactivationTime, - METH_VARARGS, gPySetDeactivationTime__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetDeactivationTime__doc__}, {"setDeactivationLinearTreshold",(PyCFunction) gPySetDeactivationLinearTreshold, - METH_VARARGS, gPySetDeactivationLinearTreshold__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetDeactivationLinearTreshold__doc__}, {"setDeactivationAngularTreshold",(PyCFunction) gPySetDeactivationAngularTreshold, - METH_VARARGS, gPySetDeactivationAngularTreshold__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetDeactivationAngularTreshold__doc__}, {"setContactBreakingTreshold",(PyCFunction) gPySetContactBreakingTreshold, - METH_VARARGS, gPySetContactBreakingTreshold__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetContactBreakingTreshold__doc__}, {"setCcdMode",(PyCFunction) gPySetCcdMode, - METH_VARARGS, gPySetCcdMode__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetCcdMode__doc__}, {"setSorConstant",(PyCFunction) gPySetSorConstant, - METH_VARARGS, gPySetSorConstant__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetSorConstant__doc__}, {"setSolverTau",(PyCFunction) gPySetSolverTau, - METH_VARARGS, gPySetSolverTau__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetSolverTau__doc__}, {"setSolverDamping",(PyCFunction) gPySetSolverDamping, - METH_VARARGS, gPySetSolverDamping__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetSolverDamping__doc__}, {"setLinearAirDamping",(PyCFunction) gPySetLinearAirDamping, - METH_VARARGS, gPySetLinearAirDamping__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetLinearAirDamping__doc__}, {"setUseEpa",(PyCFunction) gPySetUseEpa, - METH_VARARGS, gPySetUseEpa__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetUseEpa__doc__}, {"setSolverType",(PyCFunction) gPySetSolverType, - METH_VARARGS, gPySetSolverType__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPySetSolverType__doc__}, {"createConstraint",(PyCFunction) gPyCreateConstraint, - METH_VARARGS, gPyCreateConstraint__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPyCreateConstraint__doc__}, {"getVehicleConstraint",(PyCFunction) gPyGetVehicleConstraint, - METH_VARARGS, gPyGetVehicleConstraint__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPyGetVehicleConstraint__doc__}, {"removeConstraint",(PyCFunction) gPyRemoveConstraint, - METH_VARARGS, gPyRemoveConstraint__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPyRemoveConstraint__doc__}, {"getAppliedImpulse",(PyCFunction) gPyGetAppliedImpulse, - METH_VARARGS, gPyGetAppliedImpulse__doc__}, + METH_VARARGS, (PY_METHODCHAR)gPyGetAppliedImpulse__doc__}, //sentinel diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 868439546c3..fc836234e2b 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -30,7 +30,13 @@ #include "GL/glew.h" +// directory header for py function getBlendFileList #include <stdlib.h> +#ifndef WIN32 + #include <dirent.h> +#else + #include "BLI_winstuff.h" +#endif #ifdef WIN32 #pragma warning (disable : 4786) @@ -51,21 +57,25 @@ #include "BL_ActionActuator.h" #include "RAS_IRasterizer.h" #include "RAS_ICanvas.h" +#include "RAS_BucketManager.h" #include "MT_Vector3.h" #include "MT_Point3.h" #include "ListValue.h" #include "KX_Scene.h" #include "SND_DeviceManager.h" -#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h" #include "BL_Shader.h" #include "KX_PyMath.h" +#include "PyObjectPlus.h" + extern "C" { #include "Mathutils.h" // Blender.Mathutils module copied here so the blenderlayer can use. } +#include "marshal.h" /* python header for loading/saving dicts */ + #include "PHY_IPhysicsEnvironment.h" // FIXME: Enable for access to blender python modules. This is disabled because // python has dependencies on a lot of other modules and is a pain to link. @@ -77,6 +87,7 @@ extern "C" { #include "BKE_utildefines.h" #include "BKE_global.h" #include "BLI_blenlib.h" +#include "GPU_material.h" static void setSandbox(TPythonSecurityLevel level); @@ -84,6 +95,7 @@ static void setSandbox(TPythonSecurityLevel level); // 'local' copy of canvas ptr, for window height/width python scripts static RAS_ICanvas* gp_Canvas = NULL; static KX_Scene* gp_KetsjiScene = NULL; +static KX_KetsjiEngine* gp_KetsjiEngine = NULL; static RAS_IRasterizer* gp_Rasterizer = NULL; void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color) @@ -112,20 +124,16 @@ static PyObject* gPyGetRandomFloat(PyObject*) return PyFloat_FromDouble(MT_random()); } -static PyObject* gPySetGravity(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetGravity(PyObject*, PyObject* args) { MT_Vector3 vec = MT_Vector3(0., 0., 0.); - if (PyVecArgTo(args, vec)) - { - if (gp_KetsjiScene) - gp_KetsjiScene->SetGravity(vec); - - Py_Return; - } + if (!PyVecArgTo(args, vec)) + return NULL; + + if (gp_KetsjiScene) + gp_KetsjiScene->SetGravity(vec); - return NULL; + Py_RETURN_NONE; } static char gPyExpandPath_doc[] = @@ -138,20 +146,17 @@ file to make a full path name (doesn't change during the game, even if you load\ other .blend).\n\ The function also converts the directory separator to the local file system format."; -static PyObject* gPyExpandPath(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyExpandPath(PyObject*, PyObject* args) { char expanded[FILE_MAXDIR + FILE_MAXFILE]; char* filename; - if (PyArg_ParseTuple(args,"s",&filename)) - { - BLI_strncpy(expanded, filename, FILE_MAXDIR + FILE_MAXFILE); - BLI_convertstringcode(expanded, G.sce); - return PyString_FromString(expanded); - } - return NULL; + if (!PyArg_ParseTuple(args,"s",&filename)) + return NULL; + + BLI_strncpy(expanded, filename, FILE_MAXDIR + FILE_MAXFILE); + BLI_convertstringcode(expanded, G.sce); + return PyString_FromString(expanded); } @@ -179,62 +184,62 @@ static PyObject* gPyGetSpectrum(PyObject*) PyList_SetItem(resultlist, index, PyFloat_FromDouble(spectrum[index])); } } + else { + for (int index = 0; index < 512; index++) + { + PyList_SetItem(resultlist, index, PyFloat_FromDouble(0.0)); + } + } return resultlist; } -static PyObject* gPyStartDSP(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyStartDSP(PyObject*, PyObject* args) { SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance(); - if (audiodevice) - { - if (!usedsp) - { - audiodevice->StartUsingDSP(); - usedsp = true; - Py_Return; - } + if (!audiodevice) { + PyErr_SetString(PyExc_RuntimeError, "no audio device available"); + return NULL; } - return NULL; + + if (!usedsp) { + audiodevice->StartUsingDSP(); + usedsp = true; + } + + Py_RETURN_NONE; } -static PyObject* gPyStopDSP(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyStopDSP(PyObject*, PyObject* args) { SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance(); - if (audiodevice) - { - if (usedsp) - { - audiodevice->StopUsingDSP(); - usedsp = false; - Py_Return; - } + if (!audiodevice) { + PyErr_SetString(PyExc_RuntimeError, "no audio device available"); + return NULL; } - return NULL; + + if (usedsp) { + audiodevice->StopUsingDSP(); + usedsp = true; + } + + Py_RETURN_NONE; } -static PyObject* gPySetLogicTicRate(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetLogicTicRate(PyObject*, PyObject* args) { float ticrate; - if (PyArg_ParseTuple(args, "f", &ticrate)) - { - KX_KetsjiEngine::SetTicRate(ticrate); - Py_Return; - } + if (!PyArg_ParseTuple(args, "f", &ticrate)) + return NULL; - return NULL; + KX_KetsjiEngine::SetTicRate(ticrate); + Py_RETURN_NONE; } static PyObject* gPyGetLogicTicRate(PyObject*) @@ -242,33 +247,24 @@ static PyObject* gPyGetLogicTicRate(PyObject*) return PyFloat_FromDouble(KX_KetsjiEngine::GetTicRate()); } -static PyObject* gPySetPhysicsTicRate(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetPhysicsTicRate(PyObject*, PyObject* args) { float ticrate; - if (PyArg_ParseTuple(args, "f", &ticrate)) - { - - PHY_GetActiveEnvironment()->setFixedTimeStep(true,ticrate); - Py_Return; - } + if (!PyArg_ParseTuple(args, "f", &ticrate)) + return NULL; - return NULL; + PHY_GetActiveEnvironment()->setFixedTimeStep(true,ticrate); + Py_RETURN_NONE; } -static PyObject* gPySetPhysicsDebug(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetPhysicsDebug(PyObject*, PyObject* args) { int debugMode; - if (PyArg_ParseTuple(args, "i", &debugMode)) - { - PHY_GetActiveEnvironment()->setDebugMode(debugMode); - Py_Return; - } + if (!PyArg_ParseTuple(args, "i", &debugMode)) + return NULL; - return NULL; + PHY_GetActiveEnvironment()->setDebugMode(debugMode); + Py_RETURN_NONE; } @@ -278,6 +274,51 @@ static PyObject* gPyGetPhysicsTicRate(PyObject*) return PyFloat_FromDouble(PHY_GetActiveEnvironment()->getFixedTimeStep()); } +static PyObject* gPyGetAverageFrameRate(PyObject*) +{ + return PyFloat_FromDouble(KX_KetsjiEngine::GetAverageFrameRate()); +} + +static PyObject* gPyGetBlendFileList(PyObject*, PyObject* args) +{ + char cpath[sizeof(G.sce)]; + char *searchpath = NULL; + PyObject* list, *value; + + DIR *dp; + struct dirent *dirp; + + if (!PyArg_ParseTuple(args, "|s", &searchpath)) + return NULL; + + list = PyList_New(0); + + if (searchpath) { + BLI_strncpy(cpath, searchpath, FILE_MAXDIR + FILE_MAXFILE); + BLI_convertstringcode(cpath, G.sce); + } else { + /* Get the dir only */ + BLI_split_dirfile_basic(G.sce, cpath, NULL); + } + + if((dp = opendir(cpath)) == NULL) { + /* todo, show the errno, this shouldnt happen anyway if the blendfile is readable */ + fprintf(stderr, "Could not read directoty (%s) failed, code %d (%s)\n", cpath, errno, strerror(errno)); + return list; + } + + while ((dirp = readdir(dp)) != NULL) { + if (BLI_testextensie(dirp->d_name, ".blend")) { + value = PyString_FromString(dirp->d_name); + PyList_Append(list, value); + Py_DECREF(value); + } + } + + closedir(dp); + return list; +} + static STR_String gPyGetCurrentScene_doc = "getCurrentScene()\n" "Gets a reference to the current scene.\n"; @@ -360,50 +401,40 @@ static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *) static struct PyMethodDef game_methods[] = { - {"expandPath", (PyCFunction)gPyExpandPath, METH_VARARGS, gPyExpandPath_doc}, + {"expandPath", (PyCFunction)gPyExpandPath, METH_VARARGS, (PY_METHODCHAR)gPyExpandPath_doc}, {"getCurrentController", (PyCFunction) SCA_PythonController::sPyGetCurrentController, - METH_NOARGS, SCA_PythonController::sPyGetCurrentController__doc__}, + METH_NOARGS, (PY_METHODCHAR)SCA_PythonController::sPyGetCurrentController__doc__}, {"getCurrentScene", (PyCFunction) gPyGetCurrentScene, - METH_NOARGS, gPyGetCurrentScene_doc.Ptr()}, + METH_NOARGS, (PY_METHODCHAR)gPyGetCurrentScene_doc.Ptr()}, {"addActiveActuator",(PyCFunction) SCA_PythonController::sPyAddActiveActuator, - METH_VARARGS, SCA_PythonController::sPyAddActiveActuator__doc__}, + METH_VARARGS, (PY_METHODCHAR)SCA_PythonController::sPyAddActiveActuator__doc__}, {"getRandomFloat",(PyCFunction) gPyGetRandomFloat, - METH_NOARGS,gPyGetRandomFloat_doc.Ptr()}, - {"setGravity",(PyCFunction) gPySetGravity, METH_VARARGS,"set Gravitation"}, - {"getSpectrum",(PyCFunction) gPyGetSpectrum, METH_NOARGS,"get audio spectrum"}, - {"stopDSP",(PyCFunction) gPyStopDSP, METH_VARARGS,"stop using the audio dsp (for performance reasons)"}, - {"getLogicTicRate", (PyCFunction) gPyGetLogicTicRate, METH_NOARGS, "Gets the logic tic rate"}, - {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, "Sets the logic tic rate"}, - {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_NOARGS, "Gets the physics tic rate"}, - {"setPhysicsTicRate", (PyCFunction) gPySetPhysicsTicRate, METH_VARARGS, "Sets the physics tic rate"}, - {"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, "Prints GL Extension Info"}, + METH_NOARGS, (PY_METHODCHAR)gPyGetRandomFloat_doc.Ptr()}, + {"setGravity",(PyCFunction) gPySetGravity, METH_VARARGS, (PY_METHODCHAR)"set Gravitation"}, + {"getSpectrum",(PyCFunction) gPyGetSpectrum, METH_NOARGS, (PY_METHODCHAR)"get audio spectrum"}, + {"stopDSP",(PyCFunction) gPyStopDSP, METH_VARARGS, (PY_METHODCHAR)"stop using the audio dsp (for performance reasons)"}, + {"getLogicTicRate", (PyCFunction) gPyGetLogicTicRate, METH_NOARGS, (PY_METHODCHAR)"Gets the logic tic rate"}, + {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, (PY_METHODCHAR)"Sets the logic tic rate"}, + {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_NOARGS, (PY_METHODCHAR)"Gets the physics tic rate"}, + {"setPhysicsTicRate", (PyCFunction) gPySetPhysicsTicRate, METH_VARARGS, (PY_METHODCHAR)"Sets the physics tic rate"}, + {"getAverageFrameRate", (PyCFunction) gPyGetAverageFrameRate, METH_NOARGS, (PY_METHODCHAR)"Gets the estimated average frame rate"}, + {"getBlendFileList", (PyCFunction)gPyGetBlendFileList, METH_VARARGS, (PY_METHODCHAR)"Gets a list of blend files in the same directory as the current blend file"}, + {"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, (PY_METHODCHAR)"Prints GL Extension Info"}, {NULL, (PyCFunction) NULL, 0, NULL } }; -static PyObject* gPyGetWindowHeight(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyGetWindowHeight(PyObject*, PyObject* args) { - int height = (gp_Canvas ? gp_Canvas->GetHeight() : 0); - - PyObject* heightval = PyInt_FromLong(height); - return heightval; + return PyInt_FromLong((gp_Canvas ? gp_Canvas->GetHeight() : 0)); } -static PyObject* gPyGetWindowWidth(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyGetWindowWidth(PyObject*, PyObject* args) { - - - int width = (gp_Canvas ? gp_Canvas->GetWidth() : 0); - - PyObject* widthval = PyInt_FromLong(width); - return widthval; + return PyInt_FromLong((gp_Canvas ? gp_Canvas->GetWidth() : 0)); } @@ -411,282 +442,403 @@ static PyObject* gPyGetWindowWidth(PyObject*, // temporarility visibility thing, will be moved to rasterizer/renderer later bool gUseVisibilityTemp = false; -static PyObject* gPyEnableVisibility(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyEnableVisibility(PyObject*, PyObject* args) { int visible; - if (PyArg_ParseTuple(args,"i",&visible)) - { - gUseVisibilityTemp = (visible != 0); - } - else - { + if (!PyArg_ParseTuple(args,"i",&visible)) return NULL; - } - Py_Return; + + gUseVisibilityTemp = (visible != 0); + Py_RETURN_NONE; } -static PyObject* gPyShowMouse(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyShowMouse(PyObject*, PyObject* args) { int visible; - if (PyArg_ParseTuple(args,"i",&visible)) - { - if (visible) - { - if (gp_Canvas) - gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); - } else - { - if (gp_Canvas) - gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); - } - } - else { + if (!PyArg_ParseTuple(args,"i",&visible)) return NULL; + + if (visible) + { + if (gp_Canvas) + gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); + } else + { + if (gp_Canvas) + gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); } - Py_Return; + Py_RETURN_NONE; } -static PyObject* gPySetMousePosition(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetMousePosition(PyObject*, PyObject* args) { int x,y; - if (PyArg_ParseTuple(args,"ii",&x,&y)) - { - if (gp_Canvas) - gp_Canvas->SetMousePosition(x,y); - } - else { + if (!PyArg_ParseTuple(args,"ii",&x,&y)) return NULL; - } - Py_Return; + if (gp_Canvas) + gp_Canvas->SetMousePosition(x,y); + + Py_RETURN_NONE; } -static PyObject* gPySetEyeSeparation(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetEyeSeparation(PyObject*, PyObject* args) { float sep; - if (PyArg_ParseTuple(args, "f", &sep)) - { - if (gp_Rasterizer) - gp_Rasterizer->SetEyeSeparation(sep); - - Py_Return; + if (!PyArg_ParseTuple(args, "f", &sep)) + return NULL; + + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + return NULL; } - return NULL; + gp_Rasterizer->SetEyeSeparation(sep); + + Py_RETURN_NONE; } static PyObject* gPyGetEyeSeparation(PyObject*, PyObject*, PyObject*) { - if (gp_Rasterizer) - return PyFloat_FromDouble(gp_Rasterizer->GetEyeSeparation()); + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + return NULL; + } - return NULL; + return PyFloat_FromDouble(gp_Rasterizer->GetEyeSeparation()); } -static PyObject* gPySetFocalLength(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetFocalLength(PyObject*, PyObject* args) { float focus; - if (PyArg_ParseTuple(args, "f", &focus)) - { - if (gp_Rasterizer) - gp_Rasterizer->SetFocalLength(focus); - Py_Return; + if (!PyArg_ParseTuple(args, "f", &focus)) + return NULL; + + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + return NULL; } + + gp_Rasterizer->SetFocalLength(focus); - return NULL; + Py_RETURN_NONE; } static PyObject* gPyGetFocalLength(PyObject*, PyObject*, PyObject*) { - if (gp_Rasterizer) - return PyFloat_FromDouble(gp_Rasterizer->GetFocalLength()); - return NULL; + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + return NULL; + } + + return PyFloat_FromDouble(gp_Rasterizer->GetFocalLength()); + + Py_RETURN_NONE; } -static PyObject* gPySetBackgroundColor(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetBackgroundColor(PyObject*, PyObject* args) { MT_Vector4 vec = MT_Vector4(0., 0., 0.3, 0.); - if (PyVecArgTo(args, vec)) + if (!PyVecArgTo(args, vec)) + return NULL; + + if (gp_Canvas) { - if (gp_Canvas) - { - gp_Rasterizer->SetBackColor(vec[0], vec[1], vec[2], vec[3]); - } - Py_Return; + gp_Rasterizer->SetBackColor(vec[0], vec[1], vec[2], vec[3]); } - - return NULL; + Py_RETURN_NONE; } -static PyObject* gPySetMistColor(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetMistColor(PyObject*, PyObject* args) { MT_Vector3 vec = MT_Vector3(0., 0., 0.); - if (PyVecArgTo(args, vec)) - { - if (gp_Rasterizer) - { - gp_Rasterizer->SetFogColor(vec[0], vec[1], vec[2]); - } - Py_Return; - } + if (!PyVecArgTo(args, vec)) + return NULL; - return NULL; + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + return NULL; + } + gp_Rasterizer->SetFogColor(vec[0], vec[1], vec[2]); + + Py_RETURN_NONE; } -static PyObject* gPySetMistStart(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetMistStart(PyObject*, PyObject* args) { float miststart; - if (PyArg_ParseTuple(args,"f",&miststart)) - { - if (gp_Rasterizer) - { - gp_Rasterizer->SetFogStart(miststart); - } - } - else { + if (!PyArg_ParseTuple(args,"f",&miststart)) + return NULL; + + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); return NULL; } - Py_Return; + + gp_Rasterizer->SetFogStart(miststart); + + Py_RETURN_NONE; } -static PyObject* gPySetMistEnd(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetMistEnd(PyObject*, PyObject* args) { float mistend; - if (PyArg_ParseTuple(args,"f",&mistend)) - { - if (gp_Rasterizer) - { - gp_Rasterizer->SetFogEnd(mistend); - } - } - else { + if (!PyArg_ParseTuple(args,"f",&mistend)) + return NULL; + + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); return NULL; } - Py_Return; + + gp_Rasterizer->SetFogEnd(mistend); + + Py_RETURN_NONE; } -static PyObject* gPySetAmbientColor(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPySetAmbientColor(PyObject*, PyObject* args) { MT_Vector3 vec = MT_Vector3(0., 0., 0.); - if (PyVecArgTo(args, vec)) - { - if (gp_Rasterizer) - { - gp_Rasterizer->SetAmbientColor(vec[0], vec[1], vec[2]); - } - Py_Return; - } + if (!PyVecArgTo(args, vec)) + return NULL; - return NULL; + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + return NULL; + } + gp_Rasterizer->SetAmbientColor(vec[0], vec[1], vec[2]); + + Py_RETURN_NONE; } -static PyObject* gPyMakeScreenshot(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyMakeScreenshot(PyObject*, PyObject* args) { char* filename; - if (PyArg_ParseTuple(args,"s",&filename)) + if (!PyArg_ParseTuple(args,"s",&filename)) + return NULL; + + if (gp_Canvas) { - if (gp_Canvas) - { - gp_Canvas->MakeScreenShot(filename); - } + gp_Canvas->MakeScreenShot(filename); } - else { + + Py_RETURN_NONE; +} + +static PyObject* gPyEnableMotionBlur(PyObject*, PyObject* args) +{ + float motionblurvalue; + if (!PyArg_ParseTuple(args,"f",&motionblurvalue)) + return NULL; + + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); return NULL; } - Py_Return; + + gp_Rasterizer->EnableMotionBlur(motionblurvalue); + + Py_RETURN_NONE; } -static PyObject* gPyEnableMotionBlur(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyDisableMotionBlur(PyObject*, PyObject* args) { - float motionblurvalue; - if (PyArg_ParseTuple(args,"f",&motionblurvalue)) - { - if(gp_Rasterizer) - { - gp_Rasterizer->EnableMotionBlur(motionblurvalue); + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + return NULL; + } + + gp_Rasterizer->DisableMotionBlur(); + + Py_RETURN_NONE; +} + +int getGLSLSettingFlag(char *setting) +{ + if(strcmp(setting, "lights") == 0) + return G_FILE_GLSL_NO_LIGHTS; + else if(strcmp(setting, "shaders") == 0) + return G_FILE_GLSL_NO_SHADERS; + else if(strcmp(setting, "shadows") == 0) + return G_FILE_GLSL_NO_SHADOWS; + else if(strcmp(setting, "ramps") == 0) + return G_FILE_GLSL_NO_RAMPS; + else if(strcmp(setting, "nodes") == 0) + return G_FILE_GLSL_NO_NODES; + else if(strcmp(setting, "extra_textures") == 0) + return G_FILE_GLSL_NO_EXTRA_TEX; + else + return -1; +} + +static PyObject* gPySetGLSLMaterialSetting(PyObject*, + PyObject* args, + PyObject*) +{ + char *setting; + int enable, flag, fileflags; + + if (!PyArg_ParseTuple(args,"si",&setting,&enable)) + return NULL; + + flag = getGLSLSettingFlag(setting); + + if (flag==-1) { + PyErr_SetString(PyExc_ValueError, "glsl setting is not known"); + return NULL; + } + + fileflags = G.fileflags; + + if (enable) + G.fileflags &= ~flag; + else + G.fileflags |= flag; + + /* display lists and GLSL materials need to be remade */ + if(G.fileflags != fileflags) { + if(gp_KetsjiEngine) { + KX_SceneList *scenes = gp_KetsjiEngine->CurrentScenes(); + KX_SceneList::iterator it; + + for(it=scenes->begin(); it!=scenes->end(); it++) + if((*it)->GetBucketManager()) + (*it)->GetBucketManager()->ReleaseDisplayLists(); } + + GPU_materials_free(); } - else { + + Py_RETURN_NONE; +} + +static PyObject* gPyGetGLSLMaterialSetting(PyObject*, + PyObject* args, + PyObject*) +{ + char *setting; + int enabled = 0, flag; + + if (!PyArg_ParseTuple(args,"s",&setting)) + return NULL; + + flag = getGLSLSettingFlag(setting); + + if (flag==-1) { + PyErr_SetString(PyExc_ValueError, "glsl setting is not known"); return NULL; } - Py_Return; + + enabled = ((G.fileflags & flag) != 0); + return PyInt_FromLong(enabled); } -static PyObject* gPyDisableMotionBlur(PyObject*, +#define KX_TEXFACE_MATERIAL 0 +#define KX_BLENDER_MULTITEX_MATERIAL 1 +#define KX_BLENDER_GLSL_MATERIAL 2 + +static PyObject* gPySetMaterialType(PyObject*, PyObject* args, PyObject*) { - if(gp_Rasterizer) - { - gp_Rasterizer->DisableMotionBlur(); + int flag, type; + + if (!PyArg_ParseTuple(args,"i",&type)) + return NULL; + + if(type == KX_BLENDER_GLSL_MATERIAL) + flag = G_FILE_GAME_MAT|G_FILE_GAME_MAT_GLSL; + else if(type == KX_BLENDER_MULTITEX_MATERIAL) + flag = G_FILE_GAME_MAT; + else if(type == KX_TEXFACE_MATERIAL) + flag = 0; + else { + PyErr_SetString(PyExc_ValueError, "material type is not known"); + return NULL; } - Py_Return; + + G.fileflags &= ~(G_FILE_GAME_MAT|G_FILE_GAME_MAT_GLSL); + G.fileflags |= flag; + + Py_RETURN_NONE; +} + +static PyObject* gPyGetMaterialType(PyObject*) +{ + int flag; + + if(G.fileflags & (G_FILE_GAME_MAT|G_FILE_GAME_MAT_GLSL)) + flag = KX_BLENDER_GLSL_MATERIAL; + else if(G.fileflags & G_FILE_GAME_MAT) + flag = KX_BLENDER_MULTITEX_MATERIAL; + else + flag = KX_TEXFACE_MATERIAL; + + return PyInt_FromLong(flag); } -STR_String gPyGetWindowHeight__doc__="getWindowHeight doc"; -STR_String gPyGetWindowWidth__doc__="getWindowWidth doc"; -STR_String gPyEnableVisibility__doc__="enableVisibility doc"; -STR_String gPyMakeScreenshot__doc__="make Screenshot doc"; -STR_String gPyShowMouse__doc__="showMouse(bool visible)"; -STR_String gPySetMousePosition__doc__="setMousePosition(int x,int y)"; +static PyObject* gPyDrawLine(PyObject*, PyObject* args) +{ + PyObject* ob_from; + PyObject* ob_to; + PyObject* ob_color; + + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + return NULL; + } + + if (!PyArg_ParseTuple(args,"OOO",&ob_from,&ob_to,&ob_color)) + return NULL; + + MT_Vector3 from(0., 0., 0.); + MT_Vector3 to(0., 0., 0.); + MT_Vector3 color(0., 0., 0.); + if (!PyVecTo(ob_from, from)) + return NULL; + if (!PyVecTo(ob_to, to)) + return NULL; + if (!PyVecTo(ob_color, color)) + return NULL; + + gp_Rasterizer->DrawDebugLine(from,to,color); + + Py_RETURN_NONE; +} static struct PyMethodDef rasterizer_methods[] = { {"getWindowWidth",(PyCFunction) gPyGetWindowWidth, - METH_VARARGS, gPyGetWindowWidth__doc__.Ptr()}, + METH_VARARGS, "getWindowWidth doc"}, {"getWindowHeight",(PyCFunction) gPyGetWindowHeight, - METH_VARARGS, gPyGetWindowHeight__doc__.Ptr()}, + METH_VARARGS, "getWindowHeight doc"}, {"makeScreenshot",(PyCFunction)gPyMakeScreenshot, - METH_VARARGS, gPyMakeScreenshot__doc__.Ptr()}, + METH_VARARGS, "make Screenshot doc"}, {"enableVisibility",(PyCFunction) gPyEnableVisibility, - METH_VARARGS, gPyEnableVisibility__doc__.Ptr()}, + METH_VARARGS, "enableVisibility doc"}, {"showMouse",(PyCFunction) gPyShowMouse, - METH_VARARGS, gPyShowMouse__doc__.Ptr()}, + METH_VARARGS, "showMouse(bool visible)"}, {"setMousePosition",(PyCFunction) gPySetMousePosition, - METH_VARARGS, gPySetMousePosition__doc__.Ptr()}, + METH_VARARGS, "setMousePosition(int x,int y)"}, {"setBackgroundColor",(PyCFunction)gPySetBackgroundColor,METH_VARARGS,"set Background Color (rgb)"}, {"setAmbientColor",(PyCFunction)gPySetAmbientColor,METH_VARARGS,"set Ambient Color (rgb)"}, {"setMistColor",(PyCFunction)gPySetMistColor,METH_VARARGS,"set Mist Color (rgb)"}, @@ -700,11 +852,19 @@ static struct PyMethodDef rasterizer_methods[] = { {"getEyeSeparation", (PyCFunction) gPyGetEyeSeparation, METH_VARARGS, "get the eye separation for stereo mode"}, {"setFocalLength", (PyCFunction) gPySetFocalLength, METH_VARARGS, "set the focal length for stereo mode"}, {"getFocalLength", (PyCFunction) gPyGetFocalLength, METH_VARARGS, "get the focal length for stereo mode"}, + {"setMaterialMode",(PyCFunction) gPySetMaterialType, + METH_VARARGS, "set the material mode to use for OpenGL rendering"}, + {"getMaterialMode",(PyCFunction) gPyGetMaterialType, + METH_NOARGS, "get the material mode being used for OpenGL rendering"}, + {"setGLSLMaterialSetting",(PyCFunction) gPySetGLSLMaterialSetting, + METH_VARARGS, "set the state of a GLSL material setting"}, + {"getGLSLMaterialSetting",(PyCFunction) gPyGetGLSLMaterialSetting, + METH_VARARGS, "get the state of a GLSL material setting"}, + {"drawLine", (PyCFunction) gPyDrawLine, + METH_VARARGS, "draw a line on the screen"}, { NULL, (PyCFunction) NULL, 0, NULL } }; - - // Initialization function for the module (*must* be called initGameLogic) static char GameLogic_module_documentation[] = @@ -717,11 +877,12 @@ static char Rasterizer_module_documentation[] = -PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook +PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack to get gravity hook { PyObject* m; PyObject* d; + gp_KetsjiEngine = engine; gp_KetsjiScene = scene; gUseVisibilityTemp=false; @@ -733,6 +894,10 @@ PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook // Add some symbolic constants to the module d = PyModule_GetDict(m); + + // can be overwritten later for gameEngine instances that can load new blend files and re-initialize this module + // for now its safe to make sure it exists for other areas such as the web plugin + PyDict_SetItemString(d, "globalDict", PyDict_New()); ErrorObject = PyString_FromString("GameLogic.error"); PyDict_SetItemString(d, "error", ErrorObject); @@ -834,6 +999,38 @@ PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook KX_MACRO_addTypesToDict(d, CAM_POS, BL_Shader::CAM_POS); KX_MACRO_addTypesToDict(d, CONSTANT_TIMER, BL_Shader::CONSTANT_TIMER); + /* 10 state actuator */ + KX_MACRO_addTypesToDict(d, KX_STATE1, (1<<0)); + KX_MACRO_addTypesToDict(d, KX_STATE2, (1<<1)); + KX_MACRO_addTypesToDict(d, KX_STATE3, (1<<2)); + KX_MACRO_addTypesToDict(d, KX_STATE4, (1<<3)); + KX_MACRO_addTypesToDict(d, KX_STATE5, (1<<4)); + KX_MACRO_addTypesToDict(d, KX_STATE6, (1<<5)); + KX_MACRO_addTypesToDict(d, KX_STATE7, (1<<6)); + KX_MACRO_addTypesToDict(d, KX_STATE8, (1<<7)); + KX_MACRO_addTypesToDict(d, KX_STATE9, (1<<8)); + KX_MACRO_addTypesToDict(d, KX_STATE10, (1<<9)); + KX_MACRO_addTypesToDict(d, KX_STATE11, (1<<10)); + KX_MACRO_addTypesToDict(d, KX_STATE12, (1<<11)); + KX_MACRO_addTypesToDict(d, KX_STATE13, (1<<12)); + KX_MACRO_addTypesToDict(d, KX_STATE14, (1<<13)); + KX_MACRO_addTypesToDict(d, KX_STATE15, (1<<14)); + KX_MACRO_addTypesToDict(d, KX_STATE16, (1<<15)); + KX_MACRO_addTypesToDict(d, KX_STATE17, (1<<16)); + KX_MACRO_addTypesToDict(d, KX_STATE18, (1<<17)); + KX_MACRO_addTypesToDict(d, KX_STATE19, (1<<18)); + KX_MACRO_addTypesToDict(d, KX_STATE20, (1<<19)); + KX_MACRO_addTypesToDict(d, KX_STATE21, (1<<20)); + KX_MACRO_addTypesToDict(d, KX_STATE22, (1<<21)); + KX_MACRO_addTypesToDict(d, KX_STATE23, (1<<22)); + KX_MACRO_addTypesToDict(d, KX_STATE24, (1<<23)); + KX_MACRO_addTypesToDict(d, KX_STATE25, (1<<24)); + KX_MACRO_addTypesToDict(d, KX_STATE26, (1<<25)); + KX_MACRO_addTypesToDict(d, KX_STATE27, (1<<26)); + KX_MACRO_addTypesToDict(d, KX_STATE28, (1<<27)); + KX_MACRO_addTypesToDict(d, KX_STATE29, (1<<28)); + KX_MACRO_addTypesToDict(d, KX_STATE30, (1<<29)); + // Check for errors if (PyErr_Occurred()) { @@ -847,13 +1044,30 @@ PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook // override builtin functions import() and open() -PyObject *KXpy_open(PyObject *self, PyObject *args) -{ +PyObject *KXpy_open(PyObject *self, PyObject *args) { PyErr_SetString(PyExc_RuntimeError, "Sandbox: open() function disabled!\nGame Scripts should not use this function."); return NULL; } +PyObject *KXpy_reload(PyObject *self, PyObject *args) { + PyErr_SetString(PyExc_RuntimeError, "Sandbox: reload() function disabled!\nGame Scripts should not use this function."); + return NULL; +} + +PyObject *KXpy_file(PyObject *self, PyObject *args) { + PyErr_SetString(PyExc_RuntimeError, "Sandbox: file() function disabled!\nGame Scripts should not use this function."); + return NULL; +} +PyObject *KXpy_execfile(PyObject *self, PyObject *args) { + PyErr_SetString(PyExc_RuntimeError, "Sandbox: execfile() function disabled!\nGame Scripts should not use this function."); + return NULL; +} + +PyObject *KXpy_compile(PyObject *self, PyObject *args) { + PyErr_SetString(PyExc_RuntimeError, "Sandbox: compile() function disabled!\nGame Scripts should not use this function."); + return NULL; +} PyObject *KXpy_import(PyObject *self, PyObject *args) { @@ -889,40 +1103,67 @@ PyObject *KXpy_import(PyObject *self, PyObject *args) } +/* override python file type functions */ +#if 0 +static int +file_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + KXpy_file(NULL, NULL); + return -1; +} +static PyObject * +file_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return KXpy_file(NULL, NULL); +} +#endif -static PyMethodDef meth_open[] = { - { "open", KXpy_open, METH_VARARGS, - "(disabled)"} -}; - - -static PyMethodDef meth_import[] = { - { "import", KXpy_import, METH_VARARGS, - "our own import"} -}; - +static PyMethodDef meth_open[] = {{ "open", KXpy_open, METH_VARARGS, "(disabled)"}}; +static PyMethodDef meth_reload[] = {{ "reload", KXpy_reload, METH_VARARGS, "(disabled)"}}; +static PyMethodDef meth_file[] = {{ "file", KXpy_file, METH_VARARGS, "(disabled)"}}; +static PyMethodDef meth_execfile[] = {{ "execfile", KXpy_execfile, METH_VARARGS, "(disabled)"}}; +static PyMethodDef meth_compile[] = {{ "compile", KXpy_compile, METH_VARARGS, "(disabled)"}}; +static PyMethodDef meth_import[] = {{ "import", KXpy_import, METH_VARARGS, "our own import"}}; //static PyObject *g_oldopen = 0; //static PyObject *g_oldimport = 0; //static int g_security = 0; - void setSandbox(TPythonSecurityLevel level) { PyObject *m = PyImport_AddModule("__builtin__"); PyObject *d = PyModule_GetDict(m); - PyObject *meth = PyCFunction_New(meth_open, NULL); switch (level) { case psl_Highest: //if (!g_security) { //g_oldopen = PyDict_GetItemString(d, "open"); - PyDict_SetItemString(d, "open", meth); - meth = PyCFunction_New(meth_import, NULL); - PyDict_SetItemString(d, "__import__", meth); + + // functions we cant trust + PyDict_SetItemString(d, "open", PyCFunction_New(meth_open, NULL)); + PyDict_SetItemString(d, "reload", PyCFunction_New(meth_reload, NULL)); + PyDict_SetItemString(d, "file", PyCFunction_New(meth_file, NULL)); + PyDict_SetItemString(d, "execfile", PyCFunction_New(meth_execfile, NULL)); + PyDict_SetItemString(d, "compile", PyCFunction_New(meth_compile, NULL)); + + // our own import + PyDict_SetItemString(d, "__import__", PyCFunction_New(meth_import, NULL)); //g_security = level; + + // Overiding file dosnt stop it being accessed if your sneaky + // f = [ t for t in (1).__class__.__mro__[-1].__subclasses__() if t.__name__ == 'file'][0]('/some_file.txt', 'w') + // f.write('...') + // so overwrite the file types functions. be very careful here still, since python uses python. + // ps - python devs frown deeply upon this. + + /* this could mess up pythons internals, if we are serious about sandboxing + * issues like the one above need to be solved, possibly modify __subclasses__ is safer? */ +#if 0 + PyFile_Type.tp_init = file_init; + PyFile_Type.tp_new = file_new; +#endif //} break; /* @@ -1005,6 +1246,11 @@ PyObject* initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas) ErrorObject = PyString_FromString("Rasterizer.error"); PyDict_SetItemString(d, "error", ErrorObject); + /* needed for get/setMaterialType */ + KX_MACRO_addTypesToDict(d, KX_TEXFACE_MATERIAL, KX_TEXFACE_MATERIAL); + KX_MACRO_addTypesToDict(d, KX_BLENDER_MULTITEX_MATERIAL, KX_BLENDER_MULTITEX_MATERIAL); + KX_MACRO_addTypesToDict(d, KX_BLENDER_GLSL_MATERIAL, KX_BLENDER_GLSL_MATERIAL); + // XXXX Add constants here // Check for errors @@ -1026,9 +1272,38 @@ static char GameKeys_module_documentation[] = "This modules provides defines for key-codes" ; +static char gPyEventToString_doc[] = +"Take a valid event from the GameKeys module or Keyboard Sensor and return a name" +; +static PyObject* gPyEventToString(PyObject*, PyObject* value) +{ + PyObject* mod, *dict, *key, *val, *ret = NULL; + Py_ssize_t pos = 0; + + mod = PyImport_ImportModule( "GameKeys" ); + if (!mod) + return NULL; + + dict = PyModule_GetDict(mod); + + while (PyDict_Next(dict, &pos, &key, &val)) { + if (PyObject_Compare(value, val)==0) { + ret = key; + break; + } + } + + PyErr_Clear(); // incase there was an error clearing + Py_DECREF(mod); + if (!ret) PyErr_SetString(PyExc_ValueError, "expected a valid int keyboard event"); + else Py_INCREF(ret); + + return ret; +} static struct PyMethodDef gamekeys_methods[] = { + {"EventToString", (PyCFunction)gPyEventToString, METH_O, (PY_METHODCHAR)gPyEventToString_doc}, { NULL, (PyCFunction) NULL, 0, NULL } }; @@ -1186,3 +1461,76 @@ class KX_Scene* PHY_GetActiveScene() { return gp_KetsjiScene; } + +// utility function for loading and saving the globalDict +int saveGamePythonConfig( char **marshal_buffer) +{ + int marshal_length = 0; + PyObject* gameLogic = PyImport_ImportModule("GameLogic"); + if (gameLogic) { + PyObject* pyGlobalDict = PyDict_GetItemString(PyModule_GetDict(gameLogic), "globalDict"); // Same as importing the module + if (pyGlobalDict) { +#ifdef Py_MARSHAL_VERSION + PyObject* pyGlobalDictMarshal = PyMarshal_WriteObjectToString( pyGlobalDict, 2); // Py_MARSHAL_VERSION == 2 as of Py2.5 +#else + PyObject* pyGlobalDictMarshal = PyMarshal_WriteObjectToString( pyGlobalDict ); +#endif + if (pyGlobalDictMarshal) { + // for testing only + // PyObject_Print(pyGlobalDictMarshal, stderr, 0); + + marshal_length= PyString_Size(pyGlobalDictMarshal); + *marshal_buffer = new char[marshal_length + 1]; + memcpy(*marshal_buffer, PyString_AsString(pyGlobalDictMarshal), marshal_length); + + Py_DECREF(pyGlobalDictMarshal); + } else { + printf("Error, GameLogic.globalDict could not be marshal'd\n"); + } + } else { + printf("Error, GameLogic.globalDict was removed\n"); + } + Py_DECREF(gameLogic); + } else { + printf("Error, GameLogic failed to import GameLogic.globalDict will be lost\n"); + } + return marshal_length; +} + +int loadGamePythonConfig(char *marshal_buffer, int marshal_length) +{ + /* Restore the dict */ + if (marshal_buffer) { + PyObject* gameLogic = PyImport_ImportModule("GameLogic"); + + if (gameLogic) { + PyObject* pyGlobalDict = PyMarshal_ReadObjectFromString(marshal_buffer, marshal_length); + + if (pyGlobalDict) { + PyDict_SetItemString(PyModule_GetDict(gameLogic), "globalDict", pyGlobalDict); // Same as importing the module. + Py_DECREF(gameLogic); + return 1; + } else { + Py_DECREF(gameLogic); + PyErr_Clear(); + printf("Error could not marshall string\n"); + } + } else { + printf("Error, GameLogic failed to import GameLogic.globalDict will be lost\n"); + } + } + return 0; +} + +void pathGamePythonConfig( char *path ) +{ + int len = strlen(G.sce); + + strncpy(path, G.sce, sizeof(G.sce)); + /* replace extension */ + if (BLI_testextensie(path, ".blend")) { + strcpy(path+(len-6), ".bgeconf"); + } else { + strcpy(path+len, ".bgeconf"); + } +} diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h index f094a1ca575..28d9d72a4c3 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.h +++ b/source/gameengine/Ketsji/KX_PythonInit.h @@ -40,7 +40,7 @@ typedef enum { extern bool gUseVisibilityTemp; -PyObject* initGameLogic(class KX_Scene* ketsjiscene); +PyObject* initGameLogic(class KX_KetsjiEngine *engine, class KX_Scene* ketsjiscene); PyObject* initGameKeys(); PyObject* initRasterizer(class RAS_IRasterizer* rasty,class RAS_ICanvas* canvas); PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level); @@ -49,6 +49,10 @@ void exitGamePlayerPythonScripting(); PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level); void exitGamePythonScripting(); +void pathGamePythonConfig( char *path ); +int saveGamePythonConfig( char **marshal_buffer); +int loadGamePythonConfig(char *marshal_buffer, int marshal_length); + void PHY_SetActiveScene(class KX_Scene* scene); class KX_Scene* PHY_GetActiveScene(); #include "MT_Vector3.h" diff --git a/source/gameengine/Ketsji/KX_RadarSensor.cpp b/source/gameengine/Ketsji/KX_RadarSensor.cpp index d371626b597..244e9b75d8e 100644 --- a/source/gameengine/Ketsji/KX_RadarSensor.cpp +++ b/source/gameengine/Ketsji/KX_RadarSensor.cpp @@ -221,11 +221,11 @@ PyParentObject KX_RadarSensor::Parents[] = { PyMethodDef KX_RadarSensor::Methods[] = { {"getConeOrigin", (PyCFunction) KX_RadarSensor::sPyGetConeOrigin, - METH_VARARGS, GetConeOrigin_doc}, + METH_VARARGS, (PY_METHODCHAR)GetConeOrigin_doc}, {"getConeTarget", (PyCFunction) KX_RadarSensor::sPyGetConeTarget, - METH_VARARGS, GetConeTarget_doc}, + METH_VARARGS, (PY_METHODCHAR)GetConeTarget_doc}, {"getConeHeight", (PyCFunction) KX_RadarSensor::sPyGetConeHeight, - METH_VARARGS, GetConeHeight_doc}, + METH_VARARGS, (PY_METHODCHAR)GetConeHeight_doc}, {NULL,NULL,NULL,NULL} //Sentinel }; @@ -234,7 +234,7 @@ PyObject* KX_RadarSensor::_getattr(const STR_String& attr) { } /* getConeOrigin */ -char KX_RadarSensor::GetConeOrigin_doc[] = +const char KX_RadarSensor::GetConeOrigin_doc[] = "getConeOrigin()\n" "\tReturns the origin of the cone with which to test. The origin\n" "\tis in the middle of the cone."; @@ -251,7 +251,7 @@ PyObject* KX_RadarSensor::PyGetConeOrigin(PyObject* self, } /* getConeOrigin */ -char KX_RadarSensor::GetConeTarget_doc[] = +const char KX_RadarSensor::GetConeTarget_doc[] = "getConeTarget()\n" "\tReturns the center of the bottom face of the cone with which to test.\n"; PyObject* KX_RadarSensor::PyGetConeTarget(PyObject* self, @@ -267,7 +267,7 @@ PyObject* KX_RadarSensor::PyGetConeTarget(PyObject* self, } /* getConeOrigin */ -char KX_RadarSensor::GetConeHeight_doc[] = +const char KX_RadarSensor::GetConeHeight_doc[] = "getConeHeight()\n" "\tReturns the height of the cone with which to test.\n"; PyObject* KX_RadarSensor::PyGetConeHeight(PyObject* self, diff --git a/source/gameengine/Ketsji/KX_RayCast.cpp b/source/gameengine/Ketsji/KX_RayCast.cpp index 89e2d645d54..974d4b992a6 100644 --- a/source/gameengine/Ketsji/KX_RayCast.cpp +++ b/source/gameengine/Ketsji/KX_RayCast.cpp @@ -40,7 +40,21 @@ #include "PHY_IPhysicsEnvironment.h" #include "PHY_IPhysicsController.h" -bool KX_RayCast::RayTest(KX_IPhysicsController* ignore_controller, PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, MT_Point3& result_point, MT_Vector3& result_normal, const KX_RayCast& callback) +KX_RayCast::KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal) + :PHY_IRayCastFilterCallback(dynamic_cast<PHY_IPhysicsController*>(ignoreController), faceNormal) +{ +} + +void KX_RayCast::reportHit(PHY_RayCastResult* result) +{ + m_hitFound = true; + m_hitPoint.setValue((const float*)result->m_hitPoint); + m_hitNormal.setValue((const float*)result->m_hitNormal); + m_hitMesh = result->m_meshObject; + m_hitPolygon = result->m_polygon; +} + +bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, KX_RayCast& callback) { // Loops over all physics objects between frompoint and topoint, // calling callback.RayHit for each one. @@ -50,58 +64,51 @@ bool KX_RayCast::RayTest(KX_IPhysicsController* ignore_controller, PHY_IPhysicsE // returns true if an object was found, false if not. MT_Point3 frompoint(_frompoint); const MT_Vector3 todir( (topoint - frompoint).safe_normalized() ); + MT_Point3 prevpoint(_frompoint+todir*(-1.f)); PHY_IPhysicsController* hit_controller; - PHY__Vector3 phy_pos; - PHY__Vector3 phy_normal; - while((hit_controller = physics_environment->rayTest(dynamic_cast<PHY_IPhysicsController*>(ignore_controller), + while((hit_controller = physics_environment->rayTest(callback, frompoint.x(),frompoint.y(),frompoint.z(), - topoint.x(),topoint.y(),topoint.z(), - phy_pos[0],phy_pos[1],phy_pos[2], - phy_normal[0],phy_normal[1],phy_normal[2]))) + topoint.x(),topoint.y(),topoint.z())) != NULL) { - result_point = MT_Point3(phy_pos); - result_normal = MT_Vector3(phy_normal); KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(hit_controller->getNewClientInfo()); if (!info) { printf("no info!\n"); MT_assert(info && "Physics controller with no client object info"); - return false; + break; } - if (callback.RayHit(info, result_point, result_normal)) - return true; - - // There is a bug in the code below: the delta is computed with the wrong - // sign on the face opposite to the center, resulting in infinite looping. - // In Blender 2.45 this code was never executed because callback.RayHit() always - // returned true, causing the ray sensor to stop on the first object. - // To avoid changing the behaviour will simply return false here. - // It should be discussed if we want the ray sensor to "see" through objects - // that don't have the required property/material (condition to get here) - return false; - - // skip past the object and keep tracing - /* We add 0.01 of fudge, so that if the margin && radius == 0., we don't endless loop. */ - MT_Scalar marg = 0.01 + hit_controller->GetMargin(); - marg += 2.f * hit_controller->GetMargin(); + // The biggest danger to to endless loop, prevent this by checking that the + // hit point always progresses along the ray direction.. + prevpoint -= callback.m_hitPoint; + if (prevpoint.length2() < MT_EPSILON) + break; + + if (callback.RayHit(info)) + // caller may decide to stop the loop and still cancel the hit + return callback.m_hitFound; + + // Skip past the object and keep tracing. + // Note that retrieving in a single shot multiple hit points would be possible + // but it would require some change in Bullet. + prevpoint = callback.m_hitPoint; + /* We add 0.001 of fudge, so that if the margin && radius == 0., we don't endless loop. */ + MT_Scalar marg = 0.001 + hit_controller->GetMargin(); + marg *= 2.f; /* Calculate the other side of this object */ - PHY__Vector3 hitpos; - hit_controller->getPosition(hitpos); - MT_Point3 hitObjPos(hitpos); - - MT_Vector3 hitvector = hitObjPos - result_point; - if (hitvector.dot(hitvector) > MT_EPSILON) - { - hitvector.normalize(); - marg *= 2.*todir.dot(hitvector); - } - frompoint = result_point + marg * todir; + MT_Scalar h = MT_abs(todir.dot(callback.m_hitNormal)); + if (h <= 0.01) + // the normal is almost orthogonal to the ray direction, cannot compute the other side + break; + marg /= h; + frompoint = callback.m_hitPoint + marg * todir; + // verify that we are not passed the to point + if ((topoint - frompoint).dot(todir) < 0.f) + break; } - - return hit_controller; + return false; } diff --git a/source/gameengine/Ketsji/KX_RayCast.h b/source/gameengine/Ketsji/KX_RayCast.h index 607dabd8afc..c3084c997a1 100644 --- a/source/gameengine/Ketsji/KX_RayCast.h +++ b/source/gameengine/Ketsji/KX_RayCast.h @@ -30,12 +30,14 @@ #ifndef __KX_RAYCAST_H__ #define __KX_RAYCAST_H__ -class MT_Point3; -class MT_Vector3; -class KX_IPhysicsController; -class PHY_IPhysicsEnvironment; +#include "PHY_IPhysicsEnvironment.h" +#include "PHY_IPhysicsController.h" +#include "MT_Point3.h" +#include "MT_Vector3.h" +class RAS_MeshObject; struct KX_ClientObjectInfo; +class KX_IPhysicsController; /** * Defines a function for doing a ray cast. @@ -49,17 +51,27 @@ struct KX_ClientObjectInfo; * * Returns true if a client was accepted, false if nothing found. */ -class KX_RayCast +class KX_RayCast : public PHY_IRayCastFilterCallback { -protected: - KX_RayCast() {}; public: + bool m_hitFound; + MT_Point3 m_hitPoint; + MT_Vector3 m_hitNormal; + const RAS_MeshObject* m_hitMesh; + int m_hitPolygon; + + KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal); virtual ~KX_RayCast() {} + /** + * The physic environment returns the ray casting result through this function + */ + virtual void reportHit(PHY_RayCastResult* result); + /** ray test callback. * either override this in your class, or use a callback wrapper. */ - virtual bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal) const = 0; + virtual bool RayHit(KX_ClientObjectInfo* client) = 0; /** * Callback wrapper. @@ -71,13 +83,11 @@ public: /// Public interface. /// Implement bool RayHit in your class to receive ray callbacks. - static bool RayTest(KX_IPhysicsController* physics_controller, + static bool RayTest( PHY_IPhysicsEnvironment* physics_environment, - const MT_Point3& _frompoint, + const MT_Point3& frompoint, const MT_Point3& topoint, - MT_Point3& result_point, - MT_Vector3& result_normal, - const KX_RayCast& callback); + KX_RayCast& callback); }; @@ -86,18 +96,32 @@ template<class T> class KX_RayCast::Callback : public KX_RayCast T *self; void *data; public: - Callback(T *_self, void *_data = NULL) - : self(_self), + Callback(T *_self, KX_IPhysicsController* controller=NULL, void *_data = NULL, bool faceNormal=false) + : KX_RayCast(controller, faceNormal), + self(_self), data(_data) { } ~Callback() {} - - virtual bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal) const + + virtual bool RayHit(KX_ClientObjectInfo* client) { - return self->RayHit(client, hit_point, hit_normal, data); + return self->RayHit(client, this, data); } + + virtual bool needBroadphaseRayCast(PHY_IPhysicsController* controller) + { + KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(controller->getNewClientInfo()); + + if (!info) + { + MT_assert(info && "Physics controller with no client object info"); + return false; + } + return self->NeedRayCast(info); + } + }; diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp index a416c8c9f89..e24fb773eac 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.cpp +++ b/source/gameengine/Ketsji/KX_RaySensor.cpp @@ -51,6 +51,7 @@ KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr, SCA_IObject* gameobj, const STR_String& propname, bool bFindMaterial, + bool bXRay, double distance, int axis, KX_Scene* ketsjiScene, @@ -58,6 +59,7 @@ KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr, : SCA_ISensor(gameobj,eventmgr, T), m_propertyname(propname), m_bFindMaterial(bFindMaterial), + m_bXRay(bXRay), m_distance(distance), m_scene(ketsjiScene), m_axis(axis) @@ -104,16 +106,10 @@ bool KX_RaySensor::IsPositiveTrigger() return result; } -bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data) +bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { KX_GameObject* hitKXObj = client->m_gameobject; - - if (client->m_type > KX_ClientObjectInfo::ACTOR) - { - // false hit - return false; - } bool bFound = false; if (m_propertyname.Length() == 0) @@ -139,16 +135,43 @@ bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_ { m_rayHit = true; m_hitObject = hitKXObj; - m_hitPosition = hit_point; - m_hitNormal = hit_normal; + m_hitPosition = result->m_hitPoint; + m_hitNormal = result->m_hitNormal; } - - return bFound; - + // no multi-hit search yet + return true; } - +/* this function is used to pre-filter the object before casting the ray on them. + This is useful for "X-Ray" option when we want to see "through" unwanted object. + */ +bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo* client) +{ + if (client->m_type > KX_ClientObjectInfo::ACTOR) + { + // Unknown type of object, skip it. + // Should not occur as the sensor objects are filtered in RayTest() + printf("Invalid client type %d found ray casting\n", client->m_type); + return false; + } + if (m_bXRay && m_propertyname.Length() != 0) + { + if (m_bFindMaterial) + { + // not quite correct: an object may have multiple material + // should check all the material and not only the first one + if (!client->m_auxilary_info || (m_propertyname != ((char*)client->m_auxilary_info))) + return false; + } + else + { + if (client->m_gameobject->GetProperty(m_propertyname) == NULL) + return false; + } + } + return true; +} bool KX_RaySensor::Evaluate(CValue* event) { @@ -215,8 +238,6 @@ bool KX_RaySensor::Evaluate(CValue* event) m_rayDirection = todir; MT_Point3 topoint = frompoint + (m_distance) * todir; - MT_Point3 resultpoint; - MT_Vector3 resultnormal; PHY_IPhysicsEnvironment* pe = m_scene->GetPhysicsEnvironment(); if (!pe) @@ -238,7 +259,8 @@ bool KX_RaySensor::Evaluate(CValue* event) PHY_IPhysicsEnvironment* physics_environment = this->m_scene->GetPhysicsEnvironment(); - result = KX_RayCast::RayTest(spc, physics_environment, frompoint, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_RaySensor>(this)); + KX_RayCast::Callback<KX_RaySensor> callback(this, spc); + KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback); /* now pass this result to some controller */ @@ -265,6 +287,10 @@ bool KX_RaySensor::Evaluate(CValue* event) // notify logicsystem that ray JUST left the Object result = true; } + else + { + result = false; + } } if (reset) @@ -309,14 +335,14 @@ PyParentObject KX_RaySensor::Parents[] = { }; PyMethodDef KX_RaySensor::Methods[] = { - {"getHitObject",(PyCFunction) KX_RaySensor::sPyGetHitObject,METH_VARARGS, GetHitObject_doc}, - {"getHitPosition",(PyCFunction) KX_RaySensor::sPyGetHitPosition,METH_VARARGS, GetHitPosition_doc}, - {"getHitNormal",(PyCFunction) KX_RaySensor::sPyGetHitNormal,METH_VARARGS, GetHitNormal_doc}, - {"getRayDirection",(PyCFunction) KX_RaySensor::sPyGetRayDirection,METH_VARARGS, GetRayDirection_doc}, + {"getHitObject",(PyCFunction) KX_RaySensor::sPyGetHitObject,METH_VARARGS, (PY_METHODCHAR)GetHitObject_doc}, + {"getHitPosition",(PyCFunction) KX_RaySensor::sPyGetHitPosition,METH_VARARGS, (PY_METHODCHAR)GetHitPosition_doc}, + {"getHitNormal",(PyCFunction) KX_RaySensor::sPyGetHitNormal,METH_VARARGS, (PY_METHODCHAR)GetHitNormal_doc}, + {"getRayDirection",(PyCFunction) KX_RaySensor::sPyGetRayDirection,METH_VARARGS, (PY_METHODCHAR)GetRayDirection_doc}, {NULL,NULL} //Sentinel }; -char KX_RaySensor::GetHitObject_doc[] = +const char KX_RaySensor::GetHitObject_doc[] = "getHitObject()\n" "\tReturns the name of the object that was hit by this ray.\n"; PyObject* KX_RaySensor::PyGetHitObject(PyObject* self, @@ -331,7 +357,7 @@ PyObject* KX_RaySensor::PyGetHitObject(PyObject* self, } -char KX_RaySensor::GetHitPosition_doc[] = +const char KX_RaySensor::GetHitPosition_doc[] = "getHitPosition()\n" "\tReturns the position (in worldcoordinates) where the object was hit by this ray.\n"; PyObject* KX_RaySensor::PyGetHitPosition(PyObject* self, @@ -351,7 +377,7 @@ PyObject* KX_RaySensor::PyGetHitPosition(PyObject* self, } -char KX_RaySensor::GetRayDirection_doc[] = +const char KX_RaySensor::GetRayDirection_doc[] = "getRayDirection()\n" "\tReturns the direction from the ray (in worldcoordinates) .\n"; PyObject* KX_RaySensor::PyGetRayDirection(PyObject* self, @@ -371,7 +397,7 @@ PyObject* KX_RaySensor::PyGetRayDirection(PyObject* self, } -char KX_RaySensor::GetHitNormal_doc[] = +const char KX_RaySensor::GetHitNormal_doc[] = "getHitNormal()\n" "\tReturns the normal (in worldcoordinates) of the object at the location where the object was hit by this ray.\n"; PyObject* KX_RaySensor::PyGetHitNormal(PyObject* self, diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h index f4305b053d1..02a755fedc1 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.h +++ b/source/gameengine/Ketsji/KX_RaySensor.h @@ -36,12 +36,14 @@ #include "MT_Point3.h" struct KX_ClientObjectInfo; +class KX_RayCast; class KX_RaySensor : public SCA_ISensor { Py_Header; STR_String m_propertyname; bool m_bFindMaterial; + bool m_bXRay; double m_distance; class KX_Scene* m_scene; bool m_bTriggered; @@ -56,7 +58,8 @@ public: KX_RaySensor(class SCA_EventManager* eventmgr, SCA_IObject* gameobj, const STR_String& propname, - bool fFindMaterial, + bool bFindMaterial, + bool bXRay, double distance, int axis, class KX_Scene* ketsjiScene, @@ -68,7 +71,8 @@ public: virtual bool IsPositiveTrigger(); virtual void Init(); - bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data); + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo* client); KX_PYMETHOD_DOC(KX_RaySensor,GetHitObject); KX_PYMETHOD_DOC(KX_RaySensor,GetHitPosition); diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp index ca0106d64d9..5777f54b799 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp @@ -39,6 +39,8 @@ #include "KX_GameObject.h" #include "KX_IPhysicsController.h" +#include "PyObjectPlus.h" + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -52,14 +54,20 @@ KX_SCA_AddObjectActuator::KX_SCA_AddObjectActuator(SCA_IObject *gameobj, int time, SCA_IScene* scene, const MT_Vector3& linvel, - bool local, + bool linv_local, + const MT_Vector3& angvel, + bool angv_local, PyTypeObject* T) : SCA_IActuator(gameobj, T), m_OriginalObject(original), m_scene(scene), + m_linear_velocity(linvel), - m_localFlag(local) + m_localLinvFlag(linv_local), + + m_angular_velocity(angvel), + m_localAngvFlag(angv_local) { if (m_OriginalObject) m_OriginalObject->RegisterActuator(this); @@ -180,14 +188,16 @@ PyParentObject KX_SCA_AddObjectActuator::Parents[] = { NULL }; PyMethodDef KX_SCA_AddObjectActuator::Methods[] = { - {"setObject", (PyCFunction) KX_SCA_AddObjectActuator::sPySetObject, METH_O, SetObject_doc}, - {"setTime", (PyCFunction) KX_SCA_AddObjectActuator::sPySetTime, METH_VARARGS, SetTime_doc}, - {"getObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetObject, METH_VARARGS, GetObject_doc}, - {"getTime", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetTime, METH_VARARGS, GetTime_doc}, - {"getLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLinearVelocity, METH_VARARGS, GetLinearVelocity_doc}, - {"setLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPySetLinearVelocity, METH_VARARGS, SetLinearVelocity_doc}, - {"getLastCreatedObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLastCreatedObject, METH_VARARGS,"getLastCreatedObject() : get the object handle to the last created object\n"}, - {"instantAddObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyInstantAddObject, METH_VARARGS,"instantAddObject() : immediately add object without delay\n"}, + {"setObject", (PyCFunction) KX_SCA_AddObjectActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc}, + {"setTime", (PyCFunction) KX_SCA_AddObjectActuator::sPySetTime, METH_O, (PY_METHODCHAR)SetTime_doc}, + {"getObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc}, + {"getTime", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetTime, METH_NOARGS, (PY_METHODCHAR)GetTime_doc}, + {"getLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLinearVelocity, METH_NOARGS, (PY_METHODCHAR)GetLinearVelocity_doc}, + {"setLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPySetLinearVelocity, METH_VARARGS, (PY_METHODCHAR)SetLinearVelocity_doc}, + {"getAngularVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetAngularVelocity, METH_NOARGS, (PY_METHODCHAR)GetAngularVelocity_doc}, + {"setAngularVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPySetAngularVelocity, METH_VARARGS, (PY_METHODCHAR)SetAngularVelocity_doc}, + {"getLastCreatedObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLastCreatedObject, METH_NOARGS,"getLastCreatedObject() : get the object handle to the last created object\n"}, + {"instantAddObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyInstantAddObject, METH_NOARGS,"instantAddObject() : immediately add object without delay\n"}, {NULL,NULL} //Sentinel }; @@ -199,7 +209,7 @@ PyObject* KX_SCA_AddObjectActuator::_getattr(const STR_String& attr) } /* 1. setObject */ -char KX_SCA_AddObjectActuator::SetObject_doc[] = +const char KX_SCA_AddObjectActuator::SetObject_doc[] = "setObject(object)\n" "\t- object: KX_GameObject, string or None\n" "\tSets the object that will be added. There has to be an object\n" @@ -224,46 +234,43 @@ PyObject* KX_SCA_AddObjectActuator::PySetObject(PyObject* self, PyObject* value) /* 2. setTime */ -char KX_SCA_AddObjectActuator::SetTime_doc[] = +const char KX_SCA_AddObjectActuator::SetTime_doc[] = "setTime(duration)\n" "\t- duration: integer\n" "\tSets the lifetime of the object that will be added, in frames. \n" "\tIf the duration is negative, it is set to 0.\n"; -PyObject* KX_SCA_AddObjectActuator::PySetTime(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PySetTime(PyObject* self, PyObject* value) { - int deltatime; - - if (!PyArg_ParseTuple(args, "i", &deltatime)) + int deltatime = PyInt_AsLong(value); + if (deltatime==-1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "expected an int"); return NULL; + } m_timeProp = deltatime; if (m_timeProp < 0) m_timeProp = 0; - Py_Return; + Py_RETURN_NONE; } /* 3. getTime */ -char KX_SCA_AddObjectActuator::GetTime_doc[] = +const char KX_SCA_AddObjectActuator::GetTime_doc[] = "GetTime()\n" "\tReturns the lifetime of the object that will be added.\n"; -PyObject* KX_SCA_AddObjectActuator::PyGetTime(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PyGetTime(PyObject* self) { return PyInt_FromLong(m_timeProp); } /* 4. getObject */ -char KX_SCA_AddObjectActuator::GetObject_doc[] = +const char KX_SCA_AddObjectActuator::GetObject_doc[] = "getObject(name_only = 1)\n" "name_only - optional arg, when true will return the KX_GameObject rather then its name\n" "\tReturns the name of the object that will be added.\n"; @@ -285,22 +292,18 @@ PyObject* KX_SCA_AddObjectActuator::PyGetObject(PyObject* self, PyObject* args) /* 5. getLinearVelocity */ -char KX_SCA_AddObjectActuator::GetLinearVelocity_doc[] = +const char KX_SCA_AddObjectActuator::GetLinearVelocity_doc[] = "GetLinearVelocity()\n" "\tReturns the linear velocity that will be assigned to \n" "\tthe created object.\n"; - - -PyObject* KX_SCA_AddObjectActuator::PyGetLinearVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PyGetLinearVelocity(PyObject* self) { PyObject *retVal = PyList_New(3); - PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0])); - PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1])); - PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2])); + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2])); return retVal; } @@ -308,17 +311,15 @@ PyObject* KX_SCA_AddObjectActuator::PyGetLinearVelocity(PyObject* self, /* 6. setLinearVelocity */ -char KX_SCA_AddObjectActuator::SetLinearVelocity_doc[] = +const char KX_SCA_AddObjectActuator::SetLinearVelocity_doc[] = "setLinearVelocity(vx, vy, vz)\n" "\t- vx: float\n" "\t- vy: float\n" "\t- vz: float\n" +"\t- local: bool\n" "\tAssign this velocity to the created object. \n"; - -PyObject* KX_SCA_AddObjectActuator::PySetLinearVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PySetLinearVelocity(PyObject* self, PyObject* args) { float vecArg[3]; @@ -326,7 +327,46 @@ PyObject* KX_SCA_AddObjectActuator::PySetLinearVelocity(PyObject* self, return NULL; m_linear_velocity.setValue(vecArg); - Py_Return; + Py_RETURN_NONE; +} + +/* 7. getAngularVelocity */ +const char KX_SCA_AddObjectActuator::GetAngularVelocity_doc[] = +"GetAngularVelocity()\n" +"\tReturns the angular velocity that will be assigned to \n" +"\tthe created object.\n"; + +PyObject* KX_SCA_AddObjectActuator::PyGetAngularVelocity(PyObject* self) +{ + PyObject *retVal = PyList_New(3); + + PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_angular_velocity[0])); + PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_angular_velocity[1])); + PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_angular_velocity[2])); + + return retVal; +} + + + +/* 8. setAngularVelocity */ +const char KX_SCA_AddObjectActuator::SetAngularVelocity_doc[] = +"setAngularVelocity(vx, vy, vz)\n" +"\t- vx: float\n" +"\t- vy: float\n" +"\t- vz: float\n" +"\t- local: bool\n" +"\tAssign this angular velocity to the created object. \n"; + +PyObject* KX_SCA_AddObjectActuator::PySetAngularVelocity(PyObject* self, PyObject* args) +{ + + float vecArg[3]; + if (!PyArg_ParseTuple(args, "fff", &vecArg[0], &vecArg[1], &vecArg[2])) + return NULL; + + m_angular_velocity.setValue(vecArg); + Py_RETURN_NONE; } void KX_SCA_AddObjectActuator::InstantAddObject() @@ -337,8 +377,9 @@ void KX_SCA_AddObjectActuator::InstantAddObject() // Now it needs to be added to the current scene. SCA_IObject* replica = m_scene->AddReplicaObject(m_OriginalObject,GetParent(),m_timeProp ); KX_GameObject * game_obj = static_cast<KX_GameObject *>(replica); - game_obj->setLinearVelocity(m_linear_velocity,m_localFlag); - game_obj->ResolveCombinedVelocities(m_linear_velocity, MT_Vector3(0., 0., 0.), m_localFlag, false); + game_obj->setLinearVelocity(m_linear_velocity,m_localLinvFlag); + game_obj->setAngularVelocity(m_angular_velocity,m_localAngvFlag); + game_obj->ResolveCombinedVelocities(m_linear_velocity, m_angular_velocity, m_localLinvFlag, m_localAngvFlag); // keep a copy of the last object, to allow python scripters to change it if (m_lastCreatedObject) @@ -355,33 +396,32 @@ void KX_SCA_AddObjectActuator::InstantAddObject() } } -PyObject* KX_SCA_AddObjectActuator::PyInstantAddObject(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PyInstantAddObject(PyObject* self) { InstantAddObject(); - Py_Return; + Py_RETURN_NONE; } /* 7. GetLastCreatedObject */ -char KX_SCA_AddObjectActuator::GetLastCreatedObject_doc[] = +const char KX_SCA_AddObjectActuator::GetLastCreatedObject_doc[] = "getLastCreatedObject()\n" "\tReturn the last created object. \n"; -PyObject* KX_SCA_AddObjectActuator::PyGetLastCreatedObject(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PyGetLastCreatedObject(PyObject* self) { SCA_IObject* result = this->GetLastCreatedObject(); - if (result) + + // if result->GetSGNode() is NULL + // it means the object has ended, The BGE python api crashes in many places if the object is returned. + if (result && (static_cast<KX_GameObject *>(result))->GetSGNode()) { result->AddRef(); return result; } // don't return NULL to python anymore, it gives trouble in the scripts - Py_Return; + Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h index e7fdb2fbfbc..278d4180284 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h @@ -60,9 +60,13 @@ class KX_SCA_AddObjectActuator : public SCA_IActuator /// Linear velocity upon creation of the object. MT_Vector3 m_linear_velocity; + + /// Angular velocity upon creation of the object. + MT_Vector3 m_angular_velocity; /// Apply the velocity locally - bool m_localFlag; + bool m_localLinvFlag; + bool m_localAngvFlag; SCA_IObject* m_lastCreatedObject; @@ -79,7 +83,9 @@ public: int time, SCA_IScene* scene, const MT_Vector3& linvel, - bool local, + bool linv_local, + const MT_Vector3& angvel, + bool angv_local, PyTypeObject* T=&Type ); @@ -115,19 +121,23 @@ public: /* 1. setObject */ KX_PYMETHOD_DOC_O(KX_SCA_AddObjectActuator,SetObject); /* 2. setTime */ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,SetTime); + KX_PYMETHOD_DOC_O(KX_SCA_AddObjectActuator,SetTime); /* 3. getTime */ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetTime); + KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetTime); /* 4. getObject */ KX_PYMETHOD_DOC_VARARGS(KX_SCA_AddObjectActuator,GetObject); /* 5. getLinearVelocity */ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetLinearVelocity); + KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetLinearVelocity); /* 6. setLinearVelocity */ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,SetLinearVelocity); - /* 7. getLastCreatedObject */ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetLastCreatedObject); - /* 8. instantAddObject*/ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,InstantAddObject); + KX_PYMETHOD_DOC_VARARGS(KX_SCA_AddObjectActuator,SetLinearVelocity); + /* 7. getAngularVelocity */ + KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetAngularVelocity); + /* 8. setAngularVelocity */ + KX_PYMETHOD_DOC_VARARGS(KX_SCA_AddObjectActuator,SetAngularVelocity); + /* 9. getLastCreatedObject */ + KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetLastCreatedObject); + /* 10. instantAddObject*/ + KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,InstantAddObject); }; /* end of class KX_SCA_AddObjectActuator : public KX_EditObjectActuator */ diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp index 630df2d21d9..261d9ec8f0c 100644 --- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp @@ -37,6 +37,8 @@ #include "KX_SCA_ReplaceMeshActuator.h" +#include "PyObjectPlus.h" + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -80,7 +82,7 @@ PyParentObject KX_SCA_ReplaceMeshActuator::Parents[] = { PyMethodDef KX_SCA_ReplaceMeshActuator::Methods[] = { - {"setMesh", (PyCFunction) KX_SCA_ReplaceMeshActuator::sPySetMesh, METH_VARARGS, SetMesh_doc}, + {"setMesh", (PyCFunction) KX_SCA_ReplaceMeshActuator::sPySetMesh, METH_O, (PY_METHODCHAR)SetMesh_doc}, KX_PYMETHODTABLE(KX_SCA_ReplaceMeshActuator, instantReplaceMesh), KX_PYMETHODTABLE(KX_SCA_ReplaceMeshActuator, getMesh), @@ -97,30 +99,31 @@ PyObject* KX_SCA_ReplaceMeshActuator::_getattr(const STR_String& attr) /* 1. setMesh */ -char KX_SCA_ReplaceMeshActuator::SetMesh_doc[] = +const char KX_SCA_ReplaceMeshActuator::SetMesh_doc[] = "setMesh(name)\n" - "\t- name: string\n" + "\t- name: string or None\n" "\tSet the mesh that will be substituted for the current one.\n"; -PyObject* KX_SCA_ReplaceMeshActuator::PySetMesh(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_ReplaceMeshActuator::PySetMesh(PyObject* self, PyObject* value) { - char* meshname; - - if (!PyArg_ParseTuple(args, "s", &meshname)) - { - return NULL; - } - - void* mesh = SCA_ILogicBrick::m_sCurrentLogicManager->GetMeshByName(STR_String(meshname)); - - if (mesh) { + if (value == Py_None) { + m_mesh = NULL; + } else { + char* meshname = PyString_AsString(value); + if (!meshname) { + PyErr_SetString(PyExc_ValueError, "Expected the name of a mesh or None"); + return NULL; + } + void* mesh = SCA_ILogicBrick::m_sCurrentLogicManager->GetMeshByName(STR_String(meshname)); + + if (mesh==NULL) { + PyErr_SetString(PyExc_ValueError, "The mesh name given does not exist"); + return NULL; + } m_mesh= (class RAS_MeshObject*)mesh; - Py_Return; } - return NULL; + Py_RETURN_NONE; } KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, getMesh, @@ -129,7 +132,7 @@ KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, getMesh, ) { if (!m_mesh) - Py_Return; + Py_RETURN_NONE; return PyString_FromString(const_cast<char *>(m_mesh->GetName().ReadPtr())); } @@ -139,7 +142,7 @@ KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, instantReplaceMesh, "instantReplaceMesh() : immediately replace mesh without delay\n") { InstantReplaceMesh(); - Py_Return; + Py_RETURN_NONE; } /* ------------------------------------------------------------------------- */ diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h index 5ba0a099b14..1da154cc222 100644 --- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h @@ -76,7 +76,7 @@ class KX_SCA_ReplaceMeshActuator : public SCA_IActuator void InstantReplaceMesh(); /* 1. setMesh */ - KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,SetMesh); + KX_PYMETHOD_DOC_O(KX_SCA_ReplaceMeshActuator,SetMesh); KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,getMesh); KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,instantReplaceMesh); diff --git a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp index f085ff435dc..d651373869a 100644 --- a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp +++ b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp @@ -78,7 +78,7 @@ UpdateChildCoordinates( if (parent) { - const BL_ArmatureObject *armature = (const BL_ArmatureObject*)(parent->GetSGClientObject()); + BL_ArmatureObject *armature = (BL_ArmatureObject*)(parent->GetSGClientObject()); if (armature) { MT_Matrix4x4 parent_matrix; diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 2828663c63d..f5d6d7e8e0a 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -68,6 +68,7 @@ #include "SG_IObject.h" #include "SG_Tree.h" #include "DNA_group_types.h" +#include "DNA_scene_types.h" #include "BKE_anim.h" #include "KX_SG_NodeRelationships.h" @@ -116,7 +117,8 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, class SCA_IInputDevice* mousedevice, class NG_NetworkDeviceInterface *ndi, class SND_IAudioDevice* adi, - const STR_String& sceneName): + const STR_String& sceneName, + Scene *scene): PyObjectPlus(&KX_Scene::Type), m_keyboardmgr(NULL), m_mousemgr(NULL), @@ -126,7 +128,8 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_adi(adi), m_networkDeviceInterface(ndi), m_active_camera(NULL), - m_ueberExecutionPriority(0) + m_ueberExecutionPriority(0), + m_blenderScene(scene) { m_suspendedtime = 0.0; m_suspendeddelta = 0.0; @@ -156,7 +159,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, KX_NetworkEventManager* netmgr = new KX_NetworkEventManager(m_logicmgr, ndi); - SCA_JoystickManager *joymgr = new SCA_JoystickManager(m_logicmgr); + m_logicmgr->RegisterEventManager(alwaysmgr); m_logicmgr->RegisterEventManager(propmgr); @@ -167,7 +170,15 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_logicmgr->RegisterEventManager(rndmgr); m_logicmgr->RegisterEventManager(raymgr); m_logicmgr->RegisterEventManager(netmgr); - m_logicmgr->RegisterEventManager(joymgr); + + + SYS_SystemHandle hSystem = SYS_GetSystem(); + bool nojoystick= SYS_GetCommandLineInt(hSystem,"nojoystick",0); + if (!nojoystick) + { + SCA_JoystickManager *joymgr = new SCA_JoystickManager(m_logicmgr); + m_logicmgr->RegisterEventManager(joymgr); + } m_soundScene = new SND_Scene(adi); MT_assert (m_networkDeviceInterface != NULL); @@ -234,40 +245,9 @@ KX_Scene::~KX_Scene() { delete m_bucketmanager; } -#ifdef USE_BULLET - // This is a fix for memory leaks in bullet: the collision shapes is not destroyed - // when the physical controllers are destroyed. The reason is that shapes are shared - // between replicas of an object. There is no reference count in Bullet so the - // only workaround that does not involve changes in Bullet is to save in this array - // the list of shapes that are created when the scene is created (see KX_ConvertPhysicsObjects.cpp) - class btCollisionShape* shape; - class btTriangleMeshShape* meshShape; - vector<class btCollisionShape*>::iterator it = m_shapes.begin(); - while (it != m_shapes.end()) { - shape = *it; - if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE) - { - meshShape = static_cast<btTriangleMeshShape*>(shape); - // shapes based on meshes use an interface that contains the vertices. - // Again the idea is to be able to share the interface between shapes but - // this is not used in Blender: each base object will have its own interface - btStridingMeshInterface* meshInterface = meshShape->getMeshInterface(); - if (meshInterface) - delete meshInterface; - } - delete shape; - it++; - } -#endif //Py_DECREF(m_attrlist); } -void KX_Scene::AddShape(class btCollisionShape*shape) -{ - m_shapes.push_back(shape); -} - - void KX_Scene::SetProjectionMatrix(MT_CmMatrix4x4& pmat) { m_projectionmat = pmat; @@ -484,7 +464,7 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal // this is the list of object that are send to the graphics pipeline m_objectlist->Add(newobj->AddRef()); - newobj->Bucketize(); + newobj->AddMeshUser(); // logic cannot be replicated, until the whole hierarchy is replicated. m_logicHierarchicalGameObjects.push_back(newobj); @@ -654,6 +634,7 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) if (blgroupobj == blenderobj) // this check is also in group_duplilist() continue; + gameobj = (KX_GameObject*)m_logicmgr->FindGameObjByBlendObj(blenderobj); if (gameobj == NULL) { @@ -661,6 +642,9 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) // Should not happen as dupli group are created automatically continue; } + + gameobj->SetBlenderGroupObject(blgroupobj); + if ((blenderobj->lay & group->layer)==0) { // object is not visible in the 3D view, will not be instantiated @@ -718,17 +702,6 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) newscale*(groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldPosition()); replica->NodeSetLocalPosition(newpos); - if (replica->GetPhysicsController()) - { - // not required, already done in NodeSetLocalOrientation.. - //replica->GetPhysicsController()->setPosition(newpos); - //replica->GetPhysicsController()->setOrientation(newori.getRotation()); - // Scaling has been set relatively hereabove, this does not - // set the scaling of the controller. I don't know why it's just the - // relative scale and not the full scale that has to be put here... - replica->GetPhysicsController()->setScaling(newscale); - } - replica->GetSGNode()->UpdateWorldData(0); replica->GetSGNode()->SetBBox(gameobj->GetSGNode()->BBox()); replica->GetSGNode()->SetRadius(gameobj->GetSGNode()->Radius()); @@ -853,18 +826,6 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, // set the replica's relative scale with the rootnode's scale replica->NodeSetRelativeScale(newscale); - if (replica->GetPhysicsController()) - { - // not needed, already done in NodeSetLocalPosition() - //replica->GetPhysicsController()->setPosition(newpos); - //replica->GetPhysicsController()->setOrientation(newori.getRotation()); - replica->GetPhysicsController()->setScaling(newscale); - } - - // here we want to set the relative scale: the rootnode's scale will override all other - // scalings, so lets better prepare for it - - replica->GetSGNode()->UpdateWorldData(0); replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox()); replica->GetSGNode()->SetRadius(originalobj->GetSGNode()->Radius()); @@ -975,6 +936,8 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) newobj->RemoveMeshes(); ret = 1; + if (m_lightlist->RemoveValue(newobj)) // TODO - use newobj->IsLight() test when its merged in from apricot. - Campbell + ret = newobj->Release(); if (m_objectlist->RemoveValue(newobj)) ret = newobj->Release(); if (m_tempObjectList->RemoveValue(newobj)) @@ -1022,13 +985,13 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) { BL_DeformableGameObject* newobj = static_cast<BL_DeformableGameObject*>( gameobj ); - if (newobj->m_pDeformer) + if (newobj->GetDeformer()) { - delete newobj->m_pDeformer; - newobj->m_pDeformer = NULL; + delete newobj->GetDeformer(); + newobj->SetDeformer(NULL); } - if (mesh->m_class == 1) + if (mesh->IsDeformed()) { // we must create a new deformer but which one? KX_GameObject* parentobj = newobj->GetParent(); @@ -1075,7 +1038,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) NULL ); } - newobj->m_pDeformer = shapeDeformer; + newobj->SetDeformer( shapeDeformer); } else if (bHasArmature) { @@ -1087,14 +1050,14 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) static_cast<BL_ArmatureObject*>( parentobj ) ); releaseParent= false; - newobj->m_pDeformer = skinDeformer; + newobj->SetDeformer(skinDeformer); } else if (bHasDvert) { BL_MeshDeformer* meshdeformer = new BL_MeshDeformer( newobj, oldblendobj, static_cast<BL_SkinMeshObject*>(mesh) ); - newobj->m_pDeformer = meshdeformer; + newobj->SetDeformer(meshdeformer); } // release parent reference if its not being used @@ -1102,7 +1065,8 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) parentobj->Release(); } } - gameobj->Bucketize(); + + gameobj->AddMeshUser(); } @@ -1254,7 +1218,9 @@ void KX_Scene::MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool vi for (int m=0;m<nummeshes;m++) (gameobj->GetMesh(m))->SchedulePolygons(rasty->GetDrawingMode()); } - gameobj->MarkVisible(visible); + + gameobj->SetCulled(!visible); + gameobj->UpdateBuckets(false); } } if (node->Left()) @@ -1271,7 +1237,8 @@ void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Cam // Shadow lamp layers if(layer && !(gameobj->GetLayer() & layer)) { - gameobj->MarkVisible(false); + gameobj->SetCulled(true); + gameobj->UpdateBuckets(false); return; } @@ -1317,9 +1284,11 @@ void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Cam } // Visibility/ non-visibility are marked // elsewhere now. - gameobj->MarkVisible(); + gameobj->SetCulled(false); + gameobj->UpdateBuckets(false); } else { - gameobj->MarkVisible(false); + gameobj->SetCulled(true); + gameobj->UpdateBuckets(false); } } diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index 80a2abe287a..5f7e1167e27 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -54,6 +54,7 @@ */ struct SM_MaterialProps; struct SM_ShapeProps; +struct Scene; class GEN_HashedPtr; class CListValue; @@ -122,11 +123,6 @@ protected: */ list<class KX_Camera*> m_cameras; /** - * The set of bullet shapes that must be deleted at the end of the scene - * to avoid memory leak (not deleted by bullet because shape are shared between replicas) - */ - vector<class btCollisionShape*> m_shapes; - /** * Various SCA managers used by the scene */ SCA_LogicManager* m_logicmgr; @@ -282,12 +278,15 @@ protected: */ PyObject* m_attrlist; + struct Scene* m_blenderScene; + public: KX_Scene(class SCA_IInputDevice* keyboarddevice, class SCA_IInputDevice* mousedevice, class NG_NetworkDeviceInterface* ndi, class SND_IAudioDevice* adi, - const STR_String& scenename ); + const STR_String& scenename, + struct Scene* scene); virtual ~KX_Scene(); @@ -322,7 +321,6 @@ public: int NewRemoveObject(CValue* gameobj); void ReplaceMesh(CValue* gameobj, void* meshobj); - void AddShape(class btCollisionShape* shape); /** * @section Logic stuff * Initiate an update of the logic system. @@ -588,6 +586,10 @@ public: * was running and not suspended) and the "curtime" */ double getSuspendedDelta(); + /** + * Returns the Blender scene this was made from + */ + struct Scene *GetBlenderScene() { return m_blenderScene; } }; typedef std::vector<KX_Scene*> KX_SceneList; diff --git a/source/gameengine/Ketsji/KX_SceneActuator.cpp b/source/gameengine/Ketsji/KX_SceneActuator.cpp index d6164dc812a..35484699b17 100644 --- a/source/gameengine/Ketsji/KX_SceneActuator.cpp +++ b/source/gameengine/Ketsji/KX_SceneActuator.cpp @@ -259,12 +259,12 @@ PyParentObject KX_SceneActuator::Parents[] = PyMethodDef KX_SceneActuator::Methods[] = { - {"setUseRestart", (PyCFunction) KX_SceneActuator::sPySetUseRestart, METH_VARARGS, SetUseRestart_doc}, - {"setScene", (PyCFunction) KX_SceneActuator::sPySetScene, METH_VARARGS, SetScene_doc}, - {"setCamera", (PyCFunction) KX_SceneActuator::sPySetCamera, METH_VARARGS, SetCamera_doc}, - {"getUseRestart", (PyCFunction) KX_SceneActuator::sPyGetUseRestart, METH_VARARGS, GetUseRestart_doc}, - {"getScene", (PyCFunction) KX_SceneActuator::sPyGetScene, METH_VARARGS, GetScene_doc}, - {"getCamera", (PyCFunction) KX_SceneActuator::sPyGetCamera, METH_VARARGS, GetCamera_doc}, + {"setUseRestart", (PyCFunction) KX_SceneActuator::sPySetUseRestart, METH_VARARGS, (PY_METHODCHAR)SetUseRestart_doc}, + {"setScene", (PyCFunction) KX_SceneActuator::sPySetScene, METH_VARARGS, (PY_METHODCHAR)SetScene_doc}, + {"setCamera", (PyCFunction) KX_SceneActuator::sPySetCamera, METH_VARARGS, (PY_METHODCHAR)SetCamera_doc}, + {"getUseRestart", (PyCFunction) KX_SceneActuator::sPyGetUseRestart, METH_VARARGS, (PY_METHODCHAR)GetUseRestart_doc}, + {"getScene", (PyCFunction) KX_SceneActuator::sPyGetScene, METH_VARARGS, (PY_METHODCHAR)GetScene_doc}, + {"getCamera", (PyCFunction) KX_SceneActuator::sPyGetCamera, METH_VARARGS, (PY_METHODCHAR)GetCamera_doc}, {NULL,NULL} //Sentinel }; @@ -278,7 +278,7 @@ PyObject* KX_SceneActuator::_getattr(const STR_String& attr) /* 2. setUseRestart--------------------------------------------------------- */ -char KX_SceneActuator::SetUseRestart_doc[] = +const char KX_SceneActuator::SetUseRestart_doc[] = "setUseRestart(flag)\n" "\t- flag: 0 or 1.\n" "\tSet flag to 1 to restart the scene.\n" ; @@ -301,7 +301,7 @@ PyObject* KX_SceneActuator::PySetUseRestart(PyObject* self, /* 3. getUseRestart: */ -char KX_SceneActuator::GetUseRestart_doc[] = +const char KX_SceneActuator::GetUseRestart_doc[] = "getUseRestart()\n" "\tReturn whether the scene will be restarted.\n" ; PyObject* KX_SceneActuator::PyGetUseRestart(PyObject* self, @@ -314,7 +314,7 @@ PyObject* KX_SceneActuator::PyGetUseRestart(PyObject* self, /* 4. set scene------------------------------------------------------------- */ -char KX_SceneActuator::SetScene_doc[] = +const char KX_SceneActuator::SetScene_doc[] = "setScene(scene)\n" "\t- scene: string\n" "\tSet the name of scene the actuator will switch to.\n" ; @@ -339,7 +339,7 @@ PyObject* KX_SceneActuator::PySetScene(PyObject* self, /* 5. getScene: */ -char KX_SceneActuator::GetScene_doc[] = +const char KX_SceneActuator::GetScene_doc[] = "getScene()\n" "\tReturn the name of the scene the actuator wants to switch to.\n" ; PyObject* KX_SceneActuator::PyGetScene(PyObject* self, @@ -352,7 +352,7 @@ PyObject* KX_SceneActuator::PyGetScene(PyObject* self, /* 6. set camera------------------------------------------------------------ */ -char KX_SceneActuator::SetCamera_doc[] = +const char KX_SceneActuator::SetCamera_doc[] = "setCamera(camera)\n" "\t- camera: string\n" "\tSet the camera to switch to.\n" ; @@ -394,7 +394,7 @@ PyObject* KX_SceneActuator::PySetCamera(PyObject* self, /* 7. getCamera: */ -char KX_SceneActuator::GetCamera_doc[] = +const char KX_SceneActuator::GetCamera_doc[] = "getCamera()\n" "\tReturn the name of the camera to switch to.\n" ; PyObject* KX_SceneActuator::PyGetCamera(PyObject* self, diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index 34a3baec093..f75a1ee5c62 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -69,11 +69,11 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, KX_SoundActuator::~KX_SoundActuator() { - //m_soundScene->RemoveObject(this->m_soundObject); - //(this->m_soundObject)->DeleteWhenFinished(); - m_soundScene->RemoveActiveObject(m_soundObject); -// m_soundScene->DeleteObjectWhenFinished(m_soundObject); - m_soundScene->DeleteObject(m_soundObject); + if (m_soundObject) + { + m_soundScene->RemoveActiveObject(m_soundObject); + m_soundScene->DeleteObject(m_soundObject); + } } @@ -82,9 +82,12 @@ CValue* KX_SoundActuator::GetReplica() { KX_SoundActuator* replica = new KX_SoundActuator(*this); replica->ProcessReplica(); - SND_SoundObject* soundobj = new SND_SoundObject(*m_soundObject); - replica->setSoundObject(soundobj); - m_soundScene->AddObject(soundobj); + if (m_soundObject) + { + SND_SoundObject* soundobj = new SND_SoundObject(*m_soundObject); + replica->setSoundObject(soundobj); + m_soundScene->AddObject(soundobj); + } // this will copy properties and so on... CValue::AddDataToReplica(replica); @@ -104,6 +107,9 @@ bool KX_SoundActuator::Update(double curtime, bool frame) RemoveAllEvents(); + if (!m_soundObject) + return false; + if (m_pino) { bNegativeEvent = true; @@ -287,6 +293,10 @@ PyObject* KX_SoundActuator::PySetFilename(PyObject* self, PyObject* args, PyObje PyObject* KX_SoundActuator::PyGetFilename(PyObject* self, PyObject* args, PyObject* kwds) { + if (!m_soundObject) + { + return PyString_FromString(""); + } STR_String objectname = m_soundObject->GetObjectName(); char* name = objectname.Ptr(); @@ -301,7 +311,8 @@ PyObject* KX_SoundActuator::PyGetFilename(PyObject* self, PyObject* args, PyObje PyObject* KX_SoundActuator::PyStartSound(PyObject* self, PyObject* args, PyObject* kwds) { - m_soundObject->StartSound(); + if (m_soundObject) + m_soundObject->StartSound(); Py_Return; } @@ -309,7 +320,8 @@ PyObject* KX_SoundActuator::PyStartSound(PyObject* self, PyObject* args, PyObjec PyObject* KX_SoundActuator::PyPauseSound(PyObject* self, PyObject* args, PyObject* kwds) { - m_soundObject->PauseSound(); + if (m_soundObject) + m_soundObject->PauseSound(); Py_Return; } @@ -317,7 +329,8 @@ PyObject* KX_SoundActuator::PyPauseSound(PyObject* self, PyObject* args, PyObjec PyObject* KX_SoundActuator::PyStopSound(PyObject* self, PyObject* args, PyObject* kwds) { - m_soundObject->StopSound(); + if (m_soundObject) + m_soundObject->StopSound(); Py_Return; } @@ -329,7 +342,8 @@ PyObject* KX_SoundActuator::PySetGain(PyObject* self, PyObject* args, PyObject* if (!PyArg_ParseTuple(args, "f", &gain)) return NULL; - m_soundObject->SetGain(gain); + if (m_soundObject) + m_soundObject->SetGain(gain); Py_Return; } @@ -338,7 +352,7 @@ PyObject* KX_SoundActuator::PySetGain(PyObject* self, PyObject* args, PyObject* PyObject* KX_SoundActuator::PyGetGain(PyObject* self, PyObject* args, PyObject* kwds) { - float gain = m_soundObject->GetGain(); + float gain = (m_soundObject) ? m_soundObject->GetGain() : 1.0f; PyObject* result = PyFloat_FromDouble(gain); return result; @@ -352,7 +366,8 @@ PyObject* KX_SoundActuator::PySetPitch(PyObject* self, PyObject* args, PyObject* if (!PyArg_ParseTuple(args, "f", &pitch)) return NULL; - m_soundObject->SetPitch(pitch); + if (m_soundObject) + m_soundObject->SetPitch(pitch); Py_Return; } @@ -361,7 +376,7 @@ PyObject* KX_SoundActuator::PySetPitch(PyObject* self, PyObject* args, PyObject* PyObject* KX_SoundActuator::PyGetPitch(PyObject* self, PyObject* args, PyObject* kwds) { - float pitch = m_soundObject->GetPitch(); + float pitch = (m_soundObject) ? m_soundObject->GetPitch() : 1.0; PyObject* result = PyFloat_FromDouble(pitch); return result; @@ -375,7 +390,8 @@ PyObject* KX_SoundActuator::PySetRollOffFactor(PyObject* self, PyObject* args, P if (!PyArg_ParseTuple(args, "f", &rollofffactor)) return NULL; - m_soundObject->SetRollOffFactor(rollofffactor); + if (m_soundObject) + m_soundObject->SetRollOffFactor(rollofffactor); Py_Return; } @@ -384,7 +400,7 @@ PyObject* KX_SoundActuator::PySetRollOffFactor(PyObject* self, PyObject* args, P PyObject* KX_SoundActuator::PyGetRollOffFactor(PyObject* self, PyObject* args, PyObject* kwds) { - float rollofffactor = m_soundObject->GetRollOffFactor(); + float rollofffactor = (m_soundObject) ? m_soundObject->GetRollOffFactor() : 1.0; PyObject* result = PyFloat_FromDouble(rollofffactor); return result; @@ -398,7 +414,8 @@ PyObject* KX_SoundActuator::PySetLooping(PyObject* self, PyObject* args, PyObjec if (!PyArg_ParseTuple(args, "i", &looping)) return NULL; - m_soundObject->SetLoopMode(looping); + if (m_soundObject) + m_soundObject->SetLoopMode(looping); Py_Return; } @@ -407,7 +424,7 @@ PyObject* KX_SoundActuator::PySetLooping(PyObject* self, PyObject* args, PyObjec PyObject* KX_SoundActuator::PyGetLooping(PyObject* self, PyObject* args, PyObject* kwds) { - int looping = m_soundObject->GetLoopMode(); + int looping = (m_soundObject) ? m_soundObject->GetLoopMode() : SND_LOOP_OFF; PyObject* result = PyInt_FromLong(looping); return result; @@ -425,7 +442,8 @@ PyObject* KX_SoundActuator::PySetPosition(PyObject* self, PyObject* args, PyObje if (!PyArg_ParseTuple(args, "fff", &pos[0], &pos[1], &pos[2])) return NULL; - m_soundObject->SetPosition(pos); + if (m_soundObject) + m_soundObject->SetPosition(pos); Py_Return; } @@ -442,7 +460,8 @@ PyObject* KX_SoundActuator::PySetVelocity(PyObject* self, PyObject* args, PyObje if (!PyArg_ParseTuple(args, "fff", &vel[0], &vel[1], &vel[2])) return NULL; - m_soundObject->SetVelocity(vel); + if (m_soundObject) + m_soundObject->SetVelocity(vel); Py_Return; } @@ -465,7 +484,8 @@ PyObject* KX_SoundActuator::PySetOrientation(PyObject* self, PyObject* args, PyO if (!PyArg_ParseTuple(args, "fffffffff", &ori[0][0], &ori[0][1], &ori[0][2], &ori[1][0], &ori[1][1], &ori[1][2], &ori[2][0], &ori[2][1], &ori[2][2])) return NULL; - m_soundObject->SetOrientation(ori); + if (m_soundObject) + m_soundObject->SetOrientation(ori); Py_Return; } diff --git a/source/gameengine/Ketsji/KX_StateActuator.cpp b/source/gameengine/Ketsji/KX_StateActuator.cpp index 95a79f0c480..e360c4bac1f 100644 --- a/source/gameengine/Ketsji/KX_StateActuator.cpp +++ b/source/gameengine/Ketsji/KX_StateActuator.cpp @@ -140,9 +140,9 @@ KX_StateActuator::Parents[] = { PyMethodDef KX_StateActuator::Methods[] = { {"setOperation", (PyCFunction) KX_StateActuator::sPySetOperation, - METH_VARARGS, SetOperation_doc}, + METH_VARARGS, (PY_METHODCHAR)SetOperation_doc}, {"setMask", (PyCFunction) KX_StateActuator::sPySetMask, - METH_VARARGS, SetMask_doc}, + METH_VARARGS, (PY_METHODCHAR)SetMask_doc}, {NULL,NULL} //Sentinel }; @@ -157,7 +157,7 @@ KX_StateActuator::_getattr( /* set operation ---------------------------------------------------------- */ -char +const char KX_StateActuator::SetOperation_doc[] = "setOperation(op)\n" "\t - op : bit operation (0=Copy, 1=Set, 2=Clear, 3=Negate)" @@ -180,7 +180,7 @@ KX_StateActuator::PySetOperation(PyObject* self, } /* set mask ---------------------------------------------------------- */ -char +const char KX_StateActuator::SetMask_doc[] = "setMask(mask)\n" "\t - mask : bits that will be modified" diff --git a/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp b/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp index 4032a795ce3..c842ca1ee14 100644 --- a/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp +++ b/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp @@ -205,6 +205,11 @@ MT_Scalar KX_SumoPhysicsController::GetMass() return SumoPhysicsController::getMass(); } +MT_Scalar KX_SumoPhysicsController::GetRadius() +{ + return SumoPhysicsController::GetRadius(); +} + MT_Vector3 KX_SumoPhysicsController::getReactionForce() { float force[3]; diff --git a/source/gameengine/Ketsji/KX_SumoPhysicsController.h b/source/gameengine/Ketsji/KX_SumoPhysicsController.h index 1dd930bf3d9..abe48d99043 100644 --- a/source/gameengine/Ketsji/KX_SumoPhysicsController.h +++ b/source/gameengine/Ketsji/KX_SumoPhysicsController.h @@ -84,6 +84,7 @@ public: virtual void setPosition(const MT_Point3& pos); virtual void setScaling(const MT_Vector3& scaling); virtual MT_Scalar GetMass(); + virtual MT_Scalar GetRadius(); virtual MT_Vector3 getReactionForce(); virtual void setRigidBody(bool rigid); diff --git a/source/gameengine/Ketsji/KX_TouchSensor.cpp b/source/gameengine/Ketsji/KX_TouchSensor.cpp index 60e1d87d318..41757a23f7a 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.cpp +++ b/source/gameengine/Ketsji/KX_TouchSensor.cpp @@ -240,13 +240,13 @@ PyParentObject KX_TouchSensor::Parents[] = { PyMethodDef KX_TouchSensor::Methods[] = { {"setProperty", - (PyCFunction) KX_TouchSensor::sPySetProperty, METH_VARARGS, SetProperty_doc}, + (PyCFunction) KX_TouchSensor::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, {"getProperty", - (PyCFunction) KX_TouchSensor::sPyGetProperty, METH_VARARGS, GetProperty_doc}, + (PyCFunction) KX_TouchSensor::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, {"getHitObject", - (PyCFunction) KX_TouchSensor::sPyGetHitObject, METH_VARARGS, GetHitObject_doc}, + (PyCFunction) KX_TouchSensor::sPyGetHitObject, METH_VARARGS, (PY_METHODCHAR)GetHitObject_doc}, {"getHitObjectList", - (PyCFunction) KX_TouchSensor::sPyGetHitObjectList, METH_VARARGS, GetHitObjectList_doc}, + (PyCFunction) KX_TouchSensor::sPyGetHitObjectList, METH_VARARGS, (PY_METHODCHAR)GetHitObjectList_doc}, {NULL,NULL} //Sentinel }; @@ -257,7 +257,7 @@ PyObject* KX_TouchSensor::_getattr(const STR_String& attr) { /* Python API */ /* 1. setProperty */ -char KX_TouchSensor::SetProperty_doc[] = +const char KX_TouchSensor::SetProperty_doc[] = "setProperty(name)\n" "\t- name: string\n" "\tSet the property or material to collide with. Use\n" @@ -283,7 +283,7 @@ PyObject* KX_TouchSensor::PySetProperty(PyObject* self, Py_Return; } /* 2. getProperty */ -char KX_TouchSensor::GetProperty_doc[] = +const char KX_TouchSensor::GetProperty_doc[] = "getProperty(name)\n" "\tReturns the property or material to collide with. Use\n" "\tgetTouchMaterial() to find out whether this sensor\n" @@ -294,7 +294,7 @@ PyObject* KX_TouchSensor::PyGetProperty(PyObject* self, return PyString_FromString(m_touchedpropname); } -char KX_TouchSensor::GetHitObject_doc[] = +const char KX_TouchSensor::GetHitObject_doc[] = "getHitObject()\n" ; PyObject* KX_TouchSensor::PyGetHitObject(PyObject* self, @@ -310,7 +310,7 @@ PyObject* KX_TouchSensor::PyGetHitObject(PyObject* self, Py_Return; } -char KX_TouchSensor::GetHitObjectList_doc[] = +const char KX_TouchSensor::GetHitObjectList_doc[] = "getHitObjectList()\n" "\tReturn a list of the objects this object collided with,\n" "\tbut only those matching the property/material condition.\n"; @@ -364,7 +364,7 @@ PyObject* KX_TouchSensor::PyGetHitObjectList(PyObject* self, } /* 5. getTouchMaterial */ -char KX_TouchSensor::GetTouchMaterial_doc[] = +const char KX_TouchSensor::GetTouchMaterial_doc[] = "getTouchMaterial()\n" "\tReturns KX_TRUE if this sensor looks for a specific material,\n" "\tKX_FALSE if it looks for a specific property.\n" ; @@ -376,7 +376,7 @@ PyObject* KX_TouchSensor::PyGetTouchMaterial(PyObject* self, } /* 6. setTouchMaterial */ -char KX_TouchSensor::SetTouchMaterial_doc[] = +const char KX_TouchSensor::SetTouchMaterial_doc[] = "setTouchMaterial(flag)\n" "\t- flag: KX_TRUE or KX_FALSE.\n" "\tSet flag to KX_TRUE to switch on positive pulse mode,\n" diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp index 67937d5c579..acc4a6ab5d7 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp +++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp @@ -42,6 +42,8 @@ #include <iostream> #include "KX_GameObject.h" +#include "PyObjectPlus.h" + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -454,12 +456,12 @@ PyParentObject KX_TrackToActuator::Parents[] = { PyMethodDef KX_TrackToActuator::Methods[] = { - {"setObject", (PyCFunction) KX_TrackToActuator::sPySetObject, METH_O, SetObject_doc}, - {"getObject", (PyCFunction) KX_TrackToActuator::sPyGetObject, METH_VARARGS, GetObject_doc}, - {"setTime", (PyCFunction) KX_TrackToActuator::sPySetTime, METH_VARARGS, SetTime_doc}, - {"getTime", (PyCFunction) KX_TrackToActuator::sPyGetTime, METH_VARARGS, GetTime_doc}, - {"setUse3D", (PyCFunction) KX_TrackToActuator::sPySetUse3D, METH_VARARGS, SetUse3D_doc}, - {"getUse3D", (PyCFunction) KX_TrackToActuator::sPyGetUse3D, METH_VARARGS, GetUse3D_doc}, + {"setObject", (PyCFunction) KX_TrackToActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc}, + {"getObject", (PyCFunction) KX_TrackToActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc}, + {"setTime", (PyCFunction) KX_TrackToActuator::sPySetTime, METH_VARARGS, (PY_METHODCHAR)SetTime_doc}, + {"getTime", (PyCFunction) KX_TrackToActuator::sPyGetTime, METH_VARARGS, (PY_METHODCHAR)GetTime_doc}, + {"setUse3D", (PyCFunction) KX_TrackToActuator::sPySetUse3D, METH_VARARGS, (PY_METHODCHAR)SetUse3D_doc}, + {"getUse3D", (PyCFunction) KX_TrackToActuator::sPyGetUse3D, METH_VARARGS, (PY_METHODCHAR)GetUse3D_doc}, {NULL,NULL} //Sentinel }; @@ -473,7 +475,7 @@ PyObject* KX_TrackToActuator::_getattr(const STR_String& attr) /* 1. setObject */ -char KX_TrackToActuator::SetObject_doc[] = +const char KX_TrackToActuator::SetObject_doc[] = "setObject(object)\n" "\t- object: KX_GameObject, string or None\n" "\tSet the object to track with the parent of this actuator.\n"; @@ -497,7 +499,7 @@ PyObject* KX_TrackToActuator::PySetObject(PyObject* self, PyObject* value) /* 2. getObject */ -char KX_TrackToActuator::GetObject_doc[] = +const char KX_TrackToActuator::GetObject_doc[] = "getObject(name_only = 1)\n" "name_only - optional arg, when true will return the KX_GameObject rather then its name\n" "\tReturns the object to track with the parent of this actuator\n"; @@ -519,7 +521,7 @@ PyObject* KX_TrackToActuator::PyGetObject(PyObject* self, PyObject* args) /* 3. setTime */ -char KX_TrackToActuator::SetTime_doc[] = +const char KX_TrackToActuator::SetTime_doc[] = "setTime(time)\n" "\t- time: integer\n" "\tSet the time in frames with which to delay the tracking motion.\n"; @@ -540,7 +542,7 @@ PyObject* KX_TrackToActuator::PySetTime(PyObject* self, PyObject* args, PyObject /* 4.getTime */ -char KX_TrackToActuator::GetTime_doc[] = +const char KX_TrackToActuator::GetTime_doc[] = "getTime()\n" "\t- time: integer\n" "\tReturn the time in frames with which the tracking motion is delayed.\n"; @@ -552,7 +554,7 @@ PyObject* KX_TrackToActuator::PyGetTime(PyObject* self, PyObject* args, PyObject /* 5. getUse3D */ -char KX_TrackToActuator::GetUse3D_doc[] = +const char KX_TrackToActuator::GetUse3D_doc[] = "getUse3D()\n" "\tReturns 1 if the motion is allowed to extend in the z-direction.\n"; PyObject* KX_TrackToActuator::PyGetUse3D(PyObject* self, PyObject* args, PyObject* kwds) @@ -563,7 +565,7 @@ PyObject* KX_TrackToActuator::PyGetUse3D(PyObject* self, PyObject* args, PyObjec /* 6. setUse3D */ -char KX_TrackToActuator::SetUse3D_doc[] = +const char KX_TrackToActuator::SetUse3D_doc[] = "setUse3D(value)\n" "\t- value: 0 or 1\n" "\tSet to 1 to allow the tracking motion to extend in the z-direction,\n" diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp index f5a2b5e02fe..342e71c5093 100644 --- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp +++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp @@ -1,6 +1,8 @@ #include <Python.h> +#include "PyObjectPlus.h" + #include "KX_VehicleWrapper.h" #include "PHY_IPhysicsEnvironment.h" #include "PHY_IVehicle.h" diff --git a/source/gameengine/Ketsji/KX_VertexProxy.cpp b/source/gameengine/Ketsji/KX_VertexProxy.cpp index 5cec65dff1c..25205714308 100644 --- a/source/gameengine/Ketsji/KX_VertexProxy.cpp +++ b/source/gameengine/Ketsji/KX_VertexProxy.cpp @@ -82,7 +82,7 @@ PyObject* KX_VertexProxy::_getattr(const STR_String& attr) { if (attr == "XYZ") - return PyObjectFrom(MT_Vector3(m_vertex->getLocalXYZ())); + return PyObjectFrom(MT_Vector3(m_vertex->getXYZ())); if (attr == "UV") return PyObjectFrom(MT_Point2(m_vertex->getUV1())); @@ -102,11 +102,11 @@ KX_VertexProxy::_getattr(const STR_String& attr) // pos if (attr == "x") - return PyFloat_FromDouble(m_vertex->getLocalXYZ()[0]); + return PyFloat_FromDouble(m_vertex->getXYZ()[0]); if (attr == "y") - return PyFloat_FromDouble(m_vertex->getLocalXYZ()[1]); + return PyFloat_FromDouble(m_vertex->getXYZ()[1]); if (attr == "z") - return PyFloat_FromDouble(m_vertex->getLocalXYZ()[2]); + return PyFloat_FromDouble(m_vertex->getXYZ()[2]); // Col if (attr == "r") @@ -184,7 +184,7 @@ int KX_VertexProxy::_setattr(const STR_String& attr, PyObject *pyvalue) { float val = PyFloat_AsDouble(pyvalue); // pos - MT_Point3 pos(m_vertex->getLocalXYZ()); + MT_Point3 pos(m_vertex->getXYZ()); if (attr == "x") { pos.x() = val; @@ -312,7 +312,7 @@ PyObject* KX_VertexProxy::PyGetXYZ(PyObject*, PyObject*, PyObject*) { - return PyObjectFrom(MT_Point3(m_vertex->getLocalXYZ())); + return PyObjectFrom(MT_Point3(m_vertex->getXYZ())); } PyObject* KX_VertexProxy::PySetXYZ(PyObject*, @@ -426,7 +426,7 @@ PyObject* KX_VertexProxy::PySetUV2(PyObject*, { if (PyVecTo(list, vec)) { - m_vertex->SetFlag((m_vertex->getFlag()|TV_2NDUV)); + m_vertex->SetFlag((m_vertex->getFlag()|RAS_TexVert::SECOND_UV)); m_vertex->SetUnit(unit); m_vertex->SetUV2(vec); m_mesh->SetMeshModified(true); diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp index b4693a7a7db..4b0db5a7953 100644 --- a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp +++ b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp @@ -38,10 +38,12 @@ KX_VisibilityActuator::KX_VisibilityActuator( SCA_IObject* gameobj, bool visible, + bool recursive, PyTypeObject* T ) : SCA_IActuator(gameobj,T), - m_visible(visible) + m_visible(visible), + m_recursive(recursive) { // intentionally empty } @@ -75,10 +77,10 @@ KX_VisibilityActuator::Update() KX_GameObject *obj = (KX_GameObject*) GetParent(); - obj->SetVisible(m_visible); - obj->MarkVisible(); + obj->SetVisible(m_visible, m_recursive); + obj->UpdateBuckets(m_recursive); - return true; + return false; } /* ------------------------------------------------------------------------- */ @@ -120,7 +122,7 @@ KX_VisibilityActuator::Parents[] = { PyMethodDef KX_VisibilityActuator::Methods[] = { {"set", (PyCFunction) KX_VisibilityActuator::sPySetVisible, - METH_VARARGS, SetVisible_doc}, + METH_VARARGS, (PY_METHODCHAR)SetVisible_doc}, {NULL,NULL} //Sentinel }; @@ -135,7 +137,7 @@ KX_VisibilityActuator::_getattr( /* set visibility ---------------------------------------------------------- */ -char +const char KX_VisibilityActuator::SetVisible_doc[] = "setVisible(visible?)\n" "\t - visible? : Make the object visible? (KX_TRUE, KX_FALSE)" diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.h b/source/gameengine/Ketsji/KX_VisibilityActuator.h index 9b4753033fb..d1b85ab998c 100644 --- a/source/gameengine/Ketsji/KX_VisibilityActuator.h +++ b/source/gameengine/Ketsji/KX_VisibilityActuator.h @@ -39,12 +39,14 @@ class KX_VisibilityActuator : public SCA_IActuator /** Make visible? */ bool m_visible; + bool m_recursive; public: KX_VisibilityActuator( SCA_IObject* gameobj, bool visible, + bool recursive, PyTypeObject* T=&Type ); diff --git a/source/gameengine/Ketsji/Makefile b/source/gameengine/Ketsji/Makefile index 47a4855b00c..0b48ad8b8c3 100644 --- a/source/gameengine/Ketsji/Makefile +++ b/source/gameengine/Ketsji/Makefile @@ -35,10 +35,13 @@ include nan_compile.mk CCFLAGS += $(LEVEL_1_CPP_WARNINGS) +CPPFLAGS += $(NAN_SDLCFLAGS) CPPFLAGS += $(OGL_CPPFLAGS) CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) -CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) -I../../blender/python +CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) +CPPFLAGS += -I../../blender/python +CPPFLAGS += -I../../blender/python/api2_2x CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO) -I$(NAN_MOTO)/include @@ -61,13 +64,9 @@ CPPFLAGS += -I../../blender/blenlib CPPFLAGS += -I../../blender/include CPPFLAGS += -I../../blender/makesdna CPPFLAGS += -I../../blender/imbuf +CPPFLAGS += -I../../blender/gpu CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include -ifeq ($(WITH_BF_GLEXT),true) - CPPFLAGS += -DWITH_GLEXT -endif - - ########################### SOURCEDIR = source/gameengine/Ketsji diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript index f6f744b199a..02e7aed82a5 100644 --- a/source/gameengine/Ketsji/SConscript +++ b/source/gameengine/Ketsji/SConscript @@ -32,16 +32,13 @@ incs += ' #source/gameengine/SceneGraph #source/gameengine/Physics/common #sourc incs += ' #source/gameengine/Physics/BlOde #source/gameengine/Physics/Dummy' incs += ' #source/gameengine/Physics/Sumo #source/gameengine/Physics/Sumo/include' incs += ' #source/gameengine/Physics/Sumo/Fuzzics/include #source/gameengine/Network/LoopBackNetwork' -incs += ' #source/blender/misc #source/blender/blenloader #extern/glew/include' +incs += ' #source/blender/misc #source/blender/blenloader #extern/glew/include #source/blender/gpu' cflags = [] if env['OURPLATFORM'] == 'win32-vc': cflags.append('/GR') cflags.append('/Ox') -if env['WITH_BF_GLEXT'] == 1: - env['CPPFLAGS'].append('-DWITH_GLEXT') - incs += ' ' + env['BF_SOLID_INC'] incs += ' ' + env['BF_PYTHON_INC'] incs += ' ' + env['BF_SDL_INC'] diff --git a/source/gameengine/Physics/BlOde/OdePhysicsController.h b/source/gameengine/Physics/BlOde/OdePhysicsController.h index d3eb443ed3a..925f5b6686a 100644 --- a/source/gameengine/Physics/BlOde/OdePhysicsController.h +++ b/source/gameengine/Physics/BlOde/OdePhysicsController.h @@ -111,6 +111,8 @@ public: virtual void calcXform(){} virtual void SetMargin(float margin) {} virtual float GetMargin() const {return 0.f;} + virtual float GetRadius() const {return 0.f;} + virtual void SetRadius(float margin) {} // clientinfo for raycasts for example virtual void* getNewClientInfo() { return m_clientInfo;} diff --git a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp index a04560aaf09..2e8ee31058f 100644 --- a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp +++ b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.cpp @@ -198,7 +198,7 @@ int ODEPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl } -void ODEPhysicsEnvironment::removeConstraint(int constraintid) +void ODEPhysicsEnvironment::removeConstraint(void *constraintid) { if (constraintid) { @@ -206,8 +206,7 @@ void ODEPhysicsEnvironment::removeConstraint(int constraintid) } } -PHY_IPhysicsController* ODEPhysicsEnvironment::rayTest(PHY_IPhysicsController* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ) +PHY_IPhysicsController* ODEPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ) { //m_OdeWorld diff --git a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h index 7c61902f8e2..dcc87d614c0 100644 --- a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h +++ b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h @@ -54,8 +54,7 @@ public: float axisX,float axisY,float axisZ); virtual void removeConstraint(void * constraintid); - virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ); + virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ); //gamelogic callbacks diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt index b610fd1bbb0..6c733786caf 100644 --- a/source/gameengine/Physics/Bullet/CMakeLists.txt +++ b/source/gameengine/Physics/Bullet/CMakeLists.txt @@ -30,6 +30,10 @@ SET(INC . ../common ../../../../extern/bullet2/src + ../../../../intern/moto/include + ../../../kernel/gen_system + ../../../../intern/string + ../../Rasterizer ) BLENDERLIB(bf_bullet "${SRC}" "${INC}") diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index b872fae6138..c9c30c1b450 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -15,10 +15,18 @@ subject to the following restrictions: #include "CcdPhysicsController.h" #include "btBulletDynamicsCommon.h" - +#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" #include "PHY_IMotionState.h" #include "CcdPhysicsEnvironment.h" +#include "RAS_MeshObject.h" +#include "BulletSoftBody/btSoftBody.h" +#include "BulletSoftBody//btSoftBodyInternals.h" +#include "BulletSoftBody/btSoftBodyHelpers.h" +#include "LinearMath/btConvexHull.h" +#include "BulletCollision/Gimpact/btGImpactShape.h" + +#include "BulletSoftBody/btSoftRigidDynamicsWorld.h" class BP_Proxy; @@ -40,22 +48,36 @@ btVector3 startVel(0,0,0);//-10000); CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci) :m_cci(ci) { + m_prototypeTransformInitialized = false; + m_softbodyMappingDone = false; m_collisionDelay = 0; m_newClientInfo = 0; m_registerCount = 0; - + m_softBodyTransformInitialized = false; + m_parentCtrl = 0; + // copy pointers locally to allow smart release m_MotionState = ci.m_MotionState; + m_collisionShape = ci.m_collisionShape; + // apply scaling before creating rigid body + m_collisionShape->setLocalScaling(m_cci.m_scaling); + if (m_cci.m_mass) + m_collisionShape->calculateLocalInertia(m_cci.m_mass, m_cci.m_localInertiaTensor); + // shape info is shared, increment ref count + m_shapeInfo = ci.m_shapeInfo; + if (m_shapeInfo) + m_shapeInfo->AddRef(); + m_bulletMotionState = 0; CreateRigidbody(); - - #ifdef WIN32 - if (m_body->getInvMass()) - m_body->setLinearVelocity(startVel); - #endif +///??? +#ifdef WIN32 + if (GetRigidBody() && !GetRigidBody()->isStaticObject()) + GetRigidBody()->setLinearVelocity(startVel); +#endif } @@ -107,20 +129,351 @@ public: }; -void CcdPhysicsController::CreateRigidbody() +btRigidBody* CcdPhysicsController::GetRigidBody() +{ + return btRigidBody::upcast(m_object); +} +btCollisionObject* CcdPhysicsController::GetCollisionObject() +{ + return m_object; +} +btSoftBody* CcdPhysicsController::GetSoftBody() { + return btSoftBody::upcast(m_object); +} + +#include "BulletSoftBody/btSoftBodyHelpers.h" + - btTransform trans = GetTransformFromMotionState(m_MotionState); +void CcdPhysicsController::CreateRigidbody() +{ + + //btTransform trans = GetTransformFromMotionState(m_MotionState); m_bulletMotionState = new BlenderBulletMotionState(m_MotionState); - m_body = new btRigidBody(m_cci.m_mass, - m_bulletMotionState, - m_cci.m_collisionShape, - m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor, - m_cci.m_linearDamping,m_cci.m_angularDamping, - m_cci.m_friction,m_cci.m_restitution); + ///either create a btCollisionObject, btRigidBody or btSoftBody + + //create a collision object + + int shapeType = m_cci.m_collisionShape ? m_cci.m_collisionShape->getShapeType() : 0; + + //disable soft body until first sneak preview is ready + if (m_cci.m_bSoft && m_cci.m_collisionShape && + (shapeType == CONVEX_HULL_SHAPE_PROXYTYPE)| + (shapeType == TRIANGLE_MESH_SHAPE_PROXYTYPE) | + (shapeType == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE)) + { + btRigidBody::btRigidBodyConstructionInfo rbci(m_cci.m_mass,m_bulletMotionState,m_collisionShape,m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); + rbci.m_linearDamping = m_cci.m_linearDamping; + rbci.m_angularDamping = m_cci.m_angularDamping; + rbci.m_friction = m_cci.m_friction; + rbci.m_restitution = m_cci.m_restitution; + + + int nodecount = 0; + + int numtriangles = 1; + + btVector3 p(0,0,0);// = getOrigin(); + btScalar h = 1.f; + + btSoftRigidDynamicsWorld* softDynaWorld = (btSoftRigidDynamicsWorld*)m_cci.m_physicsEnv->getDynamicsWorld(); + + PHY__Vector3 grav; + grav[0] = softDynaWorld->getGravity().getX(); + grav[1] = softDynaWorld->getGravity().getY(); + grav[2] = softDynaWorld->getGravity().getZ(); + softDynaWorld->getWorldInfo().m_gravity.setValue(grav[0],grav[1],grav[2]); //?? + + + //btSoftBody* psb=btSoftBodyHelpers::CreateRope(sbi, btVector3(-10,0,i*0.25),btVector3(10,0,i*0.25), 16,1+2); + + btSoftBody* psb = 0; + + if (m_cci.m_collisionShape->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE) + { + btConvexHullShape* convexHull = (btConvexHullShape* )m_cci.m_collisionShape; + + //psb = btSoftBodyHelpers::CreateFromConvexHull(sbi,&transformedVertices[0],convexHull->getNumPoints()); + + { + int nvertices = convexHull->getNumPoints(); + const btVector3* vertices = convexHull->getPoints(); + btSoftBodyWorldInfo& worldInfo = softDynaWorld->getWorldInfo(); + + HullDesc hdsc(QF_TRIANGLES,nvertices,vertices); + HullResult hres; + HullLibrary hlib;/*??*/ + hdsc.mMaxVertices=nvertices; + hlib.CreateConvexHull(hdsc,hres); + + psb=new btSoftBody(&worldInfo,(int)hres.mNumOutputVertices, + &hres.m_OutputVertices[0],0); + for(int i=0;i<(int)hres.mNumFaces;++i) + { + const int idx[]={ hres.m_Indices[i*3+0], + hres.m_Indices[i*3+1], + hres.m_Indices[i*3+2]}; + if(idx[0]<idx[1]) psb->appendLink( idx[0],idx[1]); + if(idx[1]<idx[2]) psb->appendLink( idx[1],idx[2]); + if(idx[2]<idx[0]) psb->appendLink( idx[2],idx[0]); + psb->appendFace(idx[0],idx[1],idx[2]); + } + + + + hlib.ReleaseResult(hres); + + + } + + + + + + + } else + { + + btSoftBodyWorldInfo& sbi= softDynaWorld->getWorldInfo(); + + if (m_cci.m_collisionShape->getShapeType() ==SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) + { + btScaledBvhTriangleMeshShape* scaledtrimeshshape = (btScaledBvhTriangleMeshShape*) m_cci.m_collisionShape; + btBvhTriangleMeshShape* trimeshshape = scaledtrimeshshape->getChildShape(); + + ///only deal with meshes that have 1 sub part/component, for now + if (trimeshshape->getMeshInterface()->getNumSubParts()==1) + { + unsigned char* vertexBase; + PHY_ScalarType vertexType; + int numverts; + int vertexstride; + unsigned char* indexbase; + int indexstride; + int numtris; + PHY_ScalarType indexType; + trimeshshape->getMeshInterface()->getLockedVertexIndexBase(&vertexBase,numverts,vertexType,vertexstride,&indexbase,indexstride,numtris,indexType); + + psb = btSoftBodyHelpers::CreateFromTriMesh(sbi,(const btScalar*)vertexBase,(const int*)indexbase,numtris); + } + } else + { + btBvhTriangleMeshShape* trimeshshape = (btBvhTriangleMeshShape*) m_cci.m_collisionShape; + ///only deal with meshes that have 1 sub part/component, for now + if (trimeshshape->getMeshInterface()->getNumSubParts()==1) + { + unsigned char* vertexBase; + PHY_ScalarType vertexType; + int numverts; + int vertexstride; + unsigned char* indexbase; + int indexstride; + int numtris; + PHY_ScalarType indexType; + trimeshshape->getMeshInterface()->getLockedVertexIndexBase(&vertexBase,numverts,vertexType,vertexstride,&indexbase,indexstride,numtris,indexType); + + psb = btSoftBodyHelpers::CreateFromTriMesh(sbi,(const btScalar*)vertexBase,(const int*)indexbase,numtris); + } + + + //psb = btSoftBodyHelpers::CreateFromTriMesh(sbi,&pts[0].getX(),triangles,numtriangles); + } + + } + + + + m_object = psb; + + //psb->m_cfg.collisions = btSoftBody::fCollision::SDF_RS;//btSoftBody::fCollision::CL_SS+ btSoftBody::fCollision::CL_RS; + + //psb->m_cfg.collisions = btSoftBody::fCollision::SDF_RS + btSoftBody::fCollision::VF_SS;//CL_SS; + + + //btSoftBody::Material* pm=psb->appendMaterial(); + btSoftBody::Material* pm=psb->m_materials[0]; + pm->m_kLST = m_cci.m_soft_linStiff; + pm->m_kAST = m_cci.m_soft_angStiff; + pm->m_kVST = m_cci.m_soft_volume; + psb->m_cfg.collisions = 0; + + if (m_cci.m_soft_collisionflags & CCD_BSB_COL_CL_RS) + { + psb->m_cfg.collisions += btSoftBody::fCollision::CL_RS; + } else + { + psb->m_cfg.collisions += btSoftBody::fCollision::SDF_RS; + } + if (m_cci.m_soft_collisionflags & CCD_BSB_COL_CL_SS) + { + psb->m_cfg.collisions += btSoftBody::fCollision::CL_SS; + } else + { + psb->m_cfg.collisions += btSoftBody::fCollision::VF_SS; + } + + + psb->m_cfg.kSRHR_CL = m_cci.m_soft_kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */ + psb->m_cfg.kSKHR_CL = m_cci.m_soft_kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */ + psb->m_cfg.kSSHR_CL = m_cci.m_soft_kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */ + psb->m_cfg.kSR_SPLT_CL = m_cci.m_soft_kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + + psb->m_cfg.kSK_SPLT_CL = m_cci.m_soft_kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + psb->m_cfg.kSS_SPLT_CL = m_cci.m_soft_kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + psb->m_cfg.kVCF = m_cci.m_soft_kVCF; /* Velocities correction factor (Baumgarte) */ + psb->m_cfg.kDP = m_cci.m_soft_kDP; /* Damping coefficient [0,1] */ + + psb->m_cfg.kDG = m_cci.m_soft_kDG; /* Drag coefficient [0,+inf] */ + psb->m_cfg.kLF = m_cci.m_soft_kLF; /* Lift coefficient [0,+inf] */ + psb->m_cfg.kPR = m_cci.m_soft_kPR; /* Pressure coefficient [-inf,+inf] */ + psb->m_cfg.kVC = m_cci.m_soft_kVC; /* Volume conversation coefficient [0,+inf] */ + + psb->m_cfg.kDF = m_cci.m_soft_kDF; /* Dynamic friction coefficient [0,1] */ + psb->m_cfg.kMT = m_cci.m_soft_kMT; /* Pose matching coefficient [0,1] */ + psb->m_cfg.kCHR = m_cci.m_soft_kCHR; /* Rigid contacts hardness [0,1] */ + psb->m_cfg.kKHR = m_cci.m_soft_kKHR; /* Kinetic contacts hardness [0,1] */ + + psb->m_cfg.kSHR = m_cci.m_soft_kSHR; /* Soft contacts hardness [0,1] */ + psb->m_cfg.kAHR = m_cci.m_soft_kAHR; /* Anchors hardness [0,1] */ + + + if (m_cci.m_gamesoftFlag & CCD_BSB_BENDING_CONSTRAINTS)//OB_SB_GOAL) + { + psb->generateBendingConstraints(2,pm); + } + + psb->m_cfg.piterations = m_cci.m_soft_piterations; + psb->m_cfg.viterations = m_cci.m_soft_viterations; + psb->m_cfg.diterations = m_cci.m_soft_diterations; + psb->m_cfg.citerations = m_cci.m_soft_citerations; + + if (m_cci.m_gamesoftFlag & CCD_BSB_SHAPE_MATCHING)//OB_SB_GOAL) + { + psb->setPose(false,true);// + } else + { + psb->setPose(true,false); + } + + + + psb->randomizeConstraints(); + + if (m_cci.m_soft_collisionflags & (CCD_BSB_COL_CL_RS+CCD_BSB_COL_CL_SS)) + { + psb->generateClusters(m_cci.m_soft_numclusteriterations); + } + +// psb->activate(); +// psb->setActivationState(1); +// psb->setDeactivationTime(1.f); + + //psb->m_materials[0]->m_kLST = 0.1+(i/(btScalar)(n-1))*0.9; + psb->setTotalMass(m_cci.m_mass); + + psb->setCollisionFlags(0); + + ///create a mapping between graphics mesh vertices and soft body vertices + { + RAS_MeshObject* rasMesh= GetShapeInfo()->GetMesh(); + + if (rasMesh && !m_softbodyMappingDone) + { + + //printf("apply\n"); + RAS_MeshSlot::iterator it; + RAS_MeshMaterial *mmat; + RAS_MeshSlot *slot; + size_t i; + + //for each material + for (int m=0;m<rasMesh->NumMaterials();m++) + { + // The vertex cache can only be updated for this deformer: + // Duplicated objects with more than one ploymaterial (=multiple mesh slot per object) + // share the same mesh (=the same cache). As the rendering is done per polymaterial + // cycling through the objects, the entire mesh cache cannot be updated in one shot. + mmat = rasMesh->GetMeshMaterial(m); + + slot = mmat->m_baseslot; + for(slot->begin(it); !slot->end(it); slot->next(it)) + { + int index = 0; + for(i=it.startvertex; i<it.endvertex; i++,index++) + { + RAS_TexVert* vertex = &it.vertex[i]; + + + //search closest index, and store it in vertex + vertex->setSoftBodyIndex(0); + btScalar maxDistSqr = 1e30; + btSoftBody::tNodeArray& nodes(psb->m_nodes); + btVector3 xyz = btVector3(vertex->getXYZ()[0],vertex->getXYZ()[1],vertex->getXYZ()[2]); + for (int n=0;n<nodes.size();n++) + { + btScalar distSqr = (nodes[n].m_x - xyz).length2(); + if (distSqr<maxDistSqr) + { + maxDistSqr = distSqr; + + vertex->setSoftBodyIndex(n); + } + } + } + } + } + } + } + + m_softbodyMappingDone = true; + + + + + + +// m_object->setCollisionShape(rbci.m_collisionShape); + btTransform startTrans; + + if (rbci.m_motionState) + { + rbci.m_motionState->getWorldTransform(startTrans); + } else + { + startTrans = rbci.m_startWorldTransform; + } + //startTrans.setIdentity(); + + //m_object->setWorldTransform(startTrans); + //m_object->setInterpolationWorldTransform(startTrans); + m_MotionState->setWorldPosition(startTrans.getOrigin().getX(),startTrans.getOrigin().getY(),startTrans.getOrigin().getZ()); + m_MotionState->setWorldOrientation(0,0,0,1); + + if (!m_prototypeTransformInitialized) + { + m_prototypeTransformInitialized = true; + m_softBodyTransformInitialized = true; + GetSoftBody()->transform(startTrans); + } + +// btVector3 wp = m_softBody->getWorldTransform().getOrigin(); +// MT_Point3 center(wp.getX(),wp.getY(),wp.getZ()); +// m_gameobj->NodeSetWorldPosition(center); + + + } else + { + btRigidBody::btRigidBodyConstructionInfo rbci(m_cci.m_mass,m_bulletMotionState,m_collisionShape,m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); + rbci.m_linearDamping = m_cci.m_linearDamping; + rbci.m_angularDamping = m_cci.m_angularDamping; + rbci.m_friction = m_cci.m_friction; + rbci.m_restitution = m_cci.m_restitution; + m_object = new btRigidBody(rbci); + } + // // init the rigidbody properly // @@ -132,16 +485,39 @@ void CcdPhysicsController::CreateRigidbody() if ((m_cci.m_collisionFilterGroup & CcdConstructionInfo::SensorFilter) != 0) { // reset the flags that have been set so far - m_body->setCollisionFlags(0); + GetCollisionObject()->setCollisionFlags(0); } - m_body->setCollisionFlags(m_body->getCollisionFlags() | m_cci.m_collisionFlags); - m_body->setGravity( m_cci.m_gravity); - m_body->setDamping(m_cci.m_linearDamping, m_cci.m_angularDamping); + GetCollisionObject()->setCollisionFlags(m_object->getCollisionFlags() | m_cci.m_collisionFlags); + btRigidBody* body = GetRigidBody(); + + if (body) + { + body->setGravity( m_cci.m_gravity); + body->setDamping(m_cci.m_linearDamping, m_cci.m_angularDamping); + + if (!m_cci.m_bRigid) + { + body->setAngularFactor(0.f); + } + } + if (m_object && m_cci.m_do_anisotropic) + { + m_object->setAnisotropicFriction(m_cci.m_anisotropicFriction); + } + +} - if (!m_cci.m_bRigid) +static void DeleteBulletShape(btCollisionShape* shape) +{ + if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE) { - m_body->setAngularFactor(0.f); + // shapes based on meshes use an interface that contains the vertices. + btTriangleMeshShape* meshShape = static_cast<btTriangleMeshShape*>(shape); + btStridingMeshInterface* meshInterface = meshShape->getMeshInterface(); + if (meshInterface) + delete meshInterface; } + delete shape; } CcdPhysicsController::~CcdPhysicsController() @@ -154,7 +530,28 @@ CcdPhysicsController::~CcdPhysicsController() delete m_MotionState; if (m_bulletMotionState) delete m_bulletMotionState; - delete m_body; + delete m_object; + + if (m_collisionShape) + { + // collision shape is always unique to the controller, can delete it here + if (m_collisionShape->isCompound()) + { + // bullet does not delete the child shape, must do it here + btCompoundShape* compoundShape = (btCompoundShape*)m_collisionShape; + int numChild = compoundShape->getNumChildShapes(); + for (int i=numChild-1 ; i >= 0; i--) + { + btCollisionShape* childShape = compoundShape->getChildShape(i); + DeleteBulletShape(childShape); + } + } + DeleteBulletShape(m_collisionShape); + } + if (m_shapeInfo) + { + m_shapeInfo->Release(); + } } @@ -165,12 +562,26 @@ bool CcdPhysicsController::SynchronizeMotionStates(float time) { //sync non-static to motionstate, and static from motionstate (todo: add kinematic etc.) - if (!m_body->isStaticObject()) + btSoftBody* sb = GetSoftBody(); + if (sb) { - const btVector3& worldPos = m_body->getCenterOfMassPosition(); + btVector3 aabbMin,aabbMax; + sb->getAabb(aabbMin,aabbMax); + btVector3 worldPos = (aabbMax+aabbMin)*0.5f; + m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]); + m_MotionState->calculateWorldTransformations(); + return true; + } + + btRigidBody* body = GetRigidBody(); + + if (body && !body->isStaticObject()) + { + + const btVector3& worldPos = body->getCenterOfMassPosition(); m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]); - const btQuaternion& worldquat = m_body->getOrientation(); + const btQuaternion& worldquat = body->getOrientation(); m_MotionState->setWorldOrientation(worldquat[0],worldquat[1],worldquat[2],worldquat[3]); m_MotionState->calculateWorldTransformations(); @@ -189,7 +600,7 @@ bool CcdPhysicsController::SynchronizeMotionStates(float time) btTransform oldTrans = m_body->getCenterOfMassTransform(); btTransform newTrans(worldquat,worldPos); - m_body->setCenterOfMassTransform(newTrans); + SetCenterOfMassTransform(newTrans); //need to keep track of previous position for friction effects... m_MotionState->calculateWorldTransformations(); @@ -217,13 +628,41 @@ void CcdPhysicsController::WriteDynamicsToMotionState() // controller replication void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl) { + + m_softBodyTransformInitialized=false; m_MotionState = motionstate; m_registerCount = 0; - + m_collisionShape = NULL; - m_body = 0; + // always create a new shape to avoid scaling bug + if (m_shapeInfo) + { + m_shapeInfo->AddRef(); + m_collisionShape = m_shapeInfo->CreateBulletShape(); + + if (m_collisionShape) + { + // new shape has no scaling, apply initial scaling + m_collisionShape->setMargin(m_cci.m_margin); + m_collisionShape->setLocalScaling(m_cci.m_scaling); + + if (m_cci.m_mass) + m_collisionShape->calculateLocalInertia(m_cci.m_mass, m_cci.m_localInertiaTensor); + } + } + + m_object = 0; CreateRigidbody(); - + + btRigidBody* body = GetRigidBody(); + + if (body) + { + if (m_cci.m_mass) + { + body->setMassProps(m_cci.m_mass, m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); + } + } m_cci.m_physicsEnv->addCcdPhysicsController(this); @@ -259,40 +698,75 @@ void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionsta } + +void CcdPhysicsController::SetCenterOfMassTransform(btTransform& xform) +{ + btRigidBody* body = GetRigidBody(); + if (body) + { + body->setCenterOfMassTransform(xform); + } else + { + //either collision object or soft body? + if (GetSoftBody()) + { + + } else + { + + if (m_object->isStaticOrKinematicObject()) + { + m_object->setInterpolationWorldTransform(m_object->getWorldTransform()); + } else + { + m_object->setInterpolationWorldTransform(xform); + } + if (body) + { + body->setInterpolationLinearVelocity(body->getLinearVelocity()); + body->setInterpolationAngularVelocity(body->getAngularVelocity()); + body->updateInertiaTensor(); + } + m_object->setWorldTransform(xform); + } + } +} + // kinematic methods void CcdPhysicsController::RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local) { - if (m_body) + if (m_object) { - m_body->activate(true); - if (m_body->isStaticObject()) + m_object->activate(true); + if (m_object->isStaticObject()) { - m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } + btRigidBody* body = GetRigidBody(); btVector3 dloc(dlocX,dlocY,dlocZ); - btTransform xform = m_body->getCenterOfMassTransform(); - + btTransform xform = m_object->getWorldTransform(); + if (local) { dloc = xform.getBasis()*dloc; } xform.setOrigin(xform.getOrigin() + dloc); - m_body->setCenterOfMassTransform(xform); + SetCenterOfMassTransform(xform); } } void CcdPhysicsController::RelativeRotate(const float rotval[9],bool local) { - if (m_body) + if (m_object) { - m_body->activate(true); - if (m_body->isStaticObject()) + m_object->activate(true); + if (m_object->isStaticObject()) { - m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } btMatrix3x3 drotmat( rotval[0],rotval[4],rotval[8], @@ -303,16 +777,16 @@ void CcdPhysicsController::RelativeRotate(const float rotval[9],bool local) btMatrix3x3 currentOrn; GetWorldOrientation(currentOrn); - btTransform xform = m_body->getCenterOfMassTransform(); - + btTransform xform = m_object->getWorldTransform(); + xform.setBasis(xform.getBasis()*(local ? drotmat : (currentOrn.inverse() * drotmat * currentOrn))); - m_body->setCenterOfMassTransform(xform); + SetCenterOfMassTransform(xform); } - } + void CcdPhysicsController::GetWorldOrientation(btMatrix3x3& mat) { float orn[4]; @@ -323,7 +797,7 @@ void CcdPhysicsController::GetWorldOrientation(btMatrix3x3& mat) void CcdPhysicsController::getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal) { - btQuaternion q = m_body->getCenterOfMassTransform().getRotation(); + btQuaternion q = m_object->getWorldTransform().getRotation(); quatImag0 = q[0]; quatImag1 = q[1]; quatImag2 = q[2]; @@ -331,58 +805,72 @@ void CcdPhysicsController::getOrientation(float &quatImag0,float &quatImag1,flo } void CcdPhysicsController::setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal) { - if (m_body) + if (m_object) { - m_body->activate(true); - if (m_body->isStaticObject()) + m_object->activate(true); + if (m_object->isStaticObject()) { - m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } // not required //m_MotionState->setWorldOrientation(quatImag0,quatImag1,quatImag2,quatReal); - btTransform xform = m_body->getCenterOfMassTransform(); + btTransform xform = m_object->getWorldTransform(); xform.setRotation(btQuaternion(quatImag0,quatImag1,quatImag2,quatReal)); - m_body->setCenterOfMassTransform(xform); + SetCenterOfMassTransform(xform); // not required //m_bulletMotionState->setWorldTransform(xform); + + + } } void CcdPhysicsController::setWorldOrientation(const btMatrix3x3& orn) { - if (m_body) + if (m_object) { - m_body->activate(true); - if (m_body->isStaticObject()) + m_object->activate(true); + if (m_object->isStaticObject()) { - m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } // not required //m_MotionState->setWorldOrientation(quatImag0,quatImag1,quatImag2,quatReal); - btTransform xform = m_body->getCenterOfMassTransform(); + btTransform xform = m_object->getWorldTransform(); xform.setBasis(orn); - m_body->setCenterOfMassTransform(xform); + SetCenterOfMassTransform(xform); // not required //m_bulletMotionState->setWorldTransform(xform); + //only once! + if (!m_softBodyTransformInitialized && GetSoftBody()) + { + m_softbodyStartTrans.setBasis(orn); + xform.setOrigin(m_softbodyStartTrans.getOrigin()); + GetSoftBody()->transform(xform); + m_softBodyTransformInitialized = true; + } + } } void CcdPhysicsController::setPosition(float posX,float posY,float posZ) { - if (m_body) + if (m_object) { - m_body->activate(true); - if (m_body->isStaticObject()) + m_object->activate(true); + if (m_object->isStaticObject()) { - m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } // not required, this function is only used to update the physic controller //m_MotionState->setWorldPosition(posX,posY,posZ); - btTransform xform = m_body->getCenterOfMassTransform(); + btTransform xform = m_object->getWorldTransform(); xform.setOrigin(btVector3(posX,posY,posZ)); - m_body->setCenterOfMassTransform(xform); + SetCenterOfMassTransform(xform); + if (!m_softBodyTransformInitialized) + m_softbodyStartTrans.setOrigin(xform.getOrigin()); // not required //m_bulletMotionState->setWorldTransform(xform); } @@ -395,7 +883,7 @@ void CcdPhysicsController::resolveCombinedVelocities(float linvelX,float linvel void CcdPhysicsController::getPosition(PHY__Vector3& pos) const { - const btTransform& xform = m_body->getCenterOfMassTransform(); + const btTransform& xform = m_object->getWorldTransform(); pos[0] = xform.getOrigin().x(); pos[1] = xform.getOrigin().y(); pos[2] = xform.getOrigin().z(); @@ -409,15 +897,16 @@ void CcdPhysicsController::setScaling(float scaleX,float scaleY,float scaleZ) { m_cci.m_scaling = btVector3(scaleX,scaleY,scaleZ); - if (m_body && m_body->getCollisionShape()) + if (m_object && m_object->getCollisionShape()) { - m_body->getCollisionShape()->setLocalScaling(m_cci.m_scaling); + m_object->getCollisionShape()->setLocalScaling(m_cci.m_scaling); //printf("no inertia recalc for fixed objects with mass=0\n"); - if (m_cci.m_mass) + btRigidBody* body = GetRigidBody(); + if (body && m_cci.m_mass) { - m_body->getCollisionShape()->calculateLocalInertia(m_cci.m_mass, m_cci.m_localInertiaTensor); - m_body->setMassProps(m_cci.m_mass, m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); + body->getCollisionShape()->calculateLocalInertia(m_cci.m_mass, m_cci.m_localInertiaTensor); + body->setMassProps(m_cci.m_mass, m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); } } @@ -428,19 +917,23 @@ void CcdPhysicsController::setScaling(float scaleX,float scaleY,float scaleZ) void CcdPhysicsController::ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local) { btVector3 torque(torqueX,torqueY,torqueZ); - btTransform xform = m_body->getCenterOfMassTransform(); - if (m_body && torque.length2() > (SIMD_EPSILON*SIMD_EPSILON)) + btTransform xform = m_object->getWorldTransform(); + + + if (m_object && torque.length2() > (SIMD_EPSILON*SIMD_EPSILON)) { - m_body->activate(); - if (m_body->isStaticObject()) + btRigidBody* body = GetRigidBody(); + m_object->activate(); + if (m_object->isStaticObject()) { - m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } if (local) { torque = xform.getBasis()*torque; } - m_body->applyTorque(torque); + if (body) + body->applyTorque(torque); } } @@ -448,41 +941,57 @@ void CcdPhysicsController::ApplyForce(float forceX,float forceY,float forceZ,bo { btVector3 force(forceX,forceY,forceZ); - if (m_body && force.length2() > (SIMD_EPSILON*SIMD_EPSILON)) + + if (m_object && force.length2() > (SIMD_EPSILON*SIMD_EPSILON)) { - m_body->activate(); - if (m_body->isStaticObject()) + m_object->activate(); + if (m_object->isStaticObject()) { - m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } + { - btTransform xform = m_body->getCenterOfMassTransform(); + btTransform xform = m_object->getWorldTransform(); + if (local) { force = xform.getBasis()*force; } + btRigidBody* body = GetRigidBody(); + if (body) + body->applyCentralForce(force); + btSoftBody* soft = GetSoftBody(); + if (soft) + { + // the force is applied on each node, must reduce it in the same extend + if (soft->m_nodes.size() > 0) + force /= soft->m_nodes.size(); + soft->addForce(force); + } } - m_body->applyCentralForce(force); } } void CcdPhysicsController::SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local) { btVector3 angvel(ang_velX,ang_velY,ang_velZ); - if (m_body && angvel.length2() > (SIMD_EPSILON*SIMD_EPSILON)) + if (m_object && angvel.length2() > (SIMD_EPSILON*SIMD_EPSILON)) { - m_body->activate(true); - if (m_body->isStaticObject()) + m_object->activate(true); + if (m_object->isStaticObject()) { - m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); - } + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + } else { - btTransform xform = m_body->getCenterOfMassTransform(); + btTransform xform = m_object->getWorldTransform(); if (local) { angvel = xform.getBasis()*angvel; } + btRigidBody* body = GetRigidBody(); + if (body) + body->setAngularVelocity(angvel); + } - m_body->setAngularVelocity(angvel); } } @@ -490,39 +999,53 @@ void CcdPhysicsController::SetLinearVelocity(float lin_velX,float lin_velY,floa { btVector3 linVel(lin_velX,lin_velY,lin_velZ); - if (m_body && linVel.length2() > (SIMD_EPSILON*SIMD_EPSILON)) + if (m_object/* && linVel.length2() > (SIMD_EPSILON*SIMD_EPSILON)*/) { - m_body->activate(true); - if (m_body->isStaticObject()) + m_object->activate(true); + if (m_object->isStaticObject()) { - m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + return; } - + + btSoftBody* soft = GetSoftBody(); + if (soft) + { + if (local) + { + linVel = m_softbodyStartTrans.getBasis()*linVel; + } + soft->setVelocity(linVel); + } else { - btTransform xform = m_body->getCenterOfMassTransform(); + btTransform xform = m_object->getWorldTransform(); if (local) { linVel = xform.getBasis()*linVel; } + btRigidBody* body = GetRigidBody(); + if (body) + body->setLinearVelocity(linVel); } - m_body->setLinearVelocity(linVel); } } void CcdPhysicsController::applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ) { btVector3 impulse(impulseX,impulseY,impulseZ); - if (m_body && impulse.length2() > (SIMD_EPSILON*SIMD_EPSILON)) + if (m_object && impulse.length2() > (SIMD_EPSILON*SIMD_EPSILON)) { - m_body->activate(); - if (m_body->isStaticObject()) + m_object->activate(); + if (m_object->isStaticObject()) { - m_body->setCollisionFlags(m_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } btVector3 pos(attachX,attachY,attachZ); - - m_body->applyImpulse(impulse,pos); + btRigidBody* body = GetRigidBody(); + if (body) + body->applyImpulse(impulse,pos); + } } @@ -532,29 +1055,55 @@ void CcdPhysicsController::SetActive(bool active) // reading out information from physics void CcdPhysicsController::GetLinearVelocity(float& linvX,float& linvY,float& linvZ) { - const btVector3& linvel = this->m_body->getLinearVelocity(); - linvX = linvel.x(); - linvY = linvel.y(); - linvZ = linvel.z(); + btRigidBody* body = GetRigidBody(); + if (body) + { + const btVector3& linvel = body->getLinearVelocity(); + linvX = linvel.x(); + linvY = linvel.y(); + linvZ = linvel.z(); + } else + { + linvX = 0.f; + linvY = 0.f; + linvZ = 0.f; + } } void CcdPhysicsController::GetAngularVelocity(float& angVelX,float& angVelY,float& angVelZ) { - const btVector3& angvel= m_body->getAngularVelocity(); - angVelX = angvel.x(); - angVelY = angvel.y(); - angVelZ = angvel.z(); + btRigidBody* body = GetRigidBody(); + if (body) + { + const btVector3& angvel= body->getAngularVelocity(); + angVelX = angvel.x(); + angVelY = angvel.y(); + angVelZ = angvel.z(); + } else + { + angVelX = 0.f; + angVelY = 0.f; + angVelZ = 0.f; + } } void CcdPhysicsController::GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ) { btVector3 pos(posX,posY,posZ); - btVector3 rel_pos = pos-m_body->getCenterOfMassPosition(); - btVector3 linvel = m_body->getVelocityInLocalPoint(rel_pos); - linvX = linvel.x(); - linvY = linvel.y(); - linvZ = linvel.z(); + btRigidBody* body = GetRigidBody(); + if (body) + { + btVector3 linvel = body->getVelocityInLocalPoint(pos); + linvX = linvel.x(); + linvY = linvel.y(); + linvZ = linvel.z(); + } else + { + linvX = 0.f; + linvY = 0.f; + linvZ = 0.f; + } } void CcdPhysicsController::getReactionForce(float& forceX,float& forceY,float& forceZ) { @@ -565,11 +1114,15 @@ void CcdPhysicsController::setRigidBody(bool rigid) { if (!rigid) { - //fake it for now - btVector3 inertia = m_body->getInvInertiaDiagLocal(); - inertia[1] = 0.f; - m_body->setInvInertiaDiagLocal(inertia); - m_body->updateInertiaTensor(); + btRigidBody* body = GetRigidBody(); + if (body) + { + //fake it for now + btVector3 inertia = body->getInvInertiaDiagLocal(); + inertia[1] = 0.f; + body->setInvInertiaDiagLocal(inertia); + body->updateInertiaTensor(); + } } } @@ -586,40 +1139,52 @@ void CcdPhysicsController::setNewClientInfo(void* clientinfo) void CcdPhysicsController::UpdateDeactivation(float timeStep) { - m_body->updateDeactivation( timeStep); + btRigidBody* body = GetRigidBody(); + if (body) + { + body->updateDeactivation( timeStep); + } } bool CcdPhysicsController::wantsSleeping() { - - return m_body->wantsSleeping(); + btRigidBody* body = GetRigidBody(); + if (body) + { + return body->wantsSleeping(); + } + //check it out + return true; } PHY_IPhysicsController* CcdPhysicsController::GetReplica() { - //very experimental, shape sharing is not implemented yet. - //just support btSphereShape/ConeShape for now - + // This is used only to replicate Near and Radar sensor controllers + // The replication of object physics controller is done in KX_BulletPhysicsController::GetReplica() CcdConstructionInfo cinfo = m_cci; - if (cinfo.m_collisionShape) + if (m_shapeInfo) + { + // This situation does not normally happen + cinfo.m_collisionShape = m_shapeInfo->CreateBulletShape(); + } + else if (m_collisionShape) { - switch (cinfo.m_collisionShape->getShapeType()) + switch (m_collisionShape->getShapeType()) { case SPHERE_SHAPE_PROXYTYPE: { - btSphereShape* orgShape = (btSphereShape*)cinfo.m_collisionShape; + btSphereShape* orgShape = (btSphereShape*)m_collisionShape; cinfo.m_collisionShape = new btSphereShape(*orgShape); break; } - case CONE_SHAPE_PROXYTYPE: + case CONE_SHAPE_PROXYTYPE: { - btConeShape* orgShape = (btConeShape*)cinfo.m_collisionShape; + btConeShape* orgShape = (btConeShape*)m_collisionShape; cinfo.m_collisionShape = new btConeShape(*orgShape); break; } - default: { return 0; @@ -628,6 +1193,7 @@ PHY_IPhysicsController* CcdPhysicsController::GetReplica() } cinfo.m_MotionState = new DefaultMotionState(); + cinfo.m_shapeInfo = m_shapeInfo; CcdPhysicsController* replica = new CcdPhysicsController(cinfo); return replica; @@ -689,3 +1255,273 @@ void DefaultMotionState::calculateWorldTransformations() } +// Shape constructor +std::map<RAS_MeshObject*, CcdShapeConstructionInfo*> CcdShapeConstructionInfo::m_meshShapeMap; + +CcdShapeConstructionInfo* CcdShapeConstructionInfo::FindMesh(RAS_MeshObject* mesh, bool polytope) +{ + if (polytope) + // not yet supported + return NULL; + + std::map<RAS_MeshObject*,CcdShapeConstructionInfo*>::const_iterator mit = m_meshShapeMap.find(mesh); + if (mit != m_meshShapeMap.end()) + return mit->second; + return NULL; +} + +bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, bool polytope,bool useGimpact) +{ + m_useGimpact = useGimpact; + + // assume no shape information + // no support for dynamic change of shape yet + assert(m_meshObject == NULL); + m_shapeType = PHY_SHAPE_NONE; + m_vertexArray.clear(); + m_polygonIndexArray.clear(); + m_meshObject = NULL; + + if (!meshobj) + return false; + + // Mesh has no polygons! + int numpolys = meshobj->NumPolygons(); + if (!numpolys) + { + return false; + } + + // check that we have at least one colliding polygon + int numvalidpolys = 0; + + for (int p=0; p<numpolys; p++) + { + RAS_Polygon* poly = meshobj->GetPolygon(p); + + // only add polygons that have the collisionflag set + if (poly->IsCollider()) + { + numvalidpolys++; + break; + } + } + + // No collision polygons + if (numvalidpolys < 1) + return false; + + m_shapeType = (polytope) ? PHY_SHAPE_POLYTOPE : PHY_SHAPE_MESH; + + numvalidpolys = 0; + + for (int p2=0; p2<numpolys; p2++) + { + RAS_Polygon* poly = meshobj->GetPolygon(p2); + + // only add polygons that have the collisionflag set + if (poly->IsCollider()) + { + //Bullet can raycast any shape, so + if (polytope) + { + for (int i=0;i<poly->VertexCount();i++) + { + const float* vtx = poly->GetVertex(i)->getXYZ(); + btPoint3 point(vtx[0],vtx[1],vtx[2]); + //avoid duplicates (could better directly use vertex offsets, rather than a vertex compare) + bool found = false; + for (int j=0;j<m_vertexArray.size();j++) + { + if (m_vertexArray[j]==point) + { + found = true; + break; + } + } + if (!found) + m_vertexArray.push_back(point); + + numvalidpolys++; + } + } else + { + { + const float* vtx = poly->GetVertex(2)->getXYZ(); + btPoint3 vertex0(vtx[0],vtx[1],vtx[2]); + + vtx = poly->GetVertex(1)->getXYZ(); + btPoint3 vertex1(vtx[0],vtx[1],vtx[2]); + + vtx = poly->GetVertex(0)->getXYZ(); + btPoint3 vertex2(vtx[0],vtx[1],vtx[2]); + + m_vertexArray.push_back(vertex0); + m_vertexArray.push_back(vertex1); + m_vertexArray.push_back(vertex2); + m_polygonIndexArray.push_back(p2); + numvalidpolys++; + } + if (poly->VertexCount() == 4) + { + const float* vtx = poly->GetVertex(3)->getXYZ(); + btPoint3 vertex0(vtx[0],vtx[1],vtx[2]); + + vtx = poly->GetVertex(2)->getXYZ(); + btPoint3 vertex1(vtx[0],vtx[1],vtx[2]); + + vtx = poly->GetVertex(0)->getXYZ(); + btPoint3 vertex2(vtx[0],vtx[1],vtx[2]); + + m_vertexArray.push_back(vertex0); + m_vertexArray.push_back(vertex1); + m_vertexArray.push_back(vertex2); + m_polygonIndexArray.push_back(p2); + numvalidpolys++; + } + } + } + } + + if (!numvalidpolys) + { + // should not happen + m_shapeType = PHY_SHAPE_NONE; + return false; + } + m_meshObject = meshobj; + if (!polytope) + { + // triangle shape can be shared, store the mesh object in the map + m_meshShapeMap.insert(std::pair<RAS_MeshObject*,CcdShapeConstructionInfo*>(meshobj,this)); + } + return true; +} + +btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() +{ + btCollisionShape* collisionShape = 0; + btTriangleMeshShape* concaveShape = 0; + btTriangleMesh* collisionMeshData = 0; + btCompoundShape* compoundShape = 0; + CcdShapeConstructionInfo* nextShapeInfo; + + switch (m_shapeType) + { + case PHY_SHAPE_NONE: + break; + + case PHY_SHAPE_BOX: + collisionShape = new btBoxShape(m_halfExtend); + break; + + case PHY_SHAPE_SPHERE: + collisionShape = new btSphereShape(m_radius); + break; + + case PHY_SHAPE_CYLINDER: + collisionShape = new btCylinderShapeZ(m_halfExtend); + break; + + case PHY_SHAPE_CONE: + collisionShape = new btConeShapeZ(m_radius, m_height); + break; + + case PHY_SHAPE_POLYTOPE: + collisionShape = new btConvexHullShape(&m_vertexArray.begin()->getX(), m_vertexArray.size()); + break; + + case PHY_SHAPE_MESH: + // Let's use the latest btScaledBvhTriangleMeshShape: it allows true sharing of + // triangle mesh information between duplicates => drastic performance increase when + // duplicating complex mesh objects. + // BUT it causes a small performance decrease when sharing is not required: + // 9 multiplications/additions and one function call for each triangle that passes the mid phase filtering + // One possible optimization is to use directly the btBvhTriangleMeshShape when the scale is 1,1,1 + // and btScaledBvhTriangleMeshShape otherwise. + if (m_useGimpact) + { + collisionMeshData = new btTriangleMesh(); + + + // m_vertexArray is necessarily a multiple of 3 + for (std::vector<btPoint3>::iterator it=m_vertexArray.begin(); it != m_vertexArray.end(); ) + { + collisionMeshData->addTriangle(*it++,*it++,*it++); + } + btGImpactMeshShape* gimpactShape = new btGImpactMeshShape(collisionMeshData); + + collisionShape = gimpactShape; + gimpactShape->updateBound(); + + } else + { + if (!m_unscaledShape) + { + collisionMeshData = new btTriangleMesh(true,false); + collisionMeshData->m_weldingThreshold = m_weldingThreshold; + + // m_vertexArray is necessarily a multiple of 3 + for (std::vector<btPoint3>::iterator it=m_vertexArray.begin(); it != m_vertexArray.end(); ) + { + collisionMeshData->addTriangle(*it++,*it++,*it++); + } + // this shape will be shared and not deleted until shapeInfo is deleted + m_unscaledShape = new btBvhTriangleMeshShape( collisionMeshData, true ); + m_unscaledShape->recalcLocalAabb(); + } + collisionShape = new btScaledBvhTriangleMeshShape(m_unscaledShape, btVector3(1.0f,1.0f,1.0f)); + } + break; + + case PHY_SHAPE_COMPOUND: + if (m_shapeArray.size() > 0) + { + compoundShape = new btCompoundShape(); + for (std::vector<CcdShapeConstructionInfo*>::iterator sit = m_shapeArray.begin(); + sit != m_shapeArray.end(); + sit++) + { + collisionShape = (*sit)->CreateBulletShape(); + if (collisionShape) + { + collisionShape->setLocalScaling((*sit)->m_childScale); + compoundShape->addChildShape((*sit)->m_childTrans, collisionShape); + } + } + collisionShape = compoundShape; + } + } + return collisionShape; +} + +void CcdShapeConstructionInfo::AddShape(CcdShapeConstructionInfo* shapeInfo) +{ + m_shapeArray.push_back(shapeInfo); +} + +CcdShapeConstructionInfo::~CcdShapeConstructionInfo() +{ + for (std::vector<CcdShapeConstructionInfo*>::iterator sit = m_shapeArray.begin(); + sit != m_shapeArray.end(); + sit++) + { + (*sit)->Release(); + } + m_shapeArray.clear(); + if (m_unscaledShape) + { + DeleteBulletShape(m_unscaledShape); + } + m_vertexArray.clear(); + if (m_shapeType == PHY_SHAPE_MESH && m_meshObject != NULL) + { + std::map<RAS_MeshObject*,CcdShapeConstructionInfo*>::iterator mit = m_meshShapeMap.find(m_meshObject); + if (mit != m_meshShapeMap.end() && mit->second == this) + { + m_meshShapeMap.erase(mit); + } + } +} + + diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 448e5622eff..054ec91122a 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -17,11 +17,15 @@ subject to the following restrictions: #ifndef BULLET2_PHYSICSCONTROLLER_H #define BULLET2_PHYSICSCONTROLLER_H +#include <vector> +#include <map> + #include "PHY_IPhysicsController.h" /// PHY_IPhysicsController is the abstract simplified Interface to a physical object. /// It contains the IMotionState and IDeformableMesh Interfaces. #include "btBulletDynamicsCommon.h" +#include "LinearMath/btTransform.h" #include "PHY_IMotionState.h" @@ -31,8 +35,119 @@ extern float gAngularSleepingTreshold; extern bool gDisableDeactivation; class CcdPhysicsEnvironment; class btMotionState; +class RAS_MeshObject; +class btCollisionShape; + + +#define CCD_BSB_SHAPE_MATCHING 2 +#define CCD_BSB_BENDING_CONSTRAINTS 8 +#define CCD_BSB_AERO_VPOINT 16 /* aero model, Vertex normals are oriented toward velocity*/ +#define CCD_BSB_AERO_VTWOSIDE 32 /* aero model, Vertex normals are flipped to match velocity */ + +/* BulletSoftBody.collisionflags */ +#define CCD_BSB_COL_SDF_RS 2 /* SDF based rigid vs soft */ +#define CCD_BSB_COL_CL_RS 4 /* Cluster based rigid vs soft */ +#define CCD_BSB_COL_CL_SS 8 /* Cluster based soft vs soft */ +#define CCD_BSB_COL_VF_SS 16 /* Vertex/Face based soft vs soft */ + + + +// Shape contructor +// It contains all the information needed to create a simple bullet shape at runtime +class CcdShapeConstructionInfo +{ +public: + + + static CcdShapeConstructionInfo* FindMesh(RAS_MeshObject* mesh, bool polytope); + + CcdShapeConstructionInfo() : + m_shapeType(PHY_SHAPE_NONE), + m_radius(1.0), + m_height(1.0), + m_halfExtend(0.f,0.f,0.f), + m_childScale(1.0f,1.0f,1.0f), + m_refCount(1), + m_meshObject(NULL), + m_unscaledShape(NULL), + m_useGimpact(false), + m_weldingThreshold(0.f) + { + m_childTrans.setIdentity(); + } + + ~CcdShapeConstructionInfo(); + + CcdShapeConstructionInfo* AddRef() + { + m_refCount++; + return this; + } + + int Release() + { + if (--m_refCount > 0) + return m_refCount; + delete this; + return 0; + } + + void AddShape(CcdShapeConstructionInfo* shapeInfo); + + btTriangleMeshShape* GetMeshShape(void) + { + return m_unscaledShape; + } + CcdShapeConstructionInfo* GetChildShape(int i) + { + if (i < 0 || i >= m_shapeArray.size()) + return NULL; + + return m_shapeArray.at(i); + } + bool SetMesh(RAS_MeshObject* mesh, bool polytope,bool useGimpact); + RAS_MeshObject* GetMesh(void) + { + return m_meshObject; + } + + btCollisionShape* CreateBulletShape(); + + // member variables + PHY_ShapeType m_shapeType; + btScalar m_radius; + btScalar m_height; + btVector3 m_halfExtend; + btTransform m_childTrans; + btVector3 m_childScale; + std::vector<btPoint3> m_vertexArray; // Contains both vertex array for polytope shape and + // triangle array for concave mesh shape. + // In this case a triangle is made of 3 consecutive points + std::vector<int> m_polygonIndexArray; // Contains the array of polygon index in the + // original mesh that correspond to shape triangles. + // only set for concave mesh shape. + + void setVertexWeldingThreshold(float threshold) + { + m_weldingThreshold = threshold; + } + float getVertexWeldingThreshold() const + { + return m_weldingThreshold; + } +protected: + static std::map<RAS_MeshObject*, CcdShapeConstructionInfo*> m_meshShapeMap; + int m_refCount; // this class is shared between replicas + // keep track of users so that we can release it + RAS_MeshObject* m_meshObject; // Keep a pointer to the original mesh + btBvhTriangleMeshShape* m_unscaledShape;// holds the shared unscale BVH mesh shape, + // the actual shape is of type btScaledBvhTriangleMeshShape + std::vector<CcdShapeConstructionInfo*> m_shapeArray; // for compound shapes + bool m_useGimpact; //use gimpact for concave dynamic/moving collision detection + float m_weldingThreshold; //welding closeby vertices together can improve softbody stability etc. +}; struct CcdConstructionInfo { @@ -52,21 +167,28 @@ struct CcdConstructionInfo CcdConstructionInfo() - : m_gravity(0,0,0), + : m_localInertiaTensor(1.f, 1.f, 1.f), + m_gravity(0,0,0), m_scaling(1.f,1.f,1.f), m_mass(0.f), m_restitution(0.1f), m_friction(0.5f), m_linearDamping(0.1f), m_angularDamping(0.1f), + m_margin(0.06f), + m_gamesoftFlag(0), m_collisionFlags(0), m_bRigid(false), + m_bSoft(false), m_collisionFilterGroup(DefaultFilter), m_collisionFilterMask(AllFilter), m_collisionShape(0), m_MotionState(0), + m_shapeInfo(0), m_physicsEnv(0), - m_inertiaFactor(1.f) + m_inertiaFactor(1.f), + m_do_anisotropic(false), + m_anisotropicFriction(1.f,1.f,1.f) { } @@ -78,8 +200,50 @@ struct CcdConstructionInfo btScalar m_friction; btScalar m_linearDamping; btScalar m_angularDamping; + btScalar m_margin; + + //////////////////// + int m_gamesoftFlag; + float m_soft_linStiff; /* linear stiffness 0..1 */ + float m_soft_angStiff; /* angular stiffness 0..1 */ + float m_soft_volume; /* volume preservation 0..1 */ + + int m_soft_viterations; /* Velocities solver iterations */ + int m_soft_piterations; /* Positions solver iterations */ + int m_soft_diterations; /* Drift solver iterations */ + int m_soft_citerations; /* Cluster solver iterations */ + + float m_soft_kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */ + float m_soft_kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */ + float m_soft_kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */ + float m_soft_kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + + float m_soft_kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + float m_soft_kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + float m_soft_kVCF; /* Velocities correction factor (Baumgarte) */ + float m_soft_kDP; /* Damping coefficient [0,1] */ + + float m_soft_kDG; /* Drag coefficient [0,+inf] */ + float m_soft_kLF; /* Lift coefficient [0,+inf] */ + float m_soft_kPR; /* Pressure coefficient [-inf,+inf] */ + float m_soft_kVC; /* Volume conversation coefficient [0,+inf] */ + + float m_soft_kDF; /* Dynamic friction coefficient [0,1] */ + float m_soft_kMT; /* Pose matching coefficient [0,1] */ + float m_soft_kCHR; /* Rigid contacts hardness [0,1] */ + float m_soft_kKHR; /* Kinetic contacts hardness [0,1] */ + + float m_soft_kSHR; /* Soft contacts hardness [0,1] */ + float m_soft_kAHR; /* Anchors hardness [0,1] */ + int m_soft_collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */ + int m_soft_numclusteriterations; /* number of iterations to refine collision clusters*/ +/////////////////// + + + int m_collisionFlags; bool m_bRigid; + bool m_bSoft; ///optional use of collision group/mask: ///only collision with object goups that match the collision mask. @@ -89,29 +253,59 @@ struct CcdConstructionInfo short int m_collisionFilterGroup; short int m_collisionFilterMask; + ///these pointers are used as argument passing for the CcdPhysicsController constructor + ///and not anymore after that class btCollisionShape* m_collisionShape; class PHY_IMotionState* m_MotionState; + class CcdShapeConstructionInfo* m_shapeInfo; CcdPhysicsEnvironment* m_physicsEnv; //needed for self-replication float m_inertiaFactor;//tweak the inertia (hooked up to Blender 'formfactor' + bool m_do_anisotropic; + btVector3 m_anisotropicFriction; + + bool m_do_fh; ///< Should the object have a linear Fh spring? + bool m_do_rot_fh; ///< Should the object have an angular Fh spring? + btScalar m_fh_spring; ///< Spring constant (both linear and angular) + btScalar m_fh_damping; ///< Damping factor (linear and angular) in range [0, 1] + btScalar m_fh_distance; ///< The range above the surface where Fh is active. + bool m_fh_normal; ///< Should the object slide off slopes? + float m_radius;//for fh backwards compatibility + }; class btRigidBody; - +class btCollisionObject; +class btSoftBody; ///CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution. class CcdPhysicsController : public PHY_IPhysicsController { - btRigidBody* m_body; + + btCollisionObject* m_object; + + class PHY_IMotionState* m_MotionState; btMotionState* m_bulletMotionState; + class btCollisionShape* m_collisionShape; + class CcdShapeConstructionInfo* m_shapeInfo; + friend class CcdPhysicsEnvironment; // needed when updating the controller + //some book keeping for replication + bool m_softbodyMappingDone; + bool m_softBodyTransformInitialized; + bool m_prototypeTransformInitialized; + btTransform m_softbodyStartTrans; + void* m_newClientInfo; int m_registerCount; // needed when multiple sensors use the same controller CcdConstructionInfo m_cci;//needed for replication + + CcdPhysicsController* m_parentCtrl; + void GetWorldOrientation(btMatrix3x3& mat); void CreateRigidbody(); @@ -135,11 +329,24 @@ class CcdPhysicsController : public PHY_IPhysicsController virtual ~CcdPhysicsController(); + CcdConstructionInfo& getConstructionInfo() + { + return m_cci; + } + const CcdConstructionInfo& getConstructionInfo() const + { + return m_cci; + } + + + btRigidBody* GetRigidBody(); + btCollisionObject* GetCollisionObject(); + btSoftBody* GetSoftBody(); - btRigidBody* GetRigidBody() { return m_body;} + CcdShapeConstructionInfo* GetShapeInfo() { return m_shapeInfo; } btCollisionShape* GetCollisionShape() { - return m_body->getCollisionShape(); + return m_object->getCollisionShape(); } //////////////////////////////////// // PHY_IPhysicsController interface @@ -206,14 +413,37 @@ class CcdPhysicsController : public PHY_IPhysicsController } virtual void calcXform() {} ; - virtual void SetMargin(float margin) {}; - virtual float GetMargin() const {return 0.f;}; + virtual void SetMargin(float margin) + { + if (m_collisionShape) + m_collisionShape->setMargin(btScalar(margin)); + } + virtual float GetMargin() const + { + return (m_collisionShape) ? m_collisionShape->getMargin() : 0.f; + } + virtual float GetRadius() const + { + // this is not the actual shape radius, it's only used for Fh support + return m_cci.m_radius; + } + virtual void SetRadius(float margin) + { + if (m_collisionShape && m_collisionShape->getShapeType() == SPHERE_SHAPE_PROXYTYPE) + { + btSphereShape* sphereShape = static_cast<btSphereShape*>(m_collisionShape); + sphereShape->setUnscaledRadius(margin); + } + m_cci.m_radius = margin; + } bool wantsSleeping(); void UpdateDeactivation(float timeStep); + void SetCenterOfMassTransform(btTransform& xform); + static btTransform GetTransformFromMotionState(PHY_IMotionState* motionState); void setAabb(const btVector3& aabbMin,const btVector3& aabbMax); @@ -233,6 +463,23 @@ class CcdPhysicsController : public PHY_IPhysicsController { return m_cci.m_physicsEnv; } + + void setParentCtrl(CcdPhysicsController* parentCtrl) + { + m_parentCtrl = parentCtrl; + } + + CcdPhysicsController* getParentCtrl() + { + return m_parentCtrl; + } + + const CcdPhysicsController* getParentCtrl() const + { + return m_parentCtrl; + } + + }; diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index dfbcf115fd7..91655e96101 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -23,6 +23,9 @@ subject to the following restrictions: #include "btBulletDynamicsCommon.h" #include "LinearMath/btIDebugDraw.h" #include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h" +#include "BulletSoftBody/btSoftRigidDynamicsWorld.h" +#include "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h" +#include "BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h" //profiling/timings #include "LinearMath/btQuickprof.h" @@ -53,6 +56,7 @@ void DrawRasterizerLine(const float* from,const float* to,int color); #include <stdio.h> +#include <string.h> // for memset #ifdef NEW_BULLET_VEHICLE_SUPPORT class WrapperVehicle : public PHY_IVehicle @@ -329,30 +333,29 @@ m_filterCallback(NULL) { m_triggerCallbacks[i] = 0; } + +// m_collisionConfiguration = new btDefaultCollisionConfiguration(); + m_collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration(); + if (!dispatcher) { - dispatcher = new btCollisionDispatcher(); + btCollisionDispatcher* disp = new btCollisionDispatcher(m_collisionConfiguration); + dispatcher = disp; + btGImpactCollisionAlgorithm::registerAlgorithm(disp); m_ownDispatcher = dispatcher; } - if(!pairCache) - { - - //todo: calculate/let user specify this world sizes - btVector3 worldMin(-10000,-10000,-10000); - btVector3 worldMax(10000,10000,10000); - - pairCache = new btAxisSweep3(worldMin,worldMax); - // remember that this was allocated by us so that we can release it - m_ownPairCache = pairCache; - //broadphase = new btSimpleBroadphase(); - } + //m_broadphase = new btAxisSweep3(btVector3(-1000,-1000,-1000),btVector3(1000,1000,1000)); + //m_broadphase = new btSimpleBroadphase(); + m_broadphase = new btDbvtBroadphase(); m_filterCallback = new CcdOverlapFilterCallBack(this); - pairCache->setOverlapFilterCallback(m_filterCallback); + m_broadphase->getOverlappingPairCache()->setOverlapFilterCallback(m_filterCallback); setSolverType(1);//issues with quickstep and memory allocations - m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,pairCache,m_solver); +// m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,m_broadphase,m_solver,m_collisionConfiguration); + m_dynamicsWorld = new btSoftRigidDynamicsWorld(dispatcher,m_broadphase,m_solver,m_collisionConfiguration); + m_debugDrawer = 0; m_gravity = btVector3(0.f,-10.f,0.f); m_dynamicsWorld->setGravity(m_gravity); @@ -363,24 +366,42 @@ m_filterCallback(NULL) void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl) { btRigidBody* body = ctrl->GetRigidBody(); + btCollisionObject* obj = ctrl->GetCollisionObject(); //this m_userPointer is just used for triggers, see CallbackTriggers - body->setUserPointer(ctrl); + obj->setUserPointer(ctrl); + if (body) + body->setGravity( m_gravity ); - body->setGravity( m_gravity ); m_controllers.insert(ctrl); - //use explicit group/filter for finer control over collision in bullet => near/radar sensor - m_dynamicsWorld->addRigidBody(body, ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask()); - if (body->isStaticOrKinematicObject()) + if (body) + { + //use explicit group/filter for finer control over collision in bullet => near/radar sensor + m_dynamicsWorld->addRigidBody(body, ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask()); + } else + { + if (ctrl->GetSoftBody()) + { + btSoftBody* softBody = ctrl->GetSoftBody(); + m_dynamicsWorld->addSoftBody(softBody); + } else + { + if (obj->getCollisionShape()) + { + m_dynamicsWorld->addCollisionObject(obj,ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask()); + } + } + } + if (obj->isStaticOrKinematicObject()) { - body->setActivationState(ISLAND_SLEEPING); + obj->setActivationState(ISLAND_SLEEPING); } //CollisionObject(body,ctrl->GetCollisionFilterGroup(),ctrl->GetCollisionFilterMask()); - assert(body->getBroadphaseHandle()); + assert(obj->getBroadphaseHandle()); btBroadphaseInterface* scene = getBroadphase(); @@ -389,7 +410,7 @@ void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl) assert(shapeinterface); - const btTransform& t = ctrl->GetRigidBody()->getCenterOfMassTransform(); + const btTransform& t = ctrl->GetCollisionObject()->getWorldTransform(); btPoint3 minAabb,maxAabb; @@ -401,42 +422,59 @@ void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl) //extent it with the motion - btVector3 linMotion = body->getLinearVelocity()*timeStep; - - float maxAabbx = maxAabb.getX(); - float maxAabby = maxAabb.getY(); - float maxAabbz = maxAabb.getZ(); - float minAabbx = minAabb.getX(); - float minAabby = minAabb.getY(); - float minAabbz = minAabb.getZ(); - - if (linMotion.x() > 0.f) - maxAabbx += linMotion.x(); - else - minAabbx += linMotion.x(); - if (linMotion.y() > 0.f) - maxAabby += linMotion.y(); - else - minAabby += linMotion.y(); - if (linMotion.z() > 0.f) - maxAabbz += linMotion.z(); - else - minAabbz += linMotion.z(); - - - minAabb = btVector3(minAabbx,minAabby,minAabbz); - maxAabb = btVector3(maxAabbx,maxAabby,maxAabbz); - + if (body) + { + btVector3 linMotion = body->getLinearVelocity()*timeStep; + + float maxAabbx = maxAabb.getX(); + float maxAabby = maxAabb.getY(); + float maxAabbz = maxAabb.getZ(); + float minAabbx = minAabb.getX(); + float minAabby = minAabb.getY(); + float minAabbz = minAabb.getZ(); + + if (linMotion.x() > 0.f) + maxAabbx += linMotion.x(); + else + minAabbx += linMotion.x(); + if (linMotion.y() > 0.f) + maxAabby += linMotion.y(); + else + minAabby += linMotion.y(); + if (linMotion.z() > 0.f) + maxAabbz += linMotion.z(); + else + minAabbz += linMotion.z(); + + + minAabb = btVector3(minAabbx,minAabby,minAabbz); + maxAabb = btVector3(maxAabbx,maxAabby,maxAabbz); + } } + + void CcdPhysicsEnvironment::removeCcdPhysicsController(CcdPhysicsController* ctrl) { //also remove constraint - - m_dynamicsWorld->removeRigidBody(ctrl->GetRigidBody()); + btRigidBody* body = ctrl->GetRigidBody(); + if (body) + { + m_dynamicsWorld->removeRigidBody(ctrl->GetRigidBody()); + } else + { + //if a softbody + if (ctrl->GetSoftBody()) + { + m_dynamicsWorld->removeSoftBody(ctrl->GetSoftBody()); + } else + { + m_dynamicsWorld->removeCollisionObject(ctrl->GetCollisionObject()); + } + } m_controllers.erase(ctrl); if (ctrl->m_registerCount != 0) @@ -451,13 +489,20 @@ void CcdPhysicsEnvironment::updateCcdPhysicsController(CcdPhysicsController* ctr // this function is used when the collisionning group of a controller is changed // remove and add the collistioning object btRigidBody* body = ctrl->GetRigidBody(); - btVector3 inertia; - - m_dynamicsWorld->removeCollisionObject(body); - body->setCollisionFlags(newCollisionFlags); - body->getCollisionShape()->calculateLocalInertia(newMass, inertia); - body->setMassProps(newMass, inertia); - m_dynamicsWorld->addCollisionObject(body, newCollisionGroup, newCollisionMask); + btCollisionObject* obj = ctrl->GetCollisionObject(); + if (obj) + { + btVector3 inertia(0.0,0.0,0.0); + m_dynamicsWorld->removeCollisionObject(obj); + obj->setCollisionFlags(newCollisionFlags); + if (body) + { + if (newMass) + body->getCollisionShape()->calculateLocalInertia(newMass, inertia); + body->setMassProps(newMass, inertia); + } + m_dynamicsWorld->addCollisionObject(obj, newCollisionGroup, newCollisionMask); + } // to avoid nasty interaction, we must update the property of the controller as well ctrl->m_cci.m_mass = newMass; ctrl->m_cci.m_collisionFilterGroup = newCollisionGroup; @@ -469,9 +514,9 @@ void CcdPhysicsEnvironment::enableCcdPhysicsController(CcdPhysicsController* ctr { if (m_controllers.insert(ctrl).second) { - btRigidBody* body = ctrl->GetRigidBody(); - body->setUserPointer(ctrl); - m_dynamicsWorld->addCollisionObject(body, + btCollisionObject* obj = ctrl->GetCollisionObject(); + obj->setUserPointer(ctrl); + m_dynamicsWorld->addCollisionObject(obj, ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask()); } } @@ -480,7 +525,19 @@ void CcdPhysicsEnvironment::disableCcdPhysicsController(CcdPhysicsController* ct { if (m_controllers.erase(ctrl)) { - m_dynamicsWorld->removeRigidBody(ctrl->GetRigidBody()); + btRigidBody* body = ctrl->GetRigidBody(); + if (body) + { + m_dynamicsWorld->removeRigidBody(body); + } else + { + if (ctrl->GetSoftBody()) + { + } else + { + m_dynamicsWorld->removeCollisionObject(body); + } + } } } @@ -501,10 +558,18 @@ bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep) (*it)->SynchronizeMotionStates(timeStep); } + processFhSprings(curTime,timeStep); + float subStep = timeStep / float(m_numTimeSubSteps); for (i=0;i<m_numTimeSubSteps;i++) { - m_dynamicsWorld->stepSimulation(subStep,0);//perform always a full simulation step +// m_dynamicsWorld->stepSimulation(subStep,20,1./240.);//perform always a full simulation step + m_dynamicsWorld->stepSimulation(subStep,0);//perform always a full simulation step + } + + for (it=m_controllers.begin(); it!=m_controllers.end(); it++) + { + (*it)->SynchronizeMotionStates(timeStep); } for (it=m_controllers.begin(); it!=m_controllers.end(); it++) @@ -518,11 +583,181 @@ bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep) veh->SyncWheels(); } + if (m_dynamicsWorld->getDebugDrawer() && m_dynamicsWorld->getDebugDrawer()->getDebugMode() >0) + m_dynamicsWorld->debugDrawWorld(); + + CallbackTriggers(); return true; } +class ClosestRayResultCallbackNotMe : public btCollisionWorld::ClosestRayResultCallback +{ + btCollisionObject* m_owner; + btCollisionObject* m_parent; + +public: + ClosestRayResultCallbackNotMe(const btVector3& rayFromWorld,const btVector3& rayToWorld,btCollisionObject* owner,btCollisionObject* parent) + :btCollisionWorld::ClosestRayResultCallback(rayFromWorld,rayToWorld), + m_owner(owner) + { + + } + + virtual bool needsCollision(btBroadphaseProxy* proxy0) const + { + //don't collide with self + if (proxy0->m_clientObject == m_owner) + return false; + + if (proxy0->m_clientObject == m_parent) + return false; + + return btCollisionWorld::ClosestRayResultCallback::needsCollision(proxy0); + } + +}; + +void CcdPhysicsEnvironment::processFhSprings(double curTime,float timeStep) +{ + std::set<CcdPhysicsController*>::iterator it; + + for (it=m_controllers.begin(); it!=m_controllers.end(); it++) + { + CcdPhysicsController* ctrl = (*it); + btRigidBody* body = ctrl->GetRigidBody(); + + if (body && (ctrl->getConstructionInfo().m_do_fh || ctrl->getConstructionInfo().m_do_rot_fh)) + { + //printf("has Fh or RotFh\n"); + //re-implement SM_FhObject.cpp using btCollisionWorld::rayTest and info from ctrl->getConstructionInfo() + //send a ray from {0.0, 0.0, 0.0} towards {0.0, 0.0, -10.0}, in local coordinates + + + CcdPhysicsController* parentCtrl = ctrl->getParentCtrl(); + btRigidBody* parentBody = parentCtrl?parentCtrl->GetRigidBody() : 0; + btRigidBody* cl_object = parentBody ? parentBody : body; + + if (body->isStaticOrKinematicObject()) + continue; + + btVector3 rayDirLocal(0,0,-10); + + //m_dynamicsWorld + //ctrl->GetRigidBody(); + btVector3 rayFromWorld = body->getCenterOfMassPosition(); + //btVector3 rayToWorld = rayFromWorld + body->getCenterOfMassTransform().getBasis() * rayDirLocal; + //ray always points down the z axis in world space... + btVector3 rayToWorld = rayFromWorld + rayDirLocal; + + ClosestRayResultCallbackNotMe resultCallback(rayFromWorld,rayToWorld,body,parentBody); + + m_dynamicsWorld->rayTest(rayFromWorld,rayToWorld,resultCallback); + if (resultCallback.hasHit()) + { + //we hit this one: resultCallback.m_collisionObject; + CcdPhysicsController* controller = static_cast<CcdPhysicsController*>(resultCallback.m_collisionObject->getUserPointer()); + + if (controller) + { + if (controller->getConstructionInfo().m_fh_distance < SIMD_EPSILON) + continue; + + btRigidBody* hit_object = controller->GetRigidBody(); + if (!hit_object) + continue; + + CcdConstructionInfo& hitObjShapeProps = controller->getConstructionInfo(); + + float distance = resultCallback.m_closestHitFraction*rayDirLocal.length()-ctrl->getConstructionInfo().m_radius; + if (distance >= hitObjShapeProps.m_fh_distance) + continue; + + + + //btVector3 ray_dir = cl_object->getCenterOfMassTransform().getBasis()* rayDirLocal.normalized(); + btVector3 ray_dir = rayDirLocal.normalized(); + btVector3 normal = resultCallback.m_hitNormalWorld; + normal.normalize(); + + + if (ctrl->getConstructionInfo().m_do_fh) + { + btVector3 lspot = cl_object->getCenterOfMassPosition() + + rayDirLocal * resultCallback.m_closestHitFraction; + + + + + lspot -= hit_object->getCenterOfMassPosition(); + btVector3 rel_vel = cl_object->getLinearVelocity() - hit_object->getVelocityInLocalPoint(lspot); + btScalar rel_vel_ray = ray_dir.dot(rel_vel); + btScalar spring_extent = 1.0 - distance / hitObjShapeProps.m_fh_distance; + + btScalar i_spring = spring_extent * hitObjShapeProps.m_fh_spring; + btScalar i_damp = rel_vel_ray * hitObjShapeProps.m_fh_damping; + + cl_object->setLinearVelocity(cl_object->getLinearVelocity() + (-(i_spring + i_damp) * ray_dir)); + if (hitObjShapeProps.m_fh_normal) + { + cl_object->setLinearVelocity(cl_object->getLinearVelocity()+(i_spring + i_damp) *(normal - normal.dot(ray_dir) * ray_dir)); + } + + btVector3 lateral = rel_vel - rel_vel_ray * ray_dir; + + + if (ctrl->getConstructionInfo().m_do_anisotropic) { + //Bullet basis contains no scaling/shear etc. + const btMatrix3x3& lcs = cl_object->getCenterOfMassTransform().getBasis(); + btVector3 loc_lateral = lateral * lcs; + const btVector3& friction_scaling = cl_object->getAnisotropicFriction(); + loc_lateral *= friction_scaling; + lateral = lcs * loc_lateral; + } + + btScalar rel_vel_lateral = lateral.length(); + + if (rel_vel_lateral > SIMD_EPSILON) { + btScalar friction_factor = hit_object->getFriction();//cl_object->getFriction(); + + btScalar max_friction = friction_factor * btMax(btScalar(0.0), i_spring); + + btScalar rel_mom_lateral = rel_vel_lateral / cl_object->getInvMass(); + + btVector3 friction = (rel_mom_lateral > max_friction) ? + -lateral * (max_friction / rel_vel_lateral) : + -lateral; + + cl_object->applyCentralImpulse(friction); + } + } + + + if (ctrl->getConstructionInfo().m_do_rot_fh) { + btVector3 up2 = cl_object->getWorldTransform().getBasis().getColumn(2); + + btVector3 t_spring = up2.cross(normal) * hitObjShapeProps.m_fh_spring; + btVector3 ang_vel = cl_object->getAngularVelocity(); + + // only rotations that tilt relative to the normal are damped + ang_vel -= ang_vel.dot(normal) * normal; + + btVector3 t_damp = ang_vel * hitObjShapeProps.m_fh_damping; + + cl_object->setAngularVelocity(cl_object->getAngularVelocity() + (t_spring - t_damp)); + } + + } + + + } + + + } + } + +} void CcdPhysicsEnvironment::setDebugMode(int debugMode) { @@ -578,7 +813,7 @@ void CcdPhysicsEnvironment::setSolverDamping(float damping) void CcdPhysicsEnvironment::setLinearAirDamping(float damping) { - gLinearAirDamping = damping; + //gLinearAirDamping = damping; } void CcdPhysicsEnvironment::setUseEpa(bool epa) @@ -597,7 +832,7 @@ void CcdPhysicsEnvironment::setSolverType(int solverType) { m_solver = new btSequentialImpulseConstraintSolver(); - ((btSequentialImpulseConstraintSolver*)m_solver)->setSolverMode(btSequentialImpulseConstraintSolver::SOLVER_USE_WARMSTARTING | btSequentialImpulseConstraintSolver::SOLVER_RANDMIZE_ORDER); +// ((btSequentialImpulseConstraintSolver*)m_solver)->setSolverMode(btSequentialImpulseConstraintSolver::SOLVER_USE_WARMSTARTING | btSequentialImpulseConstraintSolver::SOLVER_RANDMIZE_ORDER); break; } } @@ -618,7 +853,13 @@ void CcdPhysicsEnvironment::setSolverType(int solverType) - +void CcdPhysicsEnvironment::getGravity(PHY__Vector3& grav) +{ + const btVector3& gravity = m_dynamicsWorld->getGravity(); + grav[0] = gravity.getX(); + grav[1] = gravity.getY(); + grav[2] = gravity.getZ(); +} void CcdPhysicsEnvironment::setGravity(float x,float y,float z) @@ -659,9 +900,10 @@ int CcdPhysicsEnvironment::createUniversalD6Constraint( { + bool useReferenceFrameA = true; genericConstraint = new btGeneric6DofConstraint( *rb0,*rb1, - frameInA,frameInB); + frameInA,frameInB,useReferenceFrameA); genericConstraint->setLinearLowerLimit(linearMinLimits); genericConstraint->setLinearUpperLimit(linearMaxLimits); genericConstraint->setAngularLowerLimit(angularMinLimits); @@ -709,35 +951,54 @@ void CcdPhysicsEnvironment::removeConstraint(int constraintId) struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { - PHY_IPhysicsController* m_ignoreClient; + PHY_IRayCastFilterCallback& m_phyRayFilter; + const btCollisionShape* m_hitTriangleShape; + int m_hitTriangleIndex; - FilterClosestRayResultCallback (PHY_IPhysicsController* ignoreClient,const btVector3& rayFrom,const btVector3& rayTo) + FilterClosestRayResultCallback (PHY_IRayCastFilterCallback& phyRayFilter,const btVector3& rayFrom,const btVector3& rayTo) : btCollisionWorld::ClosestRayResultCallback(rayFrom,rayTo), - m_ignoreClient(ignoreClient) + m_phyRayFilter(phyRayFilter), + m_hitTriangleShape(NULL), + m_hitTriangleIndex(0) { - } virtual ~FilterClosestRayResultCallback() { } - virtual float AddSingleResult( btCollisionWorld::LocalRayResult& rayResult) + virtual bool needsCollision(btBroadphaseProxy* proxy0) const + { + if (!(proxy0->m_collisionFilterGroup & m_collisionFilterMask)) + return false; + if (!(m_collisionFilterGroup & proxy0->m_collisionFilterMask)) + return false; + btCollisionObject* object = (btCollisionObject*)proxy0->m_clientObject; + CcdPhysicsController* phyCtrl = static_cast<CcdPhysicsController*>(object->getUserPointer()); + if (phyCtrl == m_phyRayFilter.m_ignoreController) + return false; + return m_phyRayFilter.needBroadphaseRayCast(phyCtrl); + } + + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { CcdPhysicsController* curHit = static_cast<CcdPhysicsController*>(rayResult.m_collisionObject->getUserPointer()); - //ignore client... - if (curHit != m_ignoreClient) - { - //if valid - return ClosestRayResultCallback::AddSingleResult(rayResult); + // save shape information as ClosestRayResultCallback::AddSingleResult() does not do it + if (rayResult.m_localShapeInfo) + { + m_hitTriangleShape = rayResult.m_collisionObject->getCollisionShape(); + m_hitTriangleIndex = rayResult.m_localShapeInfo->m_triangleIndex; + } else + { + m_hitTriangleShape = NULL; + m_hitTriangleIndex = 0; } - return m_closestHitFraction; + return ClosestRayResultCallback::addSingleResult(rayResult,normalInWorldSpace); } }; -PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IPhysicsController* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ) +PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ) { @@ -751,19 +1012,101 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IPhysicsController* i //Either Ray Cast with or without filtering //btCollisionWorld::ClosestRayResultCallback rayCallback(rayFrom,rayTo); - FilterClosestRayResultCallback rayCallback(ignoreClient,rayFrom,rayTo); + FilterClosestRayResultCallback rayCallback(filterCallback,rayFrom,rayTo); + + PHY_RayCastResult result; + memset(&result, 0, sizeof(result)); - PHY_IPhysicsController* nearestHit = 0; // don't collision with sensor object - m_dynamicsWorld->rayTest(rayFrom,rayTo,rayCallback, CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter); - if (rayCallback.HasHit()) + rayCallback.m_collisionFilterMask = CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter; + //, ,filterCallback.m_faceNormal); + + m_dynamicsWorld->rayTest(rayFrom,rayTo,rayCallback); + if (rayCallback.hasHit()) { - nearestHit = static_cast<CcdPhysicsController*>(rayCallback.m_collisionObject->getUserPointer()); - hitX = rayCallback.m_hitPointWorld.getX(); - hitY = rayCallback.m_hitPointWorld.getY(); - hitZ = rayCallback.m_hitPointWorld.getZ(); + CcdPhysicsController* controller = static_cast<CcdPhysicsController*>(rayCallback.m_collisionObject->getUserPointer()); + result.m_controller = controller; + result.m_hitPoint[0] = rayCallback.m_hitPointWorld.getX(); + result.m_hitPoint[1] = rayCallback.m_hitPointWorld.getY(); + result.m_hitPoint[2] = rayCallback.m_hitPointWorld.getZ(); + + if (rayCallback.m_hitTriangleShape != NULL) + { + // identify the mesh polygon + CcdShapeConstructionInfo* shapeInfo = controller->m_shapeInfo; + if (shapeInfo) + { + btCollisionShape* shape = controller->GetCollisionObject()->getCollisionShape(); + if (shape->isCompound()) + { + btCompoundShape* compoundShape = (btCompoundShape*)shape; + CcdShapeConstructionInfo* compoundShapeInfo = shapeInfo; + // need to search which sub-shape has been hit + for (int i=0; i<compoundShape->getNumChildShapes(); i++) + { + shapeInfo = compoundShapeInfo->GetChildShape(i); + shape=compoundShape->getChildShape(i); + if (shape == rayCallback.m_hitTriangleShape) + break; + } + } + if (shape == rayCallback.m_hitTriangleShape && + rayCallback.m_hitTriangleIndex < shapeInfo->m_polygonIndexArray.size()) + { + result.m_meshObject = shapeInfo->GetMesh(); + result.m_polygon = shapeInfo->m_polygonIndexArray.at(rayCallback.m_hitTriangleIndex); + // Bullet returns the normal from "outside". + // If the user requests the real normal, compute it now + if (filterCallback.m_faceNormal) + { + // mesh shapes are shared and stored in the shapeInfo + btTriangleMeshShape* triangleShape = shapeInfo->GetMeshShape(); + if (triangleShape) + { + // this code is copied from Bullet + btVector3 triangle[3]; + const unsigned char *vertexbase; + int numverts; + PHY_ScalarType type; + int stride; + const unsigned char *indexbase; + int indexstride; + int numfaces; + PHY_ScalarType indicestype; + btStridingMeshInterface* meshInterface = triangleShape->getMeshInterface(); + + meshInterface->getLockedReadOnlyVertexIndexBase( + &vertexbase, + numverts, + type, + stride, + &indexbase, + indexstride, + numfaces, + indicestype, + 0); + + unsigned int* gfxbase = (unsigned int*)(indexbase+rayCallback.m_hitTriangleIndex*indexstride); + const btVector3& meshScaling = shape->getLocalScaling(); + for (int j=2;j>=0;j--) + { + int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; + + btScalar* graphicsbase = (btScalar*)(vertexbase+graphicsindex*stride); + + triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ()); + } + meshInterface->unLockReadOnlyVertexBase(0); + btVector3 triangleNormal; + triangleNormal = (triangle[1]-triangle[0]).cross(triangle[2]-triangle[0]); + rayCallback.m_hitNormalWorld = rayCallback.m_collisionObject->getWorldTransform().getBasis()*triangleNormal; + } + } + } + } + } if (rayCallback.m_hitNormalWorld.length2() > (SIMD_EPSILON*SIMD_EPSILON)) { rayCallback.m_hitNormalWorld.normalize(); @@ -771,14 +1114,14 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IPhysicsController* i { rayCallback.m_hitNormalWorld.setValue(1,0,0); } - normalX = rayCallback.m_hitNormalWorld.getX(); - normalY = rayCallback.m_hitNormalWorld.getY(); - normalZ = rayCallback.m_hitNormalWorld.getZ(); - + result.m_hitNormal[0] = rayCallback.m_hitNormalWorld.getX(); + result.m_hitNormal[1] = rayCallback.m_hitNormalWorld.getY(); + result.m_hitNormal[2] = rayCallback.m_hitNormalWorld.getZ(); + filterCallback.reportHit(&result); } - return nearestHit; + return result.m_controller; } @@ -801,6 +1144,13 @@ btBroadphaseInterface* CcdPhysicsEnvironment::getBroadphase() return m_dynamicsWorld->getBroadphase(); } +btDispatcher* CcdPhysicsEnvironment::getDispatcher() +{ + return m_dynamicsWorld->getDispatcher(); +} + + + @@ -833,6 +1183,12 @@ CcdPhysicsEnvironment::~CcdPhysicsEnvironment() if (NULL != m_filterCallback) delete m_filterCallback; + + if (NULL != m_collisionConfiguration) + delete m_collisionConfiguration; + + if (NULL != m_broadphase) + delete m_broadphase; } @@ -845,7 +1201,7 @@ void CcdPhysicsEnvironment::setConstraintParam(int constraintId,int param,float { //param = 1..12, min0,max0,min1,max1...min6,max6 btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; - genCons->SetLimit(param,value0,value1); + genCons->setLimit(param,value0,value1); break; }; default: @@ -1108,6 +1464,26 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::CreateSphereController(float radi return sphereController; } +int findClosestNode(btSoftBody* sb,const btVector3& worldPoint); +int findClosestNode(btSoftBody* sb,const btVector3& worldPoint) +{ + int node = -1; + + btSoftBody::tNodeArray& nodes(sb->m_nodes); + float maxDistSqr = 1e30f; + + for (int n=0;n<nodes.size();n++) + { + btScalar distSqr = (nodes[n].m_x - worldPoint).length2(); + if (distSqr<maxDistSqr) + { + maxDistSqr = distSqr; + node = n; + } + } + return node; +} + int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl0,class PHY_IPhysicsController* ctrl1,PHY_ConstraintType type, float pivotX,float pivotY,float pivotZ, float axisX,float axisY,float axisZ, @@ -1123,14 +1499,166 @@ int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl btRigidBody* rb0 = c0 ? c0->GetRigidBody() : 0; btRigidBody* rb1 = c1 ? c1->GetRigidBody() : 0; + + + bool rb0static = rb0 ? rb0->isStaticOrKinematicObject() : true; bool rb1static = rb1 ? rb1->isStaticOrKinematicObject() : true; + + btCollisionObject* colObj0 = c0->GetCollisionObject(); + if (!colObj0) + { + return 0; + } + + btVector3 pivotInA(pivotX,pivotY,pivotZ); + + //it might be a soft body, let's try + btSoftBody* sb0 = c0 ? c0->GetSoftBody() : 0; + btSoftBody* sb1 = c1 ? c1->GetSoftBody() : 0; + if (sb0 && sb1) + { + //not between two soft bodies? + return 0; + } + + if (sb0) + { + //either cluster or node attach, let's find closest node first + //the soft body doesn't have a 'real' world transform, so get its initial world transform for now + btVector3 pivotPointSoftWorld = sb0->m_initialWorldTransform(pivotInA); + int node=findClosestNode(sb0,pivotPointSoftWorld); + if (node >=0) + { + bool clusterconstaint = false; +/* + switch (type) + { + case PHY_LINEHINGE_CONSTRAINT: + { + if (sb0->clusterCount() && rb1) + { + btSoftBody::LJoint::Specs ls; + ls.erp=0.5f; + ls.position=sb0->clusterCom(0); + sb0->appendLinearJoint(ls,rb1); + clusterconstaint = true; + break; + } + } + case PHY_GENERIC_6DOF_CONSTRAINT: + { + if (sb0->clusterCount() && rb1) + { + btSoftBody::AJoint::Specs as; + as.erp = 1; + as.cfm = 1; + as.axis.setValue(axisX,axisY,axisZ); + sb0->appendAngularJoint(as,rb1); + clusterconstaint = true; + break; + } + + break; + } + default: + { + + } + }; + */ + + if (!clusterconstaint) + { + if (rb1) + { + sb0->appendAnchor(node,rb1); + } else + { + sb0->setMass(node,0.f); + } + } + + + } + return 0;//can't remove soft body anchors yet + } + + if (sb1) + { + btVector3 pivotPointAWorld = colObj0->getWorldTransform()(pivotInA); + int node=findClosestNode(sb1,pivotPointAWorld); + if (node >=0) + { + bool clusterconstaint = false; + + /* + switch (type) + { + case PHY_LINEHINGE_CONSTRAINT: + { + if (sb1->clusterCount() && rb0) + { + btSoftBody::LJoint::Specs ls; + ls.erp=0.5f; + ls.position=sb1->clusterCom(0); + sb1->appendLinearJoint(ls,rb0); + clusterconstaint = true; + break; + } + } + case PHY_GENERIC_6DOF_CONSTRAINT: + { + if (sb1->clusterCount() && rb0) + { + btSoftBody::AJoint::Specs as; + as.erp = 1; + as.cfm = 1; + as.axis.setValue(axisX,axisY,axisZ); + sb1->appendAngularJoint(as,rb0); + clusterconstaint = true; + break; + } + + break; + } + default: + { + + + } + };*/ + + + if (!clusterconstaint) + { + if (rb0) + { + sb1->appendAnchor(node,rb0); + } else + { + sb1->setMass(node,0.f); + } + } + + + } + return 0;//can't remove soft body anchors yet + } + if (rb0static && rb1static) + { + return 0; + } + - btVector3 pivotInA(pivotX,pivotY,pivotZ); + if (!rb0) + return 0; + + btVector3 pivotInB = rb1 ? rb1->getCenterOfMassTransform().inverse()(rb0->getCenterOfMassTransform()(pivotInA)) : rb0->getCenterOfMassTransform() * pivotInA; btVector3 axisInA(axisX,axisY,axisZ); @@ -1191,10 +1719,11 @@ int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl btTransform globalFrameA = rb0->getCenterOfMassTransform() * frameInA; frameInB = inv * globalFrameA; - + bool useReferenceFrameA = true; + genericConstraint = new btGeneric6DofConstraint( *rb0,*rb1, - frameInA,frameInB); + frameInA,frameInB,useReferenceFrameA); } else @@ -1215,9 +1744,10 @@ int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl ///frameInB in worldspace frameInB = rb0->getCenterOfMassTransform() * frameInA; + bool useReferenceFrameA = true; genericConstraint = new btGeneric6DofConstraint( *rb0,s_fixedObject2, - frameInA,frameInB); + frameInA,frameInB,useReferenceFrameA); } if (genericConstraint) @@ -1370,8 +1900,9 @@ int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl PHY_IPhysicsController* CcdPhysicsEnvironment::CreateConeController(float coneradius,float coneheight) { CcdConstructionInfo cinfo; - //This is a memory leak: Bullet does not delete the shape and it cannot be added to - //the KX_Scene.m_shapes list -- too bad but that's not a lot of data + + // we don't need a CcdShapeConstructionInfo for this shape: + // it is simple enough for the standard copy constructor (see CcdPhysicsController::GetReplica) cinfo.m_collisionShape = new btConeShape(coneradius,coneheight); cinfo.m_MotionState = 0; cinfo.m_physicsEnv = this; diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h index 825a5e525f2..3d9d5442b8f 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h @@ -56,6 +56,10 @@ class CcdPhysicsEnvironment : public PHY_IPhysicsEnvironment protected: btIDebugDraw* m_debugDrawer; + + class btDefaultCollisionConfiguration* m_collisionConfiguration; + class btBroadphaseInterface* m_broadphase; + //solver iterations int m_numIterations; @@ -70,6 +74,7 @@ protected: btContactSolverInfo m_solverInfo; + void processFhSprings(double curTime,float timeStep); public: CcdPhysicsEnvironment(btDispatcher* dispatcher=0, btOverlappingPairCache* pairCache=0); @@ -115,6 +120,8 @@ protected: virtual void setDebugMode(int debugMode); virtual void setGravity(float x,float y,float z); + virtual void getGravity(PHY__Vector3& grav); + virtual int createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type, float pivotX,float pivotY,float pivotZ, @@ -157,8 +164,7 @@ protected: btTypedConstraint* getConstraintById(int constraintId); - virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ); + virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ); //Methods for gamelogic collision/physics callbacks @@ -192,8 +198,7 @@ protected: btBroadphaseInterface* getBroadphase(); - - + btDispatcher* getDispatcher(); bool IsSatCollisionDetectionEnabled() const @@ -212,7 +217,10 @@ protected: void SyncMotionStates(float timeStep); - + class btSoftRigidDynamicsWorld* getDynamicsWorld() + { + return m_dynamicsWorld; + } class btConstraintSolver* GetConstraintSolver(); @@ -230,13 +238,13 @@ protected: std::vector<WrapperVehicle*> m_wrapperVehicles; - //use explicit btDiscreteDynamicsWorld* so that we have access to + //use explicit btSoftRigidDynamicsWorld/btDiscreteDynamicsWorld* so that we have access to //btDiscreteDynamicsWorld::addRigidBody(body,filter,group) //so that we can set the body collision filter/group at the time of creation //and not afterwards (breaks the collision system for radar/near sensor) //Ideally we would like to have access to this function from the btDynamicsWorld interface //class btDynamicsWorld* m_dynamicsWorld; - class btDiscreteDynamicsWorld* m_dynamicsWorld; + class btSoftRigidDynamicsWorld* m_dynamicsWorld; class btConstraintSolver* m_solver; diff --git a/source/gameengine/Physics/Bullet/Makefile b/source/gameengine/Physics/Bullet/Makefile index 49259d0a67c..d5570e75833 100644 --- a/source/gameengine/Physics/Bullet/Makefile +++ b/source/gameengine/Physics/Bullet/Makefile @@ -37,5 +37,10 @@ CCFLAGS += $(LEVEL_1_CPP_WARNINGS) CPPFLAGS += -I$(NAN_BULLET2)/include CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I../../../kernel/gen_system CPPFLAGS += -I../../Physics/common CPPFLAGS += -I../../Physics/Dummy +CPPFLAGS += -I../../Rasterizer + diff --git a/source/gameengine/Physics/Bullet/SConscript b/source/gameengine/Physics/Bullet/SConscript index dd6eab0f018..0936d45197a 100644 --- a/source/gameengine/Physics/Bullet/SConscript +++ b/source/gameengine/Physics/Bullet/SConscript @@ -3,7 +3,7 @@ Import ('env') sources = 'CcdPhysicsEnvironment.cpp CcdPhysicsController.cpp' -incs = '. ../common' +incs = '. ../common #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/Rasterizer' incs += ' ' + env['BF_BULLET_INC'] diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp index f512d44c9f2..d78958b746c 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp @@ -109,8 +109,7 @@ void DummyPhysicsEnvironment::removeConstraint(int constraintid) } } -PHY_IPhysicsController* DummyPhysicsEnvironment::rayTest(PHY_IPhysicsController* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ) +PHY_IPhysicsController* DummyPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ) { //collision detection / raytesting return NULL; diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h index b5a61f72e4a..975be84f2a7 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h @@ -69,8 +69,7 @@ public: return 0; } - virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ); + virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ); //gamelogic callbacks diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsController.h b/source/gameengine/Physics/Sumo/SumoPhysicsController.h index 95f01b45f2b..d8ee54935d7 100644 --- a/source/gameengine/Physics/Sumo/SumoPhysicsController.h +++ b/source/gameengine/Physics/Sumo/SumoPhysicsController.h @@ -120,6 +120,7 @@ public: virtual void SetMargin(float margin) ; virtual float GetMargin() const; virtual float GetRadius() const ; + virtual void SetRadius(float margin) { SetMargin(margin); } // clientinfo for raycasts for example diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp index 65018d2523e..80e4dc4044e 100644 --- a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp @@ -26,6 +26,7 @@ * * ***** END GPL LICENSE BLOCK ***** */ +#include <string.h> // memset #include "SumoPhysicsEnvironment.h" #include "PHY_IMotionState.h" #include "SumoPhysicsController.h" @@ -125,37 +126,35 @@ void SumoPhysicsEnvironment::removeConstraint(int constraintid) } } -PHY_IPhysicsController* SumoPhysicsEnvironment::rayTest(PHY_IPhysicsController* ignoreClientCtrl, +PHY_IPhysicsController* SumoPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, - float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ, - float& normalX,float& normalY,float& normalZ) + float toX,float toY,float toZ) { - SumoPhysicsController* ignoreCtr = static_cast<SumoPhysicsController*> (ignoreClientCtrl); + SumoPhysicsController* ignoreCtr = static_cast<SumoPhysicsController*> (filterCallback.m_ignoreController); //collision detection / raytesting MT_Point3 hit, normal; - PHY_IPhysicsController *ret = 0; + PHY_RayCastResult result; SM_Object* sm_ignore = 0; if (ignoreCtr) sm_ignore = ignoreCtr->GetSumoObject(); + memset(&result, 0, sizeof(result)); SM_Object* smOb = m_sumoScene->rayTest(sm_ignore,MT_Point3(fromX, fromY, fromZ),MT_Point3(toX, toY, toZ), hit, normal); if (smOb) { - ret = (PHY_IPhysicsController *) smOb->getPhysicsClientObject(); + result.m_controller = (PHY_IPhysicsController *) smOb->getPhysicsClientObject(); + result.m_hitPoint[0] = hit[0]; + result.m_hitPoint[1] = hit[1]; + result.m_hitPoint[2] = hit[2]; + result.m_hitNormal[0] = normal[0]; + result.m_hitNormal[1] = normal[1]; + result.m_hitNormal[2] = normal[2]; + filterCallback.reportHit(&result); } - hitX = hit[0]; - hitY = hit[1]; - hitZ = hit[2]; - - normalX = normal[0]; - normalY = normal[1]; - normalZ = normal[2]; - - return ret; + return result.m_controller; } //gamelogic callbacks void SumoPhysicsEnvironment::addSensor(PHY_IPhysicsController* ctrl) diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h index 8b9fb463034..100adf969d5 100644 --- a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h +++ b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h @@ -75,8 +75,7 @@ public: return 0; } - virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ); + virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ); //gamelogic callbacks diff --git a/source/gameengine/Physics/common/PHY_DynamicTypes.h b/source/gameengine/Physics/common/PHY_DynamicTypes.h index c289b9d8bcb..3b3e42c38d2 100644 --- a/source/gameengine/Physics/common/PHY_DynamicTypes.h +++ b/source/gameengine/Physics/common/PHY_DynamicTypes.h @@ -87,6 +87,18 @@ typedef enum PHY_ConstraintType { } PHY_ConstraintType; +typedef enum PHY_ShapeType { + PHY_SHAPE_NONE, + PHY_SHAPE_BOX, + PHY_SHAPE_SPHERE, + PHY_SHAPE_CYLINDER, + PHY_SHAPE_CONE, + PHY_SHAPE_MESH, + PHY_SHAPE_POLYTOPE, + PHY_SHAPE_COMPOUND +} PHY_ShapeType; + + typedef float PHY_Vector3[3]; #endif //__PHY_DYNAMIC_TYPES diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h index ca8edea114a..884e14cfb5a 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsController.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsController.h @@ -90,7 +90,8 @@ class PHY_IPhysicsController virtual void calcXform() =0; virtual void SetMargin(float margin) =0; virtual float GetMargin() const=0; - virtual float GetRadius() const { return 0.f;} + virtual float GetRadius() const=0; + virtual void SetRadius(float margin) = 0; PHY__Vector3 GetWorldPosition(PHY__Vector3& localpos); }; diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h index 5b275066665..98496fb7f9e 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h @@ -33,6 +33,50 @@ #include <vector> #include "PHY_DynamicTypes.h" class PHY_IVehicle; +class RAS_MeshObject; +class PHY_IPhysicsController; + +/** + * pass back information from rayTest + */ +struct PHY_RayCastResult +{ + PHY_IPhysicsController* m_controller; + PHY__Vector3 m_hitPoint; + PHY__Vector3 m_hitNormal; + const RAS_MeshObject* m_meshObject; // !=NULL for mesh object (only for Bullet controllers) + int m_polygon; // index of the polygon hit by the ray, + // only if m_meshObject != NULL +}; + +/** + * This class replaces the ignoreController parameter of rayTest function. + * It allows more sophisticated filtering on the physics controller before computing the ray intersection to save CPU. + * It is only used to its full extend by the Ccd physics environement (Bullet). + */ +class PHY_IRayCastFilterCallback +{ +public: + PHY_IPhysicsController* m_ignoreController; + bool m_faceNormal; + + virtual ~PHY_IRayCastFilterCallback() + { + } + + virtual bool needBroadphaseRayCast(PHY_IPhysicsController* controller) + { + return true; + } + + virtual void reportHit(PHY_RayCastResult* result) = 0; + + PHY_IRayCastFilterCallback(PHY_IPhysicsController* ignoreController, bool faceNormal=false) + :m_ignoreController(ignoreController), + m_faceNormal(faceNormal) + { + } +}; /** * Physics Environment takes care of stepping the simulation and is a container for physics entities (rigidbodies,constraints, materials etc.) @@ -94,8 +138,7 @@ class PHY_IPhysicsEnvironment //complex constraint for vehicles virtual PHY_IVehicle* getVehicleConstraint(int constraintId) =0; - virtual PHY_IPhysicsController* rayTest(PHY_IPhysicsController* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ, - float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ)=0; + virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ)=0; //Methods for gamelogic collision/physics callbacks diff --git a/source/gameengine/PyDoc/BL_ActionActuator.py b/source/gameengine/PyDoc/BL_ActionActuator.py index d56888cde80..b68d3014115 100644 --- a/source/gameengine/PyDoc/BL_ActionActuator.py +++ b/source/gameengine/PyDoc/BL_ActionActuator.py @@ -164,5 +164,14 @@ class BL_ActionActuator(SCA_IActuator): @param mode: True for armature/world space, False for bone space @type mode: boolean """ - - + def setFrameProperty(prop): + """ + @param prop: A string specifying the property of the object that will be updated with the action frame number. + @type prop: string + """ + def getFrameProperty(): + """ + Returns the name of the property that is set to the current frame number. + + @rtype: string + """ diff --git a/source/gameengine/PyDoc/BL_ShapeActionActuator.py b/source/gameengine/PyDoc/BL_ShapeActionActuator.py index 63cce253fa4..a26b276a2da 100644 --- a/source/gameengine/PyDoc/BL_ShapeActionActuator.py +++ b/source/gameengine/PyDoc/BL_ShapeActionActuator.py @@ -154,5 +154,14 @@ class BL_ShapeActionActuator(SCA_IActuator): @rtype: string """ - - + def setFrameProperty(prop): + """ + @param prop: A string specifying the property of the object that will be updated with the action frame number. + @type prop: string + """ + def getFrameProperty(): + """ + Returns the name of the property that is set to the current frame number. + + @rtype: string + """ diff --git a/source/gameengine/PyDoc/GameKeys.py b/source/gameengine/PyDoc/GameKeys.py index 268fb9cc172..1a0a737718e 100644 --- a/source/gameengine/PyDoc/GameKeys.py +++ b/source/gameengine/PyDoc/GameKeys.py @@ -164,3 +164,12 @@ Example:: # Activate Right! """ + +def EventToString(event): + """ + Return the string name of a key event. Will raise a ValueError error if its invalid. + + @type event: int + @param event: key event from GameKeys or the keyboard sensor. + @rtype: string + """ diff --git a/source/gameengine/PyDoc/GameLogic.py b/source/gameengine/PyDoc/GameLogic.py index 965c0522bd7..af3d2810553 100644 --- a/source/gameengine/PyDoc/GameLogic.py +++ b/source/gameengine/PyDoc/GameLogic.py @@ -14,8 +14,7 @@ Documentation for the GameLogic Module. Examples:: # To get a controller: - import GameLogic - co = GameLogic.getCurrentController() + co = GameLogic.getCurrentController() # GameLogic is automatically imported # To get the game object associated with this controller: obj = co.getOwner() @@ -42,6 +41,7 @@ Documentation for the GameLogic Module. - L{SCA_MouseSensor} - L{SCA_PropertySensor} - L{SCA_RandomSensor} + - L{SCA_DelaySensor} You can also access actuators linked to the controller:: # To get an actuator attached to the controller: @@ -220,6 +220,13 @@ def setPhysicsTicRate(ticrate): @param ticrate: The new update frequency (in Hz). @type ticrate: float """ +def getAverageFrameRate(): + """ + Gets the estimated average framerate + + @return: The estimed average framerate in frames per second + @rtype: float + """ def expandPath(path): """ @@ -236,3 +243,13 @@ def expandPath(path): @return: The converted string @rtype: string """ + +def getBlendFileList(path = "//"): + """ + Returns a list of blend files in the same directory as the open blend file, or from using the option argument. + + @param path: Optional directory argument, will be expanded (like expandPath) into the full path. + @type path: string + @return: A list of filenames, with no directory prefix + @rtype: list + """ diff --git a/source/gameengine/PyDoc/KX_GameObject.py b/source/gameengine/PyDoc/KX_GameObject.py index a5ba5b1d634..ff9b4ffc95b 100644 --- a/source/gameengine/PyDoc/KX_GameObject.py +++ b/source/gameengine/PyDoc/KX_GameObject.py @@ -30,11 +30,11 @@ class KX_GameObject: Delete this object, can be used inpace of the EndObject Actuator. The actual removal of the object from the scene is delayed. """ - def getVisible(visible): + def getVisible(): """ Gets the game object's visible flag. - @type visible: boolean + @rtype: boolean """ def setVisible(visible): """ @@ -49,16 +49,25 @@ class KX_GameObject: @rtype: int @return: the objects state. """ - def setState(): + def setState(state): """ - Sets the game object's visible flag. + Sets the game object's state flag. The bitmasks for states from 1 to 30 can be set with (1<<0, 1<<1, 1<<2 ... 1<<29) - @type visible: boolean + @type state: integer """ def setPosition(pos): """ - Sets the game object's position. + Sets the game object's position. + Global coordinates for root object, local for child objects. + + + @type pos: [x, y, z] + @param pos: the new position, in local coordinates. + """ + def setWorldPosition(pos): + """ + Sets the game object's position in world coordinates regardless if the object is root or child. @type pos: [x, y, z] @param pos: the new position, in world coordinates. @@ -135,6 +144,26 @@ class KX_GameObject: @param local: - False: you get the "global" velocity ie: relative to world orientation (default). - True: you get the "local" velocity ie: relative to object orientation. """ + def getAngularVelocity(local = 0): + """ + Gets the game object's angular velocity. + + @type local: boolean + @param local: - False: you get the "global" velocity ie: relative to world orientation (default). + - True: you get the "local" velocity ie: relative to object orientation. + @rtype: list [vx, vy, vz] + @return: the object's angular velocity. + """ + def setAngularVelocity(velocity, local = 0): + """ + Sets the game object's angular velocity. + + @type velocity: 3d vector. + @param velocity: angular velocity vector. + @type local: boolean + @param local: - False: you get the "global" velocity ie: relative to world orientation (default). + - True: you get the "local" velocity ie: relative to object orientation. + """ def getVelocity(point): """ Gets the game object's velocity at the specified point. @@ -280,11 +309,13 @@ class KX_GameObject: @rtype: L{KX_GameObject} @return: the first object hit or None if no object or object does not match prop """ - def rayCast(to,from,dist,prop): + def rayCast(objto,objfrom,dist,prop,face,xray,poly): """ Look from a point/object to another point/object and find first object hit within dist that matches prop. - Returns a 3-tuple with object reference, hit point and hit normal or (None,None,None) if no hit. - Ex: + if poly is 0, returns a 3-tuple with object reference, hit point and hit normal or (None,None,None) if no hit. + if poly is 1, returns a 4-tuple with in addition a L{KX_PolyProxy} as 4th element. + + Ex:: # shoot along the axis gun-gunAim (gunAim should be collision-free) ob,point,normal = gun.rayCast(gunAim,None,50) if ob: @@ -292,21 +323,42 @@ class KX_GameObject: Notes: The ray ignores the object on which the method is called. - If is casted from/to object center or explicit [x,y,z] points. - The ray does not have X-Ray capability: the first object hit (other than self object) stops the ray - If a property was specified and the first object hit does not have that property, there is no hit - The ray ignores collision-free objects and faces that dont have the collision flag enabled, you can however use ghost objects. + It is casted from/to object center or explicit [x,y,z] points. + + The face paremeter determines the orientation of the normal:: + 0 => hit normal is always oriented towards the ray origin (as if you casted the ray from outside) + 1 => hit normal is the real face normal (only for mesh object, otherwise face has no effect) + + The ray has X-Ray capability if xray parameter is 1, otherwise the first object hit (other than self object) stops the ray. + The prop and xray parameters interact as follow:: + prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray. + prop off, xray on : idem. + prop on, xray off: return closest hit if it matches prop, no hit otherwise. + prop on, xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray. + The L{KX_PolyProxy} 4th element of the return tuple when poly=1 allows to retrieve information on the polygon hit by the ray. + If there is no hit or the hit object is not a static mesh, None is returned as 4th element. + + The ray ignores collision-free objects and faces that dont have the collision flag enabled, you can however use ghost objects. - @param to: [x,y,z] or object to which the ray is casted - @type to: L{KX_GameObject} or 3-tuple - @param from: [x,y,z] or object from which the ray is casted; None or omitted => use self object center - @type from: L{KX_GameObject} or 3-tuple or None + @param objto: [x,y,z] or object to which the ray is casted + @type objto: L{KX_GameObject} or 3-tuple + @param objfrom: [x,y,z] or object from which the ray is casted; None or omitted => use self object center + @type objfrom: L{KX_GameObject} or 3-tuple or None @param dist: max distance to look (can be negative => look behind); 0 or omitted => detect up to to @type dist: float @param prop: property name that object must have; can be omitted => detect any object @type prop: string - @rtype: 3-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz)) - @return: (object,hitpoint,hitnormal) or (None,None,None) + @param face: normal option: 1=>return face normal; 0 or omitted => normal is oriented towards origin + @type face: int + @param xray: X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object + @type xray: int + @param poly: polygon option: 1=>return value is a 4-tuple and the 4th element is a L{KX_PolyProxy} + @type poly: int + @rtype: 3-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz)) + or 4-tuple (L{KX_GameObject}, 3-tuple (x,y,z), 3-tuple (nx,ny,nz), L{KX_PolyProxy}) + @return: (object,hitpoint,hitnormal) or (object,hitpoint,hitnormal,polygon) + If no hit, returns (None,None,None) or (None,None,None,None) + If the object hit is not a static mesh, polygon is None """ diff --git a/source/gameengine/PyDoc/KX_MeshProxy.py b/source/gameengine/PyDoc/KX_MeshProxy.py index e43fa3598f0..03bc36b6ac1 100644 --- a/source/gameengine/PyDoc/KX_MeshProxy.py +++ b/source/gameengine/PyDoc/KX_MeshProxy.py @@ -95,6 +95,21 @@ class KX_MeshProxy: @rtype: L{KX_VertexProxy} @return: a vertex object. """ + def getNumPolygons(): + """ + Returns the number of polygon in the mesh. + + @rtype: integer + """ + def getPolygon(index): + """ + Gets the specified polygon from the mesh. + + @type index: integer + @param index: polygon number + @rtype: L{KX_PolyProxy} + @return: a polygon object. + """ def reinstancePhysicsMesh(): """ Updates the physics system with the changed mesh. diff --git a/source/gameengine/PyDoc/KX_ObjectActuator.py b/source/gameengine/PyDoc/KX_ObjectActuator.py index db577d21e6f..b7b76473292 100644 --- a/source/gameengine/PyDoc/KX_ObjectActuator.py +++ b/source/gameengine/PyDoc/KX_ObjectActuator.py @@ -111,9 +111,7 @@ class KX_ObjectActuator(SCA_IActuator): For the servo control actuator, this is the target speed. @rtype: list [vx, vy, vz, local] - @return: A four item list, containing the vector velocity, and whether - the velocity is applied in local coordinates (True) or world - coordinates (False) + @return: A four item list, containing the vector velocity, and whether the velocity is applied in local coordinates (True) or world coordinates (False) """ def setLinearVelocity(vx, vy, vz, local): """ diff --git a/source/gameengine/PyDoc/KX_PolyProxy.py b/source/gameengine/PyDoc/KX_PolyProxy.py new file mode 100644 index 00000000000..bcd42c2ac2e --- /dev/null +++ b/source/gameengine/PyDoc/KX_PolyProxy.py @@ -0,0 +1,100 @@ +# $Id$ +# Documentation for the polygon proxy class + +class KX_PolyProxy: + """ + A polygon holds the index of the vertex forming the poylgon. + + Note: + The polygon attributes are read-only, you need to retrieve the vertex proxy if you want + to change the vertex settings. + + @ivar matname: The name of polygon material, empty if no material. + @type matname: string + @ivar material: The material of the polygon + @type material: L{KX_PolygonMaterial} or KX_BlenderMaterial + @ivar texture: The texture name of the polygon. + @type texture: string + @ivar matid: The material index of the polygon, use this to retrieve vertex proxy from mesh proxy + @type matid: integer + @ivar v1: vertex index of the first vertex of the polygon, use this to retrieve vertex proxy from mesh proxy + @type v1: integer + @ivar v2: vertex index of the second vertex of the polygon, use this to retrieve vertex proxy from mesh proxy + @type v2: integer + @ivar v3: vertex index of the third vertex of the polygon, use this to retrieve vertex proxy from mesh proxy + @type v3: integer + @ivar v4: vertex index of the fourth vertex of the polygon, 0 if polygon has only 3 vertex + use this to retrieve vertex proxy from mesh proxy + @type v4: integer + @ivar visible: visible state of the polygon: 1=visible, 0=invisible + @type visible: integer + @ivar collide: collide state of the polygon: 1=receives collision, 0=collision free. + @type collide: integer + """ + + def getMaterialName(): + """ + Returns the polygon material name with MA prefix + + @rtype: string + @return: material name + """ + def getMaterial(): + """ + Returns the polygon material + + @rtype: L{KX_PolygonMaterial} or KX_BlenderMaterial + """ + def getTextureName(): + """ + Returns the polygon texture name + + @rtype: string + @return: texture name + """ + def getMaterialIndex(): + """ + Returns the material bucket index of the polygon. + This index and the ones returned by getVertexIndex() are needed to retrieve the vertex proxy from L{KX_MeshProxy}. + + @rtype: integer + @return: the material index in the mesh + """ + def getNumVertex(): + """ + Returns the number of vertex of the polygon. + + @rtype: integer + @return: number of vertex, 3 or 4. + """ + def isVisible(): + """ + Returns whether the polygon is visible or not + + @rtype: integer + @return: 0=invisible, 1=visible + """ + def isCollider(): + """ + Returns whether the polygon is receives collision or not + + @rtype: integer + @return: 0=collision free, 1=receives collision + """ + def getVertexIndex(vertex): + """ + Returns the mesh vertex index of a polygon vertex + This index and the one returned by getMaterialIndex() are needed to retrieve the vertex proxy from L{KX_MeshProxy}. + + @type vertex: integer + @param vertex: index of the vertex in the polygon: 0->3 + @rtype: integer + @return: mesh vertex index + """ + def getMesh(): + """ + Returns a mesh proxy + + @rtype: L{KX_MeshProxy} + @return: mesh proxy + """ diff --git a/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py b/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py index 4f2bf85bff3..c3b2e947ddb 100644 --- a/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py +++ b/source/gameengine/PyDoc/KX_SCA_AddObjectActuator.py @@ -66,6 +66,23 @@ class KX_SCA_AddObjectActuator(SCA_IActuator): @rtype: list [vx, vy, vz] """ + def setAngularVelocity(vx, vy, vz): + """ + Sets the initial angular velocity of added objects. + + @type vx: float + @param vx: the x component of the initial angular velocity. + @type vy: float + @param vy: the y component of the initial angular velocity. + @type vz: float + @param vz: the z component of the initial angular velocity. + """ + def getAngularVelocity(): + """ + Returns the initial angular velocity of added objects. + + @rtype: list [vx, vy, vz] + """ def getLastCreatedObject(): """ Returns the last object created by this actuator. diff --git a/source/gameengine/PyDoc/KX_SCA_ReplaceMeshActuator.py b/source/gameengine/PyDoc/KX_SCA_ReplaceMeshActuator.py index eb00a91a4ce..498f6072e23 100644 --- a/source/gameengine/PyDoc/KX_SCA_ReplaceMeshActuator.py +++ b/source/gameengine/PyDoc/KX_SCA_ReplaceMeshActuator.py @@ -59,8 +59,9 @@ class KX_SCA_ReplaceMeshActuator(SCA_IActuator): def setMesh(name): """ Sets the name of the mesh that will replace the current one. + When the name is None it will unset the mesh value so no action is taken. - @type name: string + @type name: string or None """ def getMesh(): """ @@ -68,6 +69,6 @@ class KX_SCA_ReplaceMeshActuator(SCA_IActuator): Returns None if no mesh has been scheduled to be added. - @rtype: string + @rtype: string or None """ diff --git a/source/gameengine/PyDoc/KX_TrackToActuator.py b/source/gameengine/PyDoc/KX_TrackToActuator.py index 2ecd94f38ae..948302991b7 100644 --- a/source/gameengine/PyDoc/KX_TrackToActuator.py +++ b/source/gameengine/PyDoc/KX_TrackToActuator.py @@ -21,7 +21,7 @@ class KX_TrackToActuator(SCA_IActuator): @type object: L{KX_GameObject}, string or None @param object: Either a reference to a game object or the name of the object to track. """ - def getObject(): + def getObject(name_only): """ Returns the name of the object to track. diff --git a/source/gameengine/PyDoc/Rasterizer.py b/source/gameengine/PyDoc/Rasterizer.py index f0e48b6ed43..cdda87fcb49 100644 --- a/source/gameengine/PyDoc/Rasterizer.py +++ b/source/gameengine/PyDoc/Rasterizer.py @@ -37,6 +37,10 @@ Example Uses an L{SCA_MouseSensor}, and two L{KX_ObjectActuator}s to implement M # Centre the mouse Rasterizer.setMousePosition(Rasterizer.getWindowWidth()/2, Rasterizer.getWindowHeight()/2) +@group Material Types: KX_TEXFACE_MATERIAL, KX_BLENDER_MULTITEX_MATERIAL, KX_BLENDER_GLSL_MATERIAL +@var KX_TEXFACE_MATERIAL: Materials as defined by the texture face settings. +@var KX_BLENDER_MULTITEX_MATERIAL: Materials approximating blender materials with multitexturing. +@var KX_BLENDER_BLENDER_MATERIAL: Materials approximating blender materials with GLSL. """ @@ -84,7 +88,8 @@ def setMousePosition(x, y): """ Sets the mouse cursor position. - @type x, y: integer + @type x: integer + @type y: integer """ def setBackgroundColor(rgba): @@ -145,3 +150,46 @@ def getFocalLength(): @rtype: float """ + +def setMaterialMode(mode): + """ + Set the material mode to use for OpenGL rendering. + + @type mode: KX_TEXFACE_MATERIAL, KX_BLENDER_MULTITEX_MATERIAL, KX_BLENDER_GLSL_MATERIAL + @note: Changes will only affect newly created scenes. + """ + +def getMaterialMode(mode): + """ + Get the material mode to use for OpenGL rendering. + + @rtype: KX_TEXFACE_MATERIAL, KX_BLENDER_MULTITEX_MATERIAL, KX_BLENDER_GLSL_MATERIAL + """ + +def setGLSLMaterialSetting(setting, enable): + """ + Enables or disables a GLSL material setting. + + @type setting: string (lights, shaders, shadows, ramps, nodes, extra_textures) + @type enable: boolean + """ + +def getGLSLMaterialSetting(setting, enable): + """ + Get the state of a GLSL material setting. + + @type setting: string (lights, shaders, shadows, ramps, nodes, extra_textures) + @rtype: boolean + """ +def drawLine(from,to,color): + """ + Draw a line in the 3D scene. + + @param from: the origin of the line + @type from: list [x, y, z] + @param to: the end of the line + @type to: list [x, y, z] + @param color: the color of the line + @type color: list [r, g, b] + """ + diff --git a/source/gameengine/PyDoc/SCA_DelaySensor.py b/source/gameengine/PyDoc/SCA_DelaySensor.py new file mode 100644 index 00000000000..19df589ea7b --- /dev/null +++ b/source/gameengine/PyDoc/SCA_DelaySensor.py @@ -0,0 +1,56 @@ +# $Id$ +# Documentation for SCA_DelaySensor +from SCA_ISensor import * + +class SCA_DelaySensor(SCA_ISensor): + """ + The Delay sensor generates positive and negative triggers at precise time, + expressed in number of frames. The delay parameter defines the length + of the initial OFF period. A positive trigger is generated at the end of this period. + The duration parameter defines the length of the ON period following the OFF period. + There is a negative trigger at the end of the ON period. If duration is 0, the sensor + stays ON and there is no negative trigger. + The sensor runs the OFF-ON cycle once unless the repeat option is set: the + OFF-ON cycle repeats indefinately (or the OFF cycle if duration is 0). + Use SCA_ISensor::reset() at any time to restart sensor. + """ + def setDelay(delay): + """ + Set the initial delay before the positive trigger. + + @param delay: length of the initial OFF period as number of frame, 0 for immediate trigger + @type delay: integer + """ + def setDuration(duration): + """ + Set the duration of the ON pulse after initial delay and the generation of the positive trigger. + If duration is greater than 0, a negative trigger is sent at the end of the ON pulse. + + @param duration: length of the ON period in number of frame after the initial OFF period + @type duration: integer + """ + def setRepeat(repeat): + """ + Set if the sensor repeat mode. + + @param repeat: 1 if the OFF-ON cycle should be repeated indefinately, 0 if it should run once. + @type repeat: integer + """ + def getDelay(): + """ + Return the delay parameter value. + + @rtype: integer + """ + def getDuration(): + """ + Return the duration parameter value + + @rtype: integer + """ + def getRepeat(): + """ + Return the repeat parameter value + + @rtype: KX_TRUE or KX_FALSE + """ diff --git a/source/gameengine/PyDoc/SCA_ISensor.py b/source/gameengine/PyDoc/SCA_ISensor.py index 0ebc2debb31..14858505e24 100644 --- a/source/gameengine/PyDoc/SCA_ISensor.py +++ b/source/gameengine/PyDoc/SCA_ISensor.py @@ -9,7 +9,12 @@ class SCA_ISensor(SCA_ILogicBrick): def isPositive(): """ - True if this sensor brick has been activated. + True if this sensor brick is in a positive state. + """ + + def isTriggered(): + """ + True if this sensor brick has triggered the current controller. """ def getUsePosPulseMode(): @@ -77,4 +82,10 @@ class SCA_ISensor(SCA_ILogicBrick): @param level: Detect level instead of edge? (KX_TRUE, KX_FALSE) @type level: boolean """ + def reset(): + """ + Reset sensor internal state, effect depends on the type of sensor and settings. + + The sensor is put in its initial state as if it was just activated. + """ diff --git a/source/gameengine/Rasterizer/Makefile b/source/gameengine/Rasterizer/Makefile index e3b1f274ee5..917f70c7108 100644 --- a/source/gameengine/Rasterizer/Makefile +++ b/source/gameengine/Rasterizer/Makefile @@ -49,10 +49,6 @@ ifeq ($(OS),darwin) CPPFLAGS += -fpascal-strings endif -ifeq ($(WITH_BF_GLEXT),true) - CPPFLAGS += -DWITH_GLEXT -endif - ############### SOURCEDIR = source/gameengine/Rasterizer diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp index ef206332057..6e5553d4781 100644 --- a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp @@ -85,7 +85,7 @@ RAS_2DFilterManager::~RAS_2DFilterManager() FreeTextures(); } -unsigned int RAS_2DFilterManager::CreateShaderProgram(char* shadersource) +unsigned int RAS_2DFilterManager::CreateShaderProgram(const char* shadersource) { GLuint program = 0; GLuint fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER); diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.h b/source/gameengine/Rasterizer/RAS_2DFilterManager.h index f5998e1f093..c16bd41dd0e 100644 --- a/source/gameengine/Rasterizer/RAS_2DFilterManager.h +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.h @@ -33,7 +33,7 @@ class RAS_2DFilterManager { private: - unsigned int CreateShaderProgram(char* shadersource); + unsigned int CreateShaderProgram(const char* shadersource); unsigned int CreateShaderProgram(int filtermode); void AnalyseShader(int passindex, vector<STR_String>& propNames); void StartShaderProgram(int passindex); diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.cpp b/source/gameengine/Rasterizer/RAS_BucketManager.cpp index 82bdce44519..f7938bb62e6 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.cpp +++ b/source/gameengine/Rasterizer/RAS_BucketManager.cpp @@ -26,10 +26,6 @@ * ***** END GPL LICENSE BLOCK ***** */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #ifdef WIN32 // don't show these anoying STL warnings #pragma warning (disable:4786) @@ -39,168 +35,234 @@ #include "RAS_MaterialBucket.h" #include "STR_HashedString.h" #include "RAS_MeshObject.h" -#define KX_NUM_MATERIALBUCKETS 100 #include "RAS_IRasterizer.h" #include "RAS_IRenderTools.h" #include "RAS_BucketManager.h" +#include <algorithm> #include <set> -RAS_BucketManager::RAS_BucketManager() +/* sorting */ + +struct RAS_BucketManager::sortedmeshslot { +public: + MT_Scalar m_z; /* depth */ + RAS_MeshSlot *m_ms; /* mesh slot */ + RAS_MaterialBucket *m_bucket; /* buck mesh slot came from */ -} + sortedmeshslot() {} -RAS_BucketManager::~RAS_BucketManager() -{ - RAS_BucketManagerClearAll(); -} + void set(RAS_MeshSlot *ms, RAS_MaterialBucket *bucket, const MT_Vector3& pnorm) + { + // would be good to use the actual bounding box center instead + MT_Point3 pos(ms->m_OpenGLMatrix[12], ms->m_OpenGLMatrix[13], ms->m_OpenGLMatrix[14]); -/** - * struct alphamesh holds a mesh, (m_ms) it's depth, (m_z) and the bucket it came from (m_bucket.) - */ -struct RAS_BucketManager::alphamesh -{ -public: - MT_Scalar m_z; - RAS_MaterialBucket::T_MeshSlotList::iterator m_ms; - RAS_MaterialBucket *m_bucket; - alphamesh(MT_Scalar z, RAS_MaterialBucket::T_MeshSlotList::iterator &ms, RAS_MaterialBucket *bucket) : - m_z(z), - m_ms(ms), - m_bucket(bucket) - {} + m_z = MT_dot(pnorm, pos); + m_ms = ms; + m_bucket = bucket; + } }; struct RAS_BucketManager::backtofront { - bool operator()(const alphamesh &a, const alphamesh &b) + bool operator()(const sortedmeshslot &a, const sortedmeshslot &b) { - return a.m_z < b.m_z; + return (a.m_z < b.m_z) || (a.m_z == b.m_z && a.m_ms < b.m_ms); } }; + +struct RAS_BucketManager::fronttoback +{ + bool operator()(const sortedmeshslot &a, const sortedmeshslot &b) + { + return (a.m_z > b.m_z) || (a.m_z == b.m_z && a.m_ms > b.m_ms); + } +}; + +/* bucket manager */ + +RAS_BucketManager::RAS_BucketManager() +{ + +} + +RAS_BucketManager::~RAS_BucketManager() +{ + BucketList::iterator it; + + for (it = m_SolidBuckets.begin(); it != m_SolidBuckets.end(); it++) + delete (*it); + + for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++) + delete(*it); + m_SolidBuckets.clear(); + m_AlphaBuckets.clear(); +} + +void RAS_BucketManager::OrderBuckets(const MT_Transform& cameratrans, BucketList& buckets, vector<sortedmeshslot>& slots, bool alpha) +{ + BucketList::iterator bit; + list<RAS_MeshSlot>::iterator mit; + size_t size = 0, i = 0; + + /* Camera's near plane equation: pnorm.dot(point) + pval, + * but we leave out pval since it's constant anyway */ + const MT_Vector3 pnorm(cameratrans.getBasis()[2]); + + for (bit = buckets.begin(); bit != buckets.end(); ++bit) + for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) + if (!mit->IsCulled()) + size++; + + slots.resize(size); + + for (bit = buckets.begin(); bit != buckets.end(); ++bit) + for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) + if (!mit->IsCulled()) + slots[i++].set(&*mit, *bit, pnorm); + + if(alpha) + sort(slots.begin(), slots.end(), backtofront()); + else + sort(slots.begin(), slots.end(), fronttoback()); +} void RAS_BucketManager::RenderAlphaBuckets( const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools) { - BucketList::iterator bit; - std::multiset<alphamesh, backtofront> alphameshset; - RAS_MaterialBucket::T_MeshSlotList::iterator mit; + vector<sortedmeshslot> slots; + vector<sortedmeshslot>::iterator sit; + + // Having depth masks disabled/enabled gives different artifacts in + // case no sorting is done or is done inexact. For compatibility, we + // disable it. + rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_DISABLED); + + OrderBuckets(cameratrans, m_AlphaBuckets, slots, true); - /* Camera's near plane equation: cam_norm.dot(point) + cam_origin */ - const MT_Vector3 cam_norm(cameratrans.getBasis()[2]); - const MT_Scalar cam_origin = cameratrans.getOrigin()[2]; - for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) - { - for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) - { - if ((*mit).m_bVisible) - { - MT_Point3 pos((*mit).m_OpenGLMatrix[12], (*mit).m_OpenGLMatrix[13], (*mit).m_OpenGLMatrix[14]); - alphameshset.insert(alphamesh(MT_dot(cam_norm, pos) + cam_origin, mit, *bit)); - } + for(sit=slots.begin(); sit!=slots.end(); ++sit) { + rendertools->SetClientObject(rasty, sit->m_ms->m_clientObj); + + while(sit->m_bucket->ActivateMaterial(cameratrans, rasty, rendertools)) + sit->m_bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *(sit->m_ms)); + } + + rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED); +} + +void RAS_BucketManager::RenderSolidBuckets( + const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools) +{ + BucketList::iterator bit; + list<RAS_MeshSlot>::iterator mit; + + rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED); + + for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) { + for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { + if (mit->IsCulled()) + continue; + + rendertools->SetClientObject(rasty, mit->m_clientObj); + + while ((*bit)->ActivateMaterial(cameratrans, rasty, rendertools)) + (*bit)->RenderMeshSlot(cameratrans, rasty, rendertools, *mit); } } - // It shouldn't be strictly necessary to disable depth writes; but - // it is needed for compatibility. - rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_DISABLED); + /* this code draws meshes order front-to-back instead to reduce overdraw. + * it turned out slower due to much material state switching, a more clever + * algorithm might do better. */ +#if 0 + vector<sortedmeshslot> slots; + vector<sortedmeshslot>::iterator sit; - RAS_IRasterizer::DrawMode drawingmode; - std::multiset< alphamesh, backtofront>::iterator msit = alphameshset.begin(); - for (; msit != alphameshset.end(); ++msit) - { - rendertools->SetClientObject((*(*msit).m_ms).m_clientObj); - while ((*msit).m_bucket->ActivateMaterial(cameratrans, rasty, rendertools, drawingmode)) - (*msit).m_bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *(*msit).m_ms, drawingmode); + OrderBuckets(cameratrans, m_SolidBuckets, slots, false); + + for(sit=slots.begin(); sit!=slots.end(); ++sit) { + rendertools->SetClientObject(rasty, sit->m_ms->m_clientObj); + + while(sit->m_bucket->ActivateMaterial(cameratrans, rasty, rendertools)) + sit->m_bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *(sit->m_ms)); } - - rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED); +#endif } void RAS_BucketManager::Renderbuckets( const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools) { - BucketList::iterator bucket; - - rasty->EnableTextures(false); - rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED); - - // beginning each frame, clear (texture/material) caching information + /* beginning each frame, clear (texture/material) caching information */ rasty->ClearCachingInfo(); - RAS_MaterialBucket::StartFrame(); - - for (bucket = m_MaterialBuckets.begin(); bucket != m_MaterialBuckets.end(); ++bucket) - (*bucket)->Render(cameratrans,rasty,rendertools); - + RenderSolidBuckets(cameratrans, rasty, rendertools); RenderAlphaBuckets(cameratrans, rasty, rendertools); - RAS_MaterialBucket::EndFrame(); + + rendertools->SetClientObject(rasty, NULL); } RAS_MaterialBucket* RAS_BucketManager::FindBucket(RAS_IPolyMaterial * material, bool &bucketCreated) { - bucketCreated = false; BucketList::iterator it; - for (it = m_MaterialBuckets.begin(); it != m_MaterialBuckets.end(); it++) - { + + bucketCreated = false; + + for (it = m_SolidBuckets.begin(); it != m_SolidBuckets.end(); it++) if (*(*it)->GetPolyMaterial() == *material) return *it; - } for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++) - { if (*(*it)->GetPolyMaterial() == *material) return *it; - } RAS_MaterialBucket *bucket = new RAS_MaterialBucket(material); bucketCreated = true; + if (bucket->IsAlpha()) m_AlphaBuckets.push_back(bucket); else - m_MaterialBuckets.push_back(bucket); + m_SolidBuckets.push_back(bucket); return bucket; } -void RAS_BucketManager::RAS_BucketManagerClearAll() +void RAS_BucketManager::OptimizeBuckets(MT_Scalar distance) { - BucketList::iterator it; - for (it = m_MaterialBuckets.begin(); it != m_MaterialBuckets.end(); it++) - { - delete (*it); - } - for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++) - { - delete(*it); - } + BucketList::iterator bit; - m_MaterialBuckets.clear(); - m_AlphaBuckets.clear(); + distance = 10.0; + + for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) + (*bit)->Optimize(distance); + for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) + (*bit)->Optimize(distance); } -void RAS_BucketManager::ReleaseDisplayLists() +void RAS_BucketManager::ReleaseDisplayLists(RAS_IPolyMaterial *mat) { BucketList::iterator bit; - RAS_MaterialBucket::T_MeshSlotList::iterator mit; + list<RAS_MeshSlot>::iterator mit; - for (bit = m_MaterialBuckets.begin(); bit != m_MaterialBuckets.end(); ++bit) { - for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { - if(mit->m_DisplayList) { - mit->m_DisplayList->Release(); - mit->m_DisplayList = NULL; + for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) { + if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) { + for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { + if(mit->m_DisplayList) { + mit->m_DisplayList->Release(); + mit->m_DisplayList = NULL; + } } } } for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) { - for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { - if(mit->m_DisplayList) { - mit->m_DisplayList->Release(); - mit->m_DisplayList = NULL; + if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) { + for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { + if(mit->m_DisplayList) { + mit->m_DisplayList->Release(); + mit->m_DisplayList = NULL; + } } } } diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.h b/source/gameengine/Rasterizer/RAS_BucketManager.h index 08b67ed022f..74526f365a0 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.h +++ b/source/gameengine/Rasterizer/RAS_BucketManager.h @@ -39,32 +39,33 @@ class RAS_BucketManager { - //GEN_Map<class RAS_IPolyMaterial,class RAS_MaterialBucket*> m_MaterialBuckets; - typedef std::vector<class RAS_MaterialBucket*> BucketList; - BucketList m_MaterialBuckets; + BucketList m_SolidBuckets; BucketList m_AlphaBuckets; - struct alphamesh; + struct sortedmeshslot; struct backtofront; + struct fronttoback; public: RAS_BucketManager(); virtual ~RAS_BucketManager(); - void RenderAlphaBuckets(const MT_Transform& cameratrans, - RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools); void Renderbuckets(const MT_Transform & cameratrans, - RAS_IRasterizer* rasty, - class RAS_IRenderTools* rendertools); + RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools); RAS_MaterialBucket* FindBucket(RAS_IPolyMaterial * material, bool &bucketCreated); + void OptimizeBuckets(MT_Scalar distance); - void ReleaseDisplayLists(); + void ReleaseDisplayLists(RAS_IPolyMaterial * material = NULL); private: - void RAS_BucketManagerClearAll(); + void OrderBuckets(const MT_Transform& cameratrans, BucketList& buckets, vector<sortedmeshslot>& slots, bool alpha); + void RenderSolidBuckets(const MT_Transform& cameratrans, + RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools); + void RenderAlphaBuckets(const MT_Transform& cameratrans, + RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools); }; #endif //__RAS_BUCKETMANAGER diff --git a/source/gameengine/Rasterizer/RAS_Deformer.h b/source/gameengine/Rasterizer/RAS_Deformer.h index 4e8484ab880..3332ac4c0a7 100644 --- a/source/gameengine/Rasterizer/RAS_Deformer.h +++ b/source/gameengine/Rasterizer/RAS_Deformer.h @@ -44,7 +44,11 @@ public: virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map)=0; virtual bool Apply(class RAS_IPolyMaterial *polymat)=0; virtual bool Update(void)=0; - virtual RAS_Deformer *GetReplica()=0; + virtual RAS_Deformer *GetReplica(class KX_GameObject* replica)=0; + virtual bool SkipVertexTransform() + { + return false; + } protected: class RAS_MeshObject *m_pMesh; }; diff --git a/source/gameengine/Rasterizer/RAS_FramingManager.h b/source/gameengine/Rasterizer/RAS_FramingManager.h index dcb48c1c2a0..9cb59f300f7 100644 --- a/source/gameengine/Rasterizer/RAS_FramingManager.h +++ b/source/gameengine/Rasterizer/RAS_FramingManager.h @@ -108,6 +108,13 @@ public : ) const { return m_frame_type; }; + + void + SetFrameType( + RAS_FrameType type + ) { + m_frame_type = type; + }; float BarRed( @@ -140,14 +147,6 @@ public : }; private : - - /** - * private to force use of public constructor - */ - - RAS_FrameSettings( - const RAS_FrameSettings & - ); RAS_FrameType m_frame_type; float m_bar_r; diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp index 4ee06d96603..fb3607f89f4 100644 --- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp +++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp @@ -42,11 +42,8 @@ RAS_IPolyMaterial::RAS_IPolyMaterial(const STR_String& texname, int transp, bool alpha, bool zsort, - int lightlayer, - bool bIsTriangle, - void* clientobject=NULL) : - - m_texturename(texname), + int lightlayer) + : m_texturename(texname), m_materialname(matname), m_tile(tile), m_tilexrep(tilexrep), @@ -56,7 +53,6 @@ RAS_IPolyMaterial::RAS_IPolyMaterial(const STR_String& texname, m_alpha(alpha), m_zsort(zsort), m_lightlayer(lightlayer), - m_bIsTriangle(bIsTriangle), m_polymatid(m_newpolymatid++), m_flag(0), m_multimode(0) @@ -72,15 +68,16 @@ bool RAS_IPolyMaterial::Equals(const RAS_IPolyMaterial& lhs) const { if(m_flag &RAS_BLENDERMAT) { - return ( + bool test = ( this->m_multimode == lhs.m_multimode && this->m_flag == lhs.m_flag && this->m_drawingmode == lhs.m_drawingmode && this->m_transp == lhs.m_transp && - this->m_lightlayer == lhs.m_lightlayer && this->m_texturename.hash() == lhs.m_texturename.hash() && this->m_materialname.hash() == lhs.m_materialname.hash() ); + + return test; } else { @@ -92,8 +89,6 @@ bool RAS_IPolyMaterial::Equals(const RAS_IPolyMaterial& lhs) const this->m_alpha == lhs.m_alpha && this->m_zsort == lhs.m_zsort && this->m_drawingmode == lhs.m_drawingmode && - this->m_bIsTriangle == lhs.m_bIsTriangle && - this->m_lightlayer == lhs.m_lightlayer && this->m_texturename.hash() == lhs.m_texturename.hash() && this->m_materialname.hash() == lhs.m_materialname.hash() ); @@ -123,11 +118,6 @@ bool RAS_IPolyMaterial::IsZSort() const return m_zsort; } -bool RAS_IPolyMaterial::UsesTriangles() const -{ - return m_bIsTriangle; -} - unsigned int RAS_IPolyMaterial::hash() const { return m_texturename.hash(); @@ -172,5 +162,10 @@ bool RAS_IPolyMaterial::UsesLighting(RAS_IRasterizer *rasty) const return dolights; } +bool RAS_IPolyMaterial::UsesObjectColor() const +{ + return !(m_flag & RAS_BLENDERGLSL); +} + unsigned int RAS_IPolyMaterial::m_newpolymatid = 0; diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h index 8fc53e6b038..218dd91cb30 100644 --- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h +++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h @@ -71,7 +71,6 @@ protected: bool m_alpha; bool m_zsort; int m_lightlayer; - bool m_bIsTriangle; unsigned int m_polymatid; static unsigned int m_newpolymatid; @@ -106,9 +105,7 @@ public: int transp, bool alpha, bool zsort, - int lightlayer, - bool bIsTriangle, - void* clientobject); + int lightlayer); virtual ~RAS_IPolyMaterial() {}; /** @@ -129,14 +126,13 @@ public: { return false; } - virtual void ActivateMeshSlot(const class KX_MeshSlot & ms, RAS_IRasterizer* rasty) const {} + virtual void ActivateMeshSlot(const class RAS_MeshSlot & ms, RAS_IRasterizer* rasty) const {} virtual bool Equals(const RAS_IPolyMaterial& lhs) const; bool Less(const RAS_IPolyMaterial& rhs) const; int GetLightLayer() const; bool IsAlpha() const; bool IsZSort() const; - bool UsesTriangles() const; unsigned int hash() const; int GetDrawingMode() const; const STR_String& GetMaterialName() const; @@ -145,6 +141,7 @@ public: const unsigned int GetFlag() const; virtual bool UsesLighting(RAS_IRasterizer *rasty) const; + virtual bool UsesObjectColor() const; /* * PreCalculate texture gen diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h index 9e03212283e..411b28fa3b7 100644 --- a/source/gameengine/Rasterizer/RAS_IRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h @@ -169,6 +169,10 @@ public: */ virtual bool BeginFrame(int drawingmode, double time)=0; /** + * ClearColorBuffer clears the color buffer. + */ + virtual void ClearColorBuffer()=0; + /** * ClearDepthBuffer clears the depth buffer. */ virtual void ClearDepthBuffer()=0; @@ -181,7 +185,8 @@ public: */ virtual void EndFrame()=0; /** - * SetRenderArea sets the render area from the 2d canvas + * SetRenderArea sets the render area from the 2d canvas. + * Returns true if only of subset of the canvas is used. */ virtual void SetRenderArea()=0; @@ -195,6 +200,7 @@ public: * @return true if stereo mode is enabled. */ virtual bool Stereo()=0; + virtual bool InterlacedStereo()=0; /** * Sets which eye buffer subsequent primitives will be rendered to. */ @@ -217,39 +223,18 @@ public: // Drawing Functions /** - * IndexPrimitives: Renders primitives. - * @param vertexarrays is an array of vertex arrays - * @param indexarrays is an array of index arrays - * @param mode determines the type of primitive stored in the vertex/index arrays - * @param useObjectColor will render the object using @param rgbacolor instead of - * vertex colors. - */ - virtual void IndexPrimitives( const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot)=0; - - virtual void IndexPrimitivesMulti( - const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot)=0; + * IndexPrimitives: Renders primitives from mesh slot. + */ + virtual void IndexPrimitives(class RAS_MeshSlot& ms)=0; + virtual void IndexPrimitivesMulti(class RAS_MeshSlot& ms)=0; /** * IndexPrimitives_3DText will render text into the polygons. * The text to be rendered is from @param rendertools client object's text property. */ - virtual void IndexPrimitives_3DText( const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, + virtual void IndexPrimitives_3DText(class RAS_MeshSlot& ms, class RAS_IPolyMaterial* polymat, - class RAS_IRenderTools* rendertools, - bool useObjectColor, - const MT_Vector4& rgbacolor)=0; + class RAS_IRenderTools* rendertools)=0; virtual void SetProjectionMatrix(MT_CmMatrix4x4 & mat)=0; /* This one should become our final version, methinks. */ @@ -271,9 +256,6 @@ public: virtual const MT_Point3& GetCameraPosition()=0; /** */ - virtual void LoadViewMatrix()=0; - /** - */ virtual void SetFog(float start, float dist, float r, @@ -309,9 +291,6 @@ public: */ virtual int GetDrawingMode()=0; /** - */ - virtual void EnableTextures(bool enable)=0; - /** * Sets face culling */ virtual void SetCullFace(bool enable)=0; @@ -385,7 +364,9 @@ public: virtual void SetAttribNum(int num) = 0; virtual void SetTexCoord(TexCoGen coords, int unit) = 0; virtual void SetAttrib(TexCoGen coords, int unit) = 0; - virtual void GetViewMatrix(MT_Matrix4x4 &mat) const = 0; + + virtual const MT_Matrix4x4& GetViewMatrix() const = 0; + virtual const MT_Matrix4x4& GetViewInvMatrix() const = 0; virtual bool QueryLists(){return false;} virtual bool QueryArrays(){return false;} @@ -398,6 +379,7 @@ public: virtual void SetMotionBlurState(int newstate)=0; virtual void SetBlendingMode(int blendmode)=0; + virtual void SetFrontFace(bool ccw)=0; }; #endif //__RAS_IRASTERIZER diff --git a/source/gameengine/Rasterizer/RAS_IRenderTools.cpp b/source/gameengine/Rasterizer/RAS_IRenderTools.cpp index 2be9bb75ebf..555a3520bb4 100644 --- a/source/gameengine/Rasterizer/RAS_IRenderTools.cpp +++ b/source/gameengine/Rasterizer/RAS_IRenderTools.cpp @@ -28,42 +28,22 @@ #include "RAS_IRenderTools.h" -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -void RAS_IRenderTools::SetViewMat(const MT_Transform& trans) -{ - trans.getValue(m_viewmat); -} - - - -void RAS_IRenderTools::SetClientObject(void* obj) +void RAS_IRenderTools::SetClientObject(RAS_IRasterizer* rasty, void *obj) { if (m_clientobject != obj) - { m_clientobject = obj; - m_modified = true; - } } - - void RAS_IRenderTools::SetAuxilaryClientInfo(void* inf) { m_auxilaryClientInfo = inf; } - - void RAS_IRenderTools::AddLight(struct RAS_LightObject* lightobject) { m_lights.push_back(lightobject); } - - void RAS_IRenderTools::RemoveLight(struct RAS_LightObject* lightobject) { std::vector<struct RAS_LightObject*>::iterator lit = @@ -71,5 +51,5 @@ void RAS_IRenderTools::RemoveLight(struct RAS_LightObject* lightobject) if (!(lit==m_lights.end())) m_lights.erase(lit); - } + diff --git a/source/gameengine/Rasterizer/RAS_IRenderTools.h b/source/gameengine/Rasterizer/RAS_IRenderTools.h index 54a663ba111..57f331e64cb 100644 --- a/source/gameengine/Rasterizer/RAS_IRenderTools.h +++ b/source/gameengine/Rasterizer/RAS_IRenderTools.h @@ -44,12 +44,9 @@ class RAS_IRenderTools { protected: - float m_viewmat[16]; void* m_clientobject; void* m_auxilaryClientInfo; - bool m_modified; - std::vector<struct RAS_LightObject*> m_lights; RAS_2DFilterManager m_filtermanager; @@ -68,8 +65,7 @@ public: RAS_IRenderTools( ) : - m_clientobject(NULL), - m_modified(true) + m_clientobject(NULL) { }; @@ -131,24 +127,21 @@ public: float v1[3], float v2[3], float v3[3], - float v4[3] + float v4[3], + int glattrib )=0; virtual - void - SetViewMat( - const MT_Transform& trans - ); - - virtual - int + void ProcessLighting( - int layer + int layer, + const MT_Transform& trans )=0; virtual void SetClientObject( + RAS_IRasterizer* rasty, void* obj ); @@ -190,24 +183,6 @@ public: virtual void Render2DFilters(RAS_ICanvas* canvas)=0; - - virtual - class RAS_IPolyMaterial* - CreateBlenderPolyMaterial( - const STR_String &texname, - bool ba, - const STR_String& matname, - int tile, - int tilexrep, - int tileyrep, - int mode, - bool transparant, - bool zsort, - int lightlayer, - bool bIsTriangle, - void* clientobject, - void* tface - )=0; }; #endif //__RAS_IRENDERTOOLS diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp index 0015b6a251f..ad8d7ebd5b0 100644 --- a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp +++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp @@ -28,10 +28,6 @@ #include "RAS_MaterialBucket.h" -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #ifdef WIN32 #pragma warning (disable:4786) #include <windows.h> @@ -44,79 +40,423 @@ #include "RAS_MeshObject.h" #include "RAS_Deformer.h" // __NLA +/* mesh slot */ + +RAS_MeshSlot::RAS_MeshSlot() +{ + m_clientObj = NULL; + m_pDeformer = NULL; + m_OpenGLMatrix = NULL; + m_mesh = NULL; + m_bucket = NULL; + m_bVisible = false; + m_bCulled = true; + m_bObjectColor = false; + m_RGBAcolor = MT_Vector4(0.0, 0.0, 0.0, 0.0); + m_DisplayList = NULL; + m_bDisplayList = true; + m_joinSlot = NULL; +} + +RAS_MeshSlot::~RAS_MeshSlot() +{ + vector<RAS_DisplayArray*>::iterator it; + + Split(true); + + while(m_joinedSlots.size()) + m_joinedSlots.front()->Split(true); + for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { + (*it)->m_users--; + if((*it)->m_users == 0) + delete *it; + } + + if (m_DisplayList) { + m_DisplayList->Release(); + m_DisplayList = NULL; + } +} -KX_VertexIndex::KX_VertexIndex(int size) +RAS_MeshSlot::RAS_MeshSlot(const RAS_MeshSlot& slot) { - m_size = size; + vector<RAS_DisplayArray*>::iterator it; + + m_clientObj = NULL; + m_pDeformer = NULL; + m_OpenGLMatrix = NULL; + m_mesh = slot.m_mesh; + m_bucket = slot.m_bucket; + m_bVisible = slot.m_bVisible; + m_bCulled = slot.m_bCulled; + m_bObjectColor = slot.m_bObjectColor; + m_RGBAcolor = slot.m_RGBAcolor; + m_DisplayList = NULL; + m_bDisplayList = slot.m_bDisplayList; + m_joinSlot = NULL; + m_currentArray = slot.m_currentArray; + m_displayArrays = slot.m_displayArrays; + m_joinedSlots = slot.m_joinedSlots; + + m_startarray = slot.m_startarray; + m_startvertex = slot.m_startvertex; + m_startindex = slot.m_startindex; + m_endarray = slot.m_endarray; + m_endvertex = slot.m_endvertex; + m_endindex = slot.m_endindex; + + for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { + // don't copy display arrays for now because it breaks python + // access to vertices, but we'll need a solution if we want to + // join display arrays for reducing draw calls. + //*it = new RAS_DisplayArray(**it); + //(*it)->m_users = 1; + + (*it)->m_users++; + } } +void RAS_MeshSlot::init(RAS_MaterialBucket *bucket, int numverts) +{ + m_bucket = bucket; + + SetDisplayArray(numverts); + m_startarray = 0; + m_startvertex = 0; + m_startindex = 0; + m_endarray = 0; + m_endvertex = 0; + m_endindex = 0; +} -void KX_VertexIndex::SetIndex(short loc,unsigned int index) +void RAS_MeshSlot::begin(RAS_MeshSlot::iterator& it) { - m_indexarray[loc]=index; + int startvertex, endvertex; + int startindex, endindex; + + it.array = (m_displayArrays.size() > 0)? m_displayArrays[m_startarray]: NULL; + + if(it.array == NULL || it.array->m_index.size() == 0 || it.array->m_vertex.size() == 0) { + it.array = NULL; + it.vertex = NULL; + it.index = NULL; + it.startvertex = 0; + it.endvertex = 0; + it.totindex = 0; + } + else { + startvertex = m_startvertex; + endvertex = (m_startarray == m_endarray)? m_endvertex: it.array->m_vertex.size(); + startindex = m_startindex; + endindex = (m_startarray == m_endarray)? m_endindex: it.array->m_index.size(); + + it.vertex = &it.array->m_vertex[0]; + it.index = &it.array->m_index[startindex]; + it.startvertex = startvertex; + it.endvertex = endvertex; + it.totindex = endindex-startindex; + it.arraynum = m_startarray; + } } -bool KX_MeshSlot::Less(const KX_MeshSlot& lhs) const +void RAS_MeshSlot::next(RAS_MeshSlot::iterator& it) { - bool result = ((m_mesh < lhs.m_mesh ) || - ((m_mesh == lhs.m_mesh)&&(m_OpenGLMatrix < lhs.m_OpenGLMatrix))); - - return result; + int startvertex, endvertex; + int startindex, endindex; + + if(it.arraynum == (size_t)m_endarray) { + it.array = NULL; + it.vertex = NULL; + it.index = NULL; + it.startvertex = 0; + it.endvertex = 0; + it.totindex = 0; + } + else { + it.arraynum++; + it.array = m_displayArrays[it.arraynum]; + + startindex = 0; + endindex = (it.arraynum == (size_t)m_endarray)? m_endindex: it.array->m_index.size(); + startvertex = 0; + endvertex = (it.arraynum == (size_t)m_endarray)? m_endvertex: it.array->m_vertex.size(); + + it.vertex = &it.array->m_vertex[0]; + it.index = &it.array->m_index[startindex]; + it.startvertex = startvertex; + it.endvertex = endvertex; + it.totindex = endindex-startindex; + } } -KX_MeshSlot::~KX_MeshSlot() +bool RAS_MeshSlot::end(RAS_MeshSlot::iterator& it) { - if (m_DisplayList) - m_DisplayList->Release(); + return (it.array == NULL); } +RAS_DisplayArray *RAS_MeshSlot::CurrentDisplayArray() +{ + return m_currentArray; +} -RAS_MaterialBucket::RAS_MaterialBucket(RAS_IPolyMaterial* mat) - :m_bModified(true) +void RAS_MeshSlot::SetDisplayArray(int numverts) { - m_material = mat; + vector<RAS_DisplayArray*>::iterator it; + RAS_DisplayArray *darray = NULL; + + for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { + darray = *it; + + if(darray->m_type == numverts) { + if(darray->m_index.size()+numverts >= RAS_DisplayArray::BUCKET_MAX_INDEX) + darray = NULL; + else if(darray->m_vertex.size()+numverts >= RAS_DisplayArray::BUCKET_MAX_VERTEX) + darray = NULL; + else + break; + } + else + darray = NULL; + } + + if(!darray) { + darray = new RAS_DisplayArray(); + darray->m_users = 1; + + if(numverts == 2) darray->m_type = RAS_DisplayArray::LINE; + else if(numverts == 3) darray->m_type = RAS_DisplayArray::TRIANGLE; + else darray->m_type = RAS_DisplayArray::QUAD; + + m_displayArrays.push_back(darray); + + if(numverts == 2) + darray->m_type = RAS_DisplayArray::LINE; + else if(numverts == 3) + darray->m_type = RAS_DisplayArray::TRIANGLE; + else if(numverts == 4) + darray->m_type = RAS_DisplayArray::QUAD; + + m_endarray = m_displayArrays.size()-1; + m_endvertex = 0; + m_endindex = 0; + } + + m_currentArray = darray; } +void RAS_MeshSlot::AddPolygon(int numverts) +{ + SetDisplayArray(numverts); +} +int RAS_MeshSlot::AddVertex(const RAS_TexVert& tv) +{ + RAS_DisplayArray *darray; + int offset; + + darray = m_currentArray; + darray->m_vertex.push_back(tv); + offset = darray->m_vertex.size()-1; -RAS_IPolyMaterial* RAS_MaterialBucket::GetPolyMaterial() const -{ - return m_material; + if(darray == m_displayArrays[m_endarray]) + m_endvertex++; + + return offset; } +void RAS_MeshSlot::AddPolygonVertex(int offset) +{ + RAS_DisplayArray *darray; + + darray = m_currentArray; + darray->m_index.push_back(offset); + + if(darray == m_displayArrays[m_endarray]) + m_endindex++; +} +bool RAS_MeshSlot::Equals(RAS_MeshSlot *target) +{ + if(!m_OpenGLMatrix || !target->m_OpenGLMatrix) + return false; + if(m_pDeformer || target->m_pDeformer) + return false; + if(m_bVisible != target->m_bVisible) + return false; + if(m_bObjectColor != target->m_bObjectColor) + return false; + if(m_bObjectColor && !(m_RGBAcolor == target->m_RGBAcolor)) + return false; -void RAS_MaterialBucket::SetMeshSlot(KX_MeshSlot& ms) + return true; +} + +bool RAS_MeshSlot::Join(RAS_MeshSlot *target, MT_Scalar distance) { - m_meshSlots.insert(ms); + vector<RAS_DisplayArray*>::iterator it; + iterator mit; + size_t i; + + // verify if we can join + if(m_joinSlot || m_joinedSlots.size() || target->m_joinSlot) + return false; + + if(!Equals(target)) + return false; + + MT_Vector3 co(&m_OpenGLMatrix[12]); + MT_Vector3 targetco(&target->m_OpenGLMatrix[12]); + + if((co - targetco).length() > distance) + return false; + + MT_Matrix4x4 mat(m_OpenGLMatrix); + MT_Matrix4x4 targetmat(target->m_OpenGLMatrix); + targetmat.invert(); + + MT_Matrix4x4 transform = targetmat*mat; + + // m_mesh, clientobj + m_joinSlot = target; + m_joinInvTransform = transform; + m_joinInvTransform.invert(); + target->m_joinedSlots.push_back(this); + + MT_Matrix4x4 ntransform = m_joinInvTransform.transposed(); + ntransform[0][3]= ntransform[1][3]= ntransform[2][3]= 0.0f; + + for(begin(mit); !end(mit); next(mit)) + for(i=mit.startvertex; i<mit.endvertex; i++) + mit.vertex[i].Transform(transform, ntransform); + + for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { + target->m_displayArrays.push_back(*it); + target->m_endarray++; + target->m_endvertex = target->m_displayArrays.back()->m_vertex.size(); + target->m_endindex = target->m_displayArrays.back()->m_index.size(); + } + + if (m_DisplayList) { + m_DisplayList->Release(); + m_DisplayList = NULL; + } + if (target->m_DisplayList) { + target->m_DisplayList->Release(); + target->m_DisplayList = NULL; + } + + return true; +#if 0 + return false; +#endif } +bool RAS_MeshSlot::Split(bool force) +{ + list<RAS_MeshSlot*>::iterator jit; + RAS_MeshSlot *target = m_joinSlot; + vector<RAS_DisplayArray*>::iterator it, jt; + iterator mit; + size_t i, found0 = 0, found1 = 0; + + if(target && (force || !Equals(target))) { + m_joinSlot = NULL; + + for(jit=target->m_joinedSlots.begin(); jit!=target->m_joinedSlots.end(); jit++) { + if(*jit == this) { + target->m_joinedSlots.erase(jit); + found0 = 1; + break; + } + } + + if(!found0) + abort(); + + for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { + found1 = 0; + for(jt=target->m_displayArrays.begin(); jt!=target->m_displayArrays.end(); jt++) { + if(*jt == *it) { + target->m_displayArrays.erase(jt); + target->m_endarray--; + found1 = 1; + break; + } + } + + if(!found1) + abort(); + } + + if(target->m_displayArrays.size()) { + target->m_endvertex = target->m_displayArrays.back()->m_vertex.size(); + target->m_endindex = target->m_displayArrays.back()->m_index.size(); + } + else { + target->m_endvertex = 0; + target->m_endindex = 0; + } + + MT_Matrix4x4 ntransform = m_joinInvTransform.inverse().transposed(); + ntransform[0][3]= ntransform[1][3]= ntransform[2][3]= 0.0f; + + for(begin(mit); !end(mit); next(mit)) + for(i=mit.startvertex; i<mit.endvertex; i++) + mit.vertex[i].Transform(m_joinInvTransform, ntransform); + + if (target->m_DisplayList) { + target->m_DisplayList->Release(); + target->m_DisplayList = NULL; + } + + return true; + } + return false; +} -void RAS_MaterialBucket::RemoveMeshSlot(KX_MeshSlot& ms) +bool RAS_MeshSlot::IsCulled() { - T_MeshSlotList::iterator it = m_meshSlots.find(ms); + list<RAS_MeshSlot*>::iterator it; - if (!(it == m_meshSlots.end())) - m_meshSlots.erase(it); - + if(m_joinSlot) + return true; + if(!m_bCulled) + return false; + + for(it=m_joinedSlots.begin(); it!=m_joinedSlots.end(); it++) + if(!(*it)->m_bCulled) + return false; + + return true; } +/* material bucket sorting */ + +struct RAS_MaterialBucket::less +{ + bool operator()(const RAS_MaterialBucket* x, const RAS_MaterialBucket* y) const + { + return *x->GetPolyMaterial() < *y->GetPolyMaterial(); + } +}; + +/* material bucket */ +RAS_MaterialBucket::RAS_MaterialBucket(RAS_IPolyMaterial* mat) +{ + m_material = mat; +} -void RAS_MaterialBucket::MarkVisibleMeshSlot(KX_MeshSlot& ms, - bool visible, - bool color, - const MT_Vector4& rgbavec) +RAS_MaterialBucket::~RAS_MaterialBucket() { - T_MeshSlotList::iterator it = m_meshSlots.find(ms); - - assert (!(it == m_meshSlots.end())); - (*it).m_bVisible = visible; - (*it).m_bObjectColor = color; - (*it).m_RGBAcolor= rgbavec; +} + +RAS_IPolyMaterial* RAS_MaterialBucket::GetPolyMaterial() const +{ + return m_material; } bool RAS_MaterialBucket::IsAlpha() const @@ -129,162 +469,132 @@ bool RAS_MaterialBucket::IsZSort() const return (m_material->IsZSort()); } - - -void RAS_MaterialBucket::StartFrame() +RAS_MeshSlot* RAS_MaterialBucket::AddMesh(int numverts) { -} + RAS_MeshSlot *ms; + m_meshSlots.push_back(RAS_MeshSlot()); + + ms = &m_meshSlots.back(); + ms->init(this, numverts); + return ms; +} -void RAS_MaterialBucket::EndFrame() +RAS_MeshSlot* RAS_MaterialBucket::CopyMesh(RAS_MeshSlot *ms) { + m_meshSlots.push_back(RAS_MeshSlot(*ms)); + + return &m_meshSlots.back(); } -unsigned int RAS_MaterialBucket::NumMeshSlots() +void RAS_MaterialBucket::RemoveMesh(RAS_MeshSlot* ms) { - return m_meshSlots.size(); + list<RAS_MeshSlot>::iterator it; + + for(it=m_meshSlots.begin(); it!=m_meshSlots.end(); it++) { + if(&*it == ms) { + m_meshSlots.erase(it); + return; + } + } } -RAS_MaterialBucket::T_MeshSlotList::iterator RAS_MaterialBucket::msBegin() +list<RAS_MeshSlot>::iterator RAS_MaterialBucket::msBegin() { return m_meshSlots.begin(); } -RAS_MaterialBucket::T_MeshSlotList::iterator RAS_MaterialBucket::msEnd() +list<RAS_MeshSlot>::iterator RAS_MaterialBucket::msEnd() { return m_meshSlots.end(); } bool RAS_MaterialBucket::ActivateMaterial(const MT_Transform& cameratrans, RAS_IRasterizer* rasty, - RAS_IRenderTools *rendertools, RAS_IRasterizer::DrawMode &drawmode) + RAS_IRenderTools *rendertools) { - rendertools->SetViewMat(cameratrans); - if (!rasty->SetMaterial(*m_material)) return false; if (m_material->UsesLighting(rasty)) - rendertools->ProcessLighting(RAS_IRenderTools::RAS_LIGHT_OBJECT_LAYER/*m_material->GetLightLayer()*/); + rendertools->ProcessLighting(RAS_IRenderTools::RAS_LIGHT_OBJECT_LAYER, cameratrans); else - rendertools->ProcessLighting(-1); - - if(rasty->GetDrawingMode() < RAS_IRasterizer::KX_SOLID) - drawmode = RAS_IRasterizer::KX_MODE_LINES; - else if(m_material->UsesTriangles()) - drawmode = RAS_IRasterizer::KX_MODE_TRIANGLES; - else - drawmode = RAS_IRasterizer::KX_MODE_QUADS; + rendertools->ProcessLighting(-1, cameratrans); return true; } void RAS_MaterialBucket::RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRasterizer* rasty, - RAS_IRenderTools* rendertools, const KX_MeshSlot &ms, RAS_IRasterizer::DrawMode drawmode) + RAS_IRenderTools* rendertools, RAS_MeshSlot &ms) { - if (!ms.m_bVisible) - return; - m_material->ActivateMeshSlot(ms, rasty); - /* __NLA Do the deformation */ if (ms.m_pDeformer) { ms.m_pDeformer->Apply(m_material); // KX_ReInstanceShapeFromMesh(ms.m_mesh); // Recompute the physics mesh. (Can't call KX_* from RAS_) } - /* End __NLA */ - if (rasty->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID) - ms.m_mesh->SortPolygons(cameratrans*MT_Transform(ms.m_OpenGLMatrix)); + if(IsZSort() && rasty->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID) + ms.m_mesh->SortPolygons(ms, cameratrans*MT_Transform(ms.m_OpenGLMatrix)); rendertools->PushMatrix(); - rendertools->applyTransform(rasty,ms.m_OpenGLMatrix,m_material->GetDrawingMode()); + if (!ms.m_pDeformer || !ms.m_pDeformer->SkipVertexTransform()) + { + rendertools->applyTransform(rasty,ms.m_OpenGLMatrix,m_material->GetDrawingMode()); + } if(rasty->QueryLists()) - { if(ms.m_DisplayList) ms.m_DisplayList->SetModified(ms.m_mesh->MeshModified()); - } // verify if we can use display list, not for deformed object, and // also don't create a new display list when drawing shadow buffers, - // then it won't have texture coordinates for actual drawing - KX_ListSlot **displaylist; + // then it won't have texture coordinates for actual drawing. also + // for zsort we can't make a display list, since the polygon order + // changes all the time. if(ms.m_pDeformer) - displaylist = 0; + ms.m_bDisplayList = false; else if(!ms.m_DisplayList && rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW) - displaylist = 0; + ms.m_bDisplayList = false; + else if (IsZSort()) + ms.m_bDisplayList = false; + else if(m_material->UsesObjectColor() && ms.m_bObjectColor) + ms.m_bDisplayList = false; else - displaylist = &ms.m_DisplayList; + ms.m_bDisplayList = true; - // Use the text-specific IndexPrimitives for text faces + // for text drawing using faces if (m_material->GetDrawingMode() & RAS_IRasterizer::RAS_RENDER_3DPOLYGON_TEXT) - { - rasty->IndexPrimitives_3DText( - ms.m_mesh->GetVertexCache(m_material), - ms.m_mesh->GetIndexCache(m_material), - drawmode, - m_material, - rendertools, // needed for textprinting on polys - ms.m_bObjectColor, - ms.m_RGBAcolor); - } - - // for using glMultiTexCoord - else if((m_material->GetFlag() & RAS_MULTITEX)) - { - rasty->IndexPrimitivesMulti( - ms.m_mesh->GetVertexCache(m_material), - ms.m_mesh->GetIndexCache(m_material), - drawmode, - ms.m_bObjectColor, - ms.m_RGBAcolor, - displaylist); - } - - // Use the normal IndexPrimitives + rasty->IndexPrimitives_3DText(ms, m_material, rendertools); + // for multitexturing + else if((m_material->GetFlag() & (RAS_MULTITEX|RAS_BLENDERGLSL))) + rasty->IndexPrimitivesMulti(ms); + // use normal IndexPrimitives else - { - rasty->IndexPrimitives( - ms.m_mesh->GetVertexCache(m_material), - ms.m_mesh->GetIndexCache(m_material), - drawmode, - ms.m_bObjectColor, - ms.m_RGBAcolor, - displaylist); - } + rasty->IndexPrimitives(ms); - if(rasty->QueryLists()) { + if(rasty->QueryLists()) if(ms.m_DisplayList) ms.m_mesh->SetMeshModified(false); - } rendertools->PopMatrix(); } -void RAS_MaterialBucket::Render(const MT_Transform& cameratrans, - RAS_IRasterizer* rasty, - RAS_IRenderTools* rendertools) +void RAS_MaterialBucket::Optimize(MT_Scalar distance) { - if (m_meshSlots.begin()== m_meshSlots.end()) - return; - - //rendertools->SetViewMat(cameratrans); - - //rasty->SetMaterial(*m_material); + /* TODO: still have to check before this works correct: + * - lightlayer, frontface, text, billboard + * - make it work with physics */ - RAS_IRasterizer::DrawMode drawmode; - for (T_MeshSlotList::const_iterator it = m_meshSlots.begin(); - ! (it == m_meshSlots.end()); ++it) - { - rendertools->SetClientObject((*it).m_clientObj); - while (ActivateMaterial(cameratrans, rasty, rendertools, drawmode)) { - RenderMeshSlot(cameratrans, rasty, rendertools, *it, drawmode); - } - } - // to reset the eventual GL_CW mode - rendertools->SetClientObject(NULL); +#if 0 + list<RAS_MeshSlot>::iterator it; + list<RAS_MeshSlot>::iterator jt; + + // greed joining on all following buckets + for(it=m_meshSlots.begin(); it!=m_meshSlots.end(); it++) + for(jt=it, jt++; jt!=m_meshSlots.end(); jt++) + jt->Join(&*it, distance); +#endif } - diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.h b/source/gameengine/Rasterizer/RAS_MaterialBucket.h index 4eef889c533..475f01d549a 100644 --- a/source/gameengine/Rasterizer/RAS_MaterialBucket.h +++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.h @@ -36,30 +36,15 @@ #include "MT_Transform.h" #include "RAS_IPolygonMaterial.h" #include "RAS_IRasterizer.h" -#include "RAS_Deformer.h" // __NLA +#include "RAS_Deformer.h" + #include <vector> -#include <map> #include <set> +#include <list> using namespace std; -/** - * KX_VertexIndex - */ -struct KX_VertexIndex { -public: - KX_VertexIndex(int size); - void SetIndex(short loc,unsigned int index); - - // The vertex array - short m_vtxarray; - // An index into the vertex array for up to 4 verticies - unsigned short m_indexarray[4]; - short m_size; -}; +/* Display List Slot */ -/** - * KX_ListSlot. - */ class KX_ListSlot { protected: @@ -80,91 +65,149 @@ public: virtual void SetModified(bool mod)=0; }; -/** - * KX_MeshSlot. - */ -class KX_MeshSlot +class RAS_DisplayArray; +class RAS_MeshSlot; +class RAS_MeshMaterial; +class RAS_MaterialBucket; + +/* An array with data used for OpenGL drawing */ + +class RAS_DisplayArray { public: - void* m_clientObj; - RAS_Deformer* m_pDeformer; // __NLA - double* m_OpenGLMatrix; - class RAS_MeshObject* m_mesh; - mutable bool m_bVisible; // for visibility - mutable bool m_bObjectColor; - mutable MT_Vector4 m_RGBAcolor; - mutable KX_ListSlot* m_DisplayList; // for lists - KX_MeshSlot() : - m_pDeformer(NULL), - m_bVisible(true), - m_DisplayList(0) - { - } - ~KX_MeshSlot(); - bool Less(const KX_MeshSlot& lhs) const; + vector<RAS_TexVert> m_vertex; + vector<unsigned short> m_index; + enum { LINE = 2, TRIANGLE = 3, QUAD = 4 } m_type; + //RAS_MeshSlot *m_origSlot; + int m_users; + + enum { BUCKET_MAX_INDEX = 65535 }; + enum { BUCKET_MAX_VERTEX = 65535 }; }; +/* Entry of a RAS_MeshObject into RAS_MaterialBucket */ -inline bool operator <( const KX_MeshSlot& rhs,const KX_MeshSlot& lhs) +class RAS_MeshSlot { - return ( rhs.Less(lhs)); -} +private: + // indices into display arrays + int m_startarray; + int m_endarray; + int m_startindex; + int m_endindex; + int m_startvertex; + int m_endvertex; + vector<RAS_DisplayArray*> m_displayArrays; + + // for construction only + RAS_DisplayArray* m_currentArray; + +public: + // for rendering + RAS_MaterialBucket* m_bucket; + RAS_MeshObject* m_mesh; + void* m_clientObj; + RAS_Deformer* m_pDeformer; + double* m_OpenGLMatrix; + // visibility + bool m_bVisible; + bool m_bCulled; + // object color + bool m_bObjectColor; + MT_Vector4 m_RGBAcolor; + // display lists + KX_ListSlot* m_DisplayList; + bool m_bDisplayList; + // joined mesh slots + RAS_MeshSlot* m_joinSlot; + MT_Matrix4x4 m_joinInvTransform; + list<RAS_MeshSlot*> m_joinedSlots; + + RAS_MeshSlot(); + RAS_MeshSlot(const RAS_MeshSlot& slot); + virtual ~RAS_MeshSlot(); + + void init(RAS_MaterialBucket *bucket, int numverts); + + struct iterator { + RAS_DisplayArray *array; + RAS_TexVert *vertex; + unsigned short *index; + size_t startvertex; + size_t endvertex; + size_t totindex; + size_t arraynum; + }; + + void begin(iterator& it); + void next(iterator& it); + bool end(iterator& it); + + /* used during construction */ + void SetDisplayArray(int numverts); + RAS_DisplayArray *CurrentDisplayArray(); + + void AddPolygon(int numverts); + int AddVertex(const RAS_TexVert& tv); + void AddPolygonVertex(int offset); + + /* optimization */ + bool Split(bool force=false); + bool Join(RAS_MeshSlot *target, MT_Scalar distance); + bool Equals(RAS_MeshSlot *target); + bool IsCulled(); +}; + +/* Used by RAS_MeshObject, to point to it's slots in a bucket */ + +class RAS_MeshMaterial +{ +public: + RAS_MeshSlot *m_baseslot; + class RAS_MaterialBucket *m_bucket; + + GEN_Map<GEN_HashedPtr,RAS_MeshSlot*> m_slots; +}; + +/* Contains a list of display arrays with the same material, + * and a mesh slot for each mesh that uses display arrays in + * this bucket */ -/** - * Contains a list of meshs with the same material properties. - */ class RAS_MaterialBucket { public: - typedef std::set<KX_MeshSlot> T_MeshSlotList; - RAS_MaterialBucket(RAS_IPolyMaterial* mat); - virtual ~RAS_MaterialBucket() {} - - void Render(const MT_Transform& cameratrans, - class RAS_IRasterizer* rasty, - class RAS_IRenderTools* rendertools); + virtual ~RAS_MaterialBucket(); + /* Bucket Sorting */ + struct less; + typedef set<RAS_MaterialBucket*, less> Set; + + /* Material Properties */ RAS_IPolyMaterial* GetPolyMaterial() const; - bool IsAlpha() const; - bool IsZSort() const; + bool IsAlpha() const; + bool IsZSort() const; - static void StartFrame(); - static void EndFrame(); - - void SetMeshSlot(KX_MeshSlot& ms); - void RemoveMeshSlot(KX_MeshSlot& ms); - void MarkVisibleMeshSlot(KX_MeshSlot& ms, - bool visible, - bool color, - const MT_Vector4& rgbavec); - - void RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRasterizer* rasty, - RAS_IRenderTools* rendertools, const KX_MeshSlot &ms, RAS_IRasterizer::DrawMode drawmode); + /* Rendering */ bool ActivateMaterial(const MT_Transform& cameratrans, RAS_IRasterizer* rasty, - RAS_IRenderTools *rendertools, RAS_IRasterizer::DrawMode& drawmode); - - unsigned int NumMeshSlots(); - T_MeshSlotList::iterator msBegin(); - T_MeshSlotList::iterator msEnd(); - - struct less - { - bool operator()(const RAS_MaterialBucket* x, const RAS_MaterialBucket* y) const - { - return *x->GetPolyMaterial() < *y->GetPolyMaterial(); - } - }; + RAS_IRenderTools *rendertools); + void RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRasterizer* rasty, + RAS_IRenderTools* rendertools, RAS_MeshSlot &ms); - typedef set<RAS_MaterialBucket*, less> Set; + /* Mesh Slot Access */ + list<RAS_MeshSlot>::iterator msBegin(); + list<RAS_MeshSlot>::iterator msEnd(); + + class RAS_MeshSlot* AddMesh(int numverts); + class RAS_MeshSlot* CopyMesh(class RAS_MeshSlot *ms); + void RemoveMesh(class RAS_MeshSlot* ms); + void Optimize(MT_Scalar distance); + private: - - T_MeshSlotList m_meshSlots; - bool m_bModified; + list<RAS_MeshSlot> m_meshSlots; RAS_IPolyMaterial* m_material; - double* m_pOGLMatrix; }; -#endif //__KX_BUCKET +#endif //__RAS_MATERIAL_BUCKET diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.cpp b/source/gameengine/Rasterizer/RAS_MeshObject.cpp index af5228e4c35..a907994bf57 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.cpp +++ b/source/gameengine/Rasterizer/RAS_MeshObject.cpp @@ -26,10 +26,6 @@ * ***** END GPL LICENSE BLOCK ***** */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #include "RAS_MeshObject.h" #include "RAS_IRasterizer.h" #include "MT_MinMax.h" @@ -37,62 +33,84 @@ #include <algorithm> +/* polygon sorting */ -STR_String RAS_MeshObject::s_emptyname = ""; +struct RAS_MeshObject::polygonSlot +{ + float m_z; + int m_index[4]; + + polygonSlot() {} + /* pnorm is the normal from the plane equation that the distance from is + * used to sort again. */ + void get(const RAS_TexVert *vertexarray, const unsigned short *indexarray, + int offset, int nvert, const MT_Vector3& pnorm) + { + MT_Vector3 center(0, 0, 0); + int i; + for(i=0; i<nvert; i++) { + m_index[i] = indexarray[offset+i]; + center += vertexarray[m_index[i]].getXYZ(); + } -KX_ArrayOptimizer::~KX_ArrayOptimizer() -{ - for (vector<KX_VertexArray*>::iterator itv = m_VertexArrayCache1.begin(); - !(itv == m_VertexArrayCache1.end());++itv) - { - delete (*itv); + /* note we don't divide center by the number of vertices, since all + * polygons have the same number of vertices, and that we leave out + * the 4-th component of the plane equation since it is constant. */ + m_z = MT_dot(pnorm, center); } - for (vector<KX_IndexArray*>::iterator iti = m_IndexArrayCache1.begin(); - !(iti == m_IndexArrayCache1.end());++iti) + void set(unsigned short *indexarray, int offset, int nvert) { - delete (*iti); + int i; + + for(i=0; i<nvert; i++) + indexarray[offset+i] = m_index[i]; } +}; - m_TriangleArrayCount.clear(); - m_VertexArrayCache1.clear(); - m_IndexArrayCache1.clear(); - +struct RAS_MeshObject::backtofront +{ + bool operator()(const polygonSlot &a, const polygonSlot &b) const + { + return a.m_z < b.m_z; + } +}; -} +struct RAS_MeshObject::fronttoback +{ + bool operator()(const polygonSlot &a, const polygonSlot &b) const + { + return a.m_z > b.m_z; + } +}; +/* mesh object */ +STR_String RAS_MeshObject::s_emptyname = ""; RAS_MeshObject::RAS_MeshObject(Mesh* mesh, int lightlayer) - : m_bModified(true), - m_lightlayer(lightlayer), - m_zsort(false), - m_MeshMod(true), + : m_lightlayer(lightlayer), + m_bModified(true), + m_bMeshModified(true), m_mesh(mesh), - m_class(0) + m_bDeformed(false) { } - -bool RAS_MeshObject::MeshModified() -{ - return m_MeshMod; -} - - RAS_MeshObject::~RAS_MeshObject() { - for (vector<RAS_Polygon*>::iterator it=m_Polygons.begin();!(it==m_Polygons.end());it++) - { - delete (*it); - } + vector<RAS_Polygon*>::iterator it; - ClearArrayData(); + for(it=m_Polygons.begin(); it!=m_Polygons.end(); it++) + delete (*it); } - +bool RAS_MeshObject::MeshModified() +{ + return m_bMeshModified; +} unsigned int RAS_MeshObject::GetLightLayer() { @@ -108,18 +126,21 @@ int RAS_MeshObject::NumMaterials() const STR_String& RAS_MeshObject::GetMaterialName(unsigned int matid) { - RAS_MaterialBucket* bucket = GetMaterialBucket(matid); + RAS_MeshMaterial* mmat = GetMeshMaterial(matid); + + if(mmat) + return mmat->m_bucket->GetPolyMaterial()->GetMaterialName(); - return bucket?bucket->GetPolyMaterial()->GetMaterialName():s_emptyname; + return s_emptyname; } -RAS_MaterialBucket* RAS_MeshObject::GetMaterialBucket(unsigned int matid) +RAS_MeshMaterial* RAS_MeshObject::GetMeshMaterial(unsigned int matid) { if (m_materials.size() > 0 && (matid < m_materials.size())) { - RAS_MaterialBucket::Set::const_iterator it = m_materials.begin(); + list<RAS_MeshMaterial>::iterator it = m_materials.begin(); while (matid--) ++it; - return *it; + return &*it; } return NULL; @@ -134,21 +155,24 @@ int RAS_MeshObject::NumPolygons() -RAS_Polygon* RAS_MeshObject::GetPolygon(int num) +RAS_Polygon* RAS_MeshObject::GetPolygon(int num) const { return m_Polygons[num]; } -RAS_MaterialBucket::Set::iterator RAS_MeshObject::GetFirstMaterial() + + list<RAS_MeshMaterial>::iterator GetFirstMaterial(); + list<RAS_MeshMaterial>::iterator GetLastMaterial(); +list<RAS_MeshMaterial>::iterator RAS_MeshObject::GetFirstMaterial() { return m_materials.begin(); } -RAS_MaterialBucket::Set::iterator RAS_MeshObject::GetLastMaterial() +list<RAS_MeshMaterial>::iterator RAS_MeshObject::GetLastMaterial() { return m_materials.end(); } @@ -171,377 +195,238 @@ const STR_String& RAS_MeshObject::GetName() const STR_String& RAS_MeshObject::GetTextureName(unsigned int matid) { - RAS_MaterialBucket* bucket = GetMaterialBucket(matid); + RAS_MeshMaterial* mmat = GetMeshMaterial(matid); - return bucket?bucket->GetPolyMaterial()->GetTextureName():s_emptyname; + if(mmat) + return mmat->m_bucket->GetPolyMaterial()->GetTextureName(); + + return s_emptyname; } +RAS_MeshMaterial *RAS_MeshObject::GetMeshMaterial(RAS_IPolyMaterial *mat) +{ + list<RAS_MeshMaterial>::iterator mit; + /* find a mesh material */ + for(mit = m_materials.begin(); mit != m_materials.end(); mit++) + if(mit->m_bucket->GetPolyMaterial() == mat) + return &*mit; -void RAS_MeshObject::AddPolygon(RAS_Polygon* poly) -{ - m_Polygons.push_back(poly); + return NULL; } +RAS_Polygon* RAS_MeshObject::AddPolygon(RAS_MaterialBucket *bucket, int numverts) +{ + RAS_MeshMaterial *mmat; + RAS_Polygon *poly; + RAS_MeshSlot *slot; + /* find a mesh material */ + mmat = GetMeshMaterial(bucket->GetPolyMaterial()); + + /* none found, create a new one */ + if(!mmat) { + RAS_MeshMaterial meshmat; + meshmat.m_bucket = bucket; + meshmat.m_baseslot = meshmat.m_bucket->AddMesh(numverts); + m_materials.push_back(meshmat); + mmat = &m_materials.back(); + } + + /* add it to the bucket, this also adds new display arrays */ + slot = mmat->m_baseslot; + slot->AddPolygon(numverts); + + /* create a new polygon */ + RAS_DisplayArray *darray = slot->CurrentDisplayArray(); + poly = new RAS_Polygon(bucket, darray, numverts); + m_Polygons.push_back(poly); + + return poly; +} void RAS_MeshObject::DebugColor(unsigned int abgr) { -/* - int numpolys = NumPolygons(); - for (int i=0;i<numpolys;i++) - { + /*int numpolys = NumPolygons(); + + for (int i=0;i<numpolys;i++) { RAS_Polygon* poly = m_polygons[i]; for (int v=0;v<poly->VertexCount();v++) - { - RAS_TexVert* vtx = poly->GetVertex(v); - vtx->setDebugRGBA(abgr); - } + RAS_TexVert* vtx = poly->GetVertex(v)->setDebugRGBA(abgr); } */ - m_debugcolor = abgr; + /* m_debugcolor = abgr; */ } void RAS_MeshObject::SetVertexColor(RAS_IPolyMaterial* mat,MT_Vector4 rgba) { - const vecVertexArray & vertexvec = GetVertexCache(mat); - - for (vector<KX_VertexArray*>::const_iterator it = vertexvec.begin(); it != vertexvec.end(); ++it) - { - KX_VertexArray::iterator vit; - for (vit=(*it)->begin(); vit != (*it)->end(); vit++) - { - vit->SetRGBA(rgba); - } - } -} - -void RAS_MeshObject::SchedulePoly(const KX_VertexIndex& idx, - int numverts, - RAS_IPolyMaterial* mat) -{ - KX_ArrayOptimizer* ao = GetArrayOptimizer(mat); - - ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[0]); - ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[1]); - ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[2]); - - if (!mat->UsesTriangles()) - ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[3]); -} + RAS_MeshMaterial *mmat = GetMeshMaterial(mat); + RAS_MeshSlot *slot = mmat->m_baseslot; + RAS_MeshSlot::iterator it; + size_t i; + + for(slot->begin(it); !slot->end(it); slot->next(it)) + for(i=it.startvertex; i<it.endvertex; i++) + it.vertex[i].SetRGBA(rgba); +} + +void RAS_MeshObject::AddVertex(RAS_Polygon *poly, int i, + const MT_Point3& xyz, + const MT_Point2& uv, + const MT_Point2& uv2, + const MT_Vector4& tangent, + const unsigned int rgba, + const MT_Vector3& normal, + bool flat, + int origindex) +{ + RAS_TexVert texvert(xyz, uv, uv2, tangent, rgba, normal, flat, origindex); + RAS_MeshMaterial *mmat; + RAS_DisplayArray *darray; + RAS_MeshSlot *slot; + int offset; + + mmat = GetMeshMaterial(poly->GetMaterial()->GetPolyMaterial()); + slot = mmat->m_baseslot; + darray = slot->CurrentDisplayArray(); + if(!flat) { + /* find vertices shared between faces, with the restriction + * that they exist in the same display array, and have the + * same uv coordinate etc */ + vector<SharedVertex>& sharedmap = m_sharedvertex_map[origindex]; + vector<SharedVertex>::iterator it; -void RAS_MeshObject::ScheduleWireframePoly(const KX_VertexIndex& idx, - int numverts, - int edgecode, - RAS_IPolyMaterial* mat) -{ - //int indexpos = m_IndexArrayCount[idx.m_vtxarray]; - int edgetrace = 1<<(numverts-1); - bool drawedge = (edgecode & edgetrace)!=0; - edgetrace = 1; - int prevvert = idx.m_indexarray[numverts-1]; - KX_ArrayOptimizer* ao = GetArrayOptimizer(mat); - - for (int v = 0; v < numverts; v++) - { - unsigned int curvert = idx.m_indexarray[v]; - if (drawedge) + for(it = sharedmap.begin(); it != sharedmap.end(); it++) { - ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(prevvert); - ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(curvert); + if(it->m_darray != darray) + continue; + if(!it->m_darray->m_vertex[it->m_offset].closeTo(&texvert)) + continue; + + /* found one, add it and we're done */ + if(poly->IsVisible()) + slot->AddPolygonVertex(it->m_offset); + poly->SetVertexOffset(i, it->m_offset); + return; } - prevvert = curvert; - drawedge = (edgecode & edgetrace)!=0; - edgetrace*=2; } - //m_IndexArrayCount[idx.m_vtxarray] = indexpos; -} -int RAS_MeshObject::FindOrAddVertex(int vtxarray, - const MT_Point3& xyz, - const MT_Point2& uv, - const MT_Point2& uv2, - const MT_Vector4& tangent, - const unsigned int rgbacolor, - const MT_Vector3& normal, - bool flat, - RAS_IPolyMaterial* mat, - int origindex) -{ - KX_ArrayOptimizer* ao = GetArrayOptimizer(mat); - - int numverts = ao->m_VertexArrayCache1[vtxarray]->size();//m_VertexArrayCount[vtxarray]; - RAS_TexVert newvert(xyz,uv,uv2,tangent,rgbacolor,normal, flat? TV_CALCFACENORMAL: 0,origindex); + /* no shared vertex found, add a new one */ + offset = slot->AddVertex(texvert); + if(poly->IsVisible()) + slot->AddPolygonVertex(offset); + poly->SetVertexOffset(i, offset); -#define KX_FIND_SHARED_VERTICES -#ifdef KX_FIND_SHARED_VERTICES if(!flat) { - for (std::vector<RAS_MatArrayIndex>::iterator it = m_xyz_index_to_vertex_index_mapping[origindex].begin(); - it != m_xyz_index_to_vertex_index_mapping[origindex].end(); - it++) - { - if ((*it).m_arrayindex1 == ao->m_index1 && - (*it).m_array == vtxarray && - *(*it).m_matid == *mat && - (*ao->m_VertexArrayCache1[vtxarray])[(*it).m_index].closeTo(&newvert) - ) - { - return (*it).m_index; - } - } + SharedVertex shared; + shared.m_darray = darray; + shared.m_offset = offset; + m_sharedvertex_map[origindex].push_back(shared); } -#endif // KX_FIND_SHARED_VERTICES - - // no vertex found, add one - ao->m_VertexArrayCache1[vtxarray]->push_back(newvert); - // printf("(%f,%f,%f) ",xyz[0],xyz[1],xyz[2]); - RAS_MatArrayIndex idx; - idx.m_arrayindex1 = ao->m_index1; - idx.m_array = vtxarray; - idx.m_index = numverts; - idx.m_matid = mat; - m_xyz_index_to_vertex_index_mapping[origindex].push_back(idx); - - return numverts; } -vecVertexArray& RAS_MeshObject::GetVertexCache (RAS_IPolyMaterial* mat) +int RAS_MeshObject::NumVertices(RAS_IPolyMaterial* mat) { - KX_ArrayOptimizer* ao = GetArrayOptimizer(mat); - - return ao->m_VertexArrayCache1; -} + RAS_MeshMaterial *mmat; + RAS_MeshSlot *slot; + RAS_MeshSlot::iterator it; + size_t len = 0; -int RAS_MeshObject::GetVertexArrayLength(RAS_IPolyMaterial* mat) -{ - int len = 0; - - const vecVertexArray & vertexvec = GetVertexCache(mat); - vector<KX_VertexArray*>::const_iterator it = vertexvec.begin(); + mmat = GetMeshMaterial(mat); + slot = mmat->m_baseslot; + for(slot->begin(it); !slot->end(it); slot->next(it)) + len += it.endvertex - it.startvertex; - for (; it != vertexvec.end(); ++it) - { - len += (*it)->size(); - } - return len; } - RAS_TexVert* RAS_MeshObject::GetVertex(unsigned int matid, unsigned int index) { - RAS_TexVert* vertex = NULL; - - RAS_MaterialBucket* bucket = GetMaterialBucket(matid); - if (bucket) - { - RAS_IPolyMaterial* mat = bucket->GetPolyMaterial(); - if (mat) - { - const vecVertexArray & vertexvec = GetVertexCache(mat); - vector<KX_VertexArray*>::const_iterator it = vertexvec.begin(); - - for (unsigned int len = 0; it != vertexvec.end(); ++it) - { - if (index < len + (*it)->size()) - { - vertex = &(*(*it))[index-len]; - break; - } - else - { - len += (*it)->size(); - } - } - } - } - - return vertex; -} - - + RAS_MeshMaterial *mmat; + RAS_MeshSlot *slot; + RAS_MeshSlot::iterator it; + size_t len; -const vecIndexArrays& RAS_MeshObject::GetIndexCache (RAS_IPolyMaterial* mat) -{ - KX_ArrayOptimizer* ao = GetArrayOptimizer(mat); - - return ao->m_IndexArrayCache1; -} + mmat = GetMeshMaterial(matid); - - -KX_ArrayOptimizer* RAS_MeshObject::GetArrayOptimizer(RAS_IPolyMaterial* polymat) -{ - KX_ArrayOptimizer** aop = m_matVertexArrayS[polymat]; - - if(aop) - return *aop; + if(!mmat) + return NULL; - // didn't find array, but an array might already exist - // for a material equal to this one - for(int i=0;i<m_matVertexArrayS.size();i++) { - RAS_IPolyMaterial *mat = (RAS_IPolyMaterial*)(m_matVertexArrayS.getKey(i)->getValue()); - if(*mat == *polymat) { - m_matVertexArrayS.insert(polymat, *m_matVertexArrayS.at(i)); - return *m_matVertexArrayS.at(i); - } + slot = mmat->m_baseslot; + len = 0; + for(slot->begin(it); !slot->end(it); slot->next(it)) { + if(index >= len + it.endvertex - it.startvertex) + len += it.endvertex - it.startvertex; + else + return &it.vertex[index - len]; } - - // create new array - int numelements = m_matVertexArrayS.size(); - m_sortedMaterials.push_back(polymat); - - KX_ArrayOptimizer* ao = new KX_ArrayOptimizer(numelements); - m_matVertexArrayS.insert(polymat, ao); - return ao; + return NULL; } - - -void RAS_MeshObject::Bucketize(double* oglmatrix, - void* clientobj, - bool useObjectColor, - const MT_Vector4& rgbavec) +void RAS_MeshObject::AddMeshUser(void *clientobj) { - KX_MeshSlot ms; - ms.m_clientObj = clientobj; - ms.m_mesh = this; - ms.m_OpenGLMatrix = oglmatrix; - ms.m_bObjectColor = useObjectColor; - ms.m_RGBAcolor = rgbavec; - - for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it) - { - RAS_MaterialBucket* bucket = *it; -// KX_ArrayOptimizer* oa = GetArrayOptimizer(bucket->GetPolyMaterial()); - bucket->SetMeshSlot(ms); - } + list<RAS_MeshMaterial>::iterator it; -} - - - -void RAS_MeshObject::MarkVisible(double* oglmatrix, - void* clientobj, - bool visible, - bool useObjectColor, - const MT_Vector4& rgbavec) -{ - KX_MeshSlot ms; - ms.m_clientObj = clientobj; - ms.m_mesh = this; - ms.m_OpenGLMatrix = oglmatrix; - ms.m_RGBAcolor = rgbavec; - ms.m_bObjectColor= useObjectColor; - - for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it) - { - RAS_MaterialBucket* bucket = *it; -// KX_ArrayOptimizer* oa = GetArrayOptimizer(bucket->GetPolyMaterial()); - bucket->MarkVisibleMeshSlot(ms,visible,useObjectColor,rgbavec); + for(it = m_materials.begin();it!=m_materials.end();++it) { + /* always copy from the base slot, which is never removed + * since new objects can be created with the same mesh data */ + RAS_MeshSlot *ms = it->m_bucket->CopyMesh(it->m_baseslot); + ms->m_clientObj = clientobj; + it->m_slots.insert(clientobj, ms); } } - -void RAS_MeshObject::RemoveFromBuckets(double* oglmatrix, - void* clientobj) +void RAS_MeshObject::UpdateBuckets(void* clientobj, + double* oglmatrix, + bool useObjectColor, + const MT_Vector4& rgbavec, + bool visible, + bool culled) { - KX_MeshSlot ms; - ms.m_clientObj = clientobj; - ms.m_mesh = this; - ms.m_OpenGLMatrix = oglmatrix; - - for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it) - { - RAS_MaterialBucket* bucket = *it; -// RAS_IPolyMaterial* polymat = bucket->GetPolyMaterial(); - //KX_ArrayOptimizer* oa = GetArrayOptimizer(polymat); - bucket->RemoveMeshSlot(ms); - } - -} - - + list<RAS_MeshMaterial>::iterator it; -/* - * RAS_MeshObject::GetVertex returns the vertex located somewhere in the vertexpool - * it is the clients responsibility to make sure the array and index are valid - */ -RAS_TexVert* RAS_MeshObject::GetVertex(short array, - unsigned int index, - RAS_IPolyMaterial* polymat) -{ - KX_ArrayOptimizer* ao = GetArrayOptimizer(polymat); - return &((*(ao->m_VertexArrayCache1)[array])[index]); -} + for(it = m_materials.begin();it!=m_materials.end();++it) { + RAS_MeshSlot **msp = it->m_slots[clientobj]; + if(!msp) + continue; + RAS_MeshSlot *ms = *msp; -void RAS_MeshObject::ClearArrayData() -{ - for (int i=0;i<m_matVertexArrayS.size();i++) { - KX_ArrayOptimizer** ao = m_matVertexArrayS.at(i); - - // we have duplicate entries, only free once - for(int j=i+1;j<m_matVertexArrayS.size();j++) { - if(ao == m_matVertexArrayS.at(j)) { - ao = NULL; - break; - } - } + ms->m_mesh = this; + ms->m_OpenGLMatrix = oglmatrix; + ms->m_bObjectColor = useObjectColor; + ms->m_RGBAcolor = rgbavec; + ms->m_bVisible = visible; + ms->m_bCulled = culled || !visible; - if (ao) - delete *ao; + /* split if necessary */ + ms->Split(); } } - - -/** - * RAS_MeshObject::CreateNewVertices creates vertices within sorted pools of vertices that share same material -*/ -int RAS_MeshObject::FindVertexArray(int numverts, - RAS_IPolyMaterial* polymat) +void RAS_MeshObject::RemoveFromBuckets(void *clientobj) { -// bool found=false; - int array=-1; + list<RAS_MeshMaterial>::iterator it; - KX_ArrayOptimizer* ao = GetArrayOptimizer(polymat); + for(it = m_materials.begin();it!=m_materials.end();++it) { + RAS_MeshSlot **msp = it->m_slots[clientobj]; - for (unsigned int i=0;i<ao->m_VertexArrayCache1.size();i++) - { - if ( (ao->m_TriangleArrayCount[i] + (numverts-2)) < BUCKET_MAX_TRIANGLES) - { - if((ao->m_VertexArrayCache1[i]->size()+numverts < BUCKET_MAX_INDICES)) - { - array = i; - ao->m_TriangleArrayCount[array]+=numverts-2; - break; - } - } - } + if(!msp) + continue; - if (array == -1) - { - array = ao->m_VertexArrayCache1.size(); - vector<RAS_TexVert>* va = new vector<RAS_TexVert>; - ao->m_VertexArrayCache1.push_back(va); - KX_IndexArray *ia = new KX_IndexArray(); - ao->m_IndexArrayCache1.push_back(ia); - ao->m_TriangleArrayCount.push_back(numverts-2); - } + RAS_MeshSlot *ms = *msp; - return array; + it->m_bucket->RemoveMesh(ms); + it->m_slots.remove(clientobj); + } } - - - //void RAS_MeshObject::Transform(const MT_Transform& trans) //{ //m_trans.translate(MT_Vector3(0,0,1));//.operator *=(trans); @@ -563,71 +448,7 @@ void RAS_MeshObject::RelativeTransform(const MT_Vector3& vec) } */ - - -void RAS_MeshObject::UpdateMaterialList() -{ - m_materials.clear(); - unsigned int numpolys = m_Polygons.size(); - // for all polygons, find out which material they use, and add it to the set of materials - for (unsigned int i=0;i<numpolys;i++) - { - m_materials.insert(m_Polygons[i]->GetMaterial()); - } -} - -struct RAS_MeshObject::polygonSlot -{ - float m_z; - int m_index[4]; - - polygonSlot() {} - - /* pnorm is the normal from the plane equation that the distance from is - * used to sort again. */ - void get(const KX_VertexArray& vertexarray, const KX_IndexArray& indexarray, - int offset, int nvert, const MT_Vector3& pnorm) - { - MT_Vector3 center(0, 0, 0); - int i; - - for(i=0; i<nvert; i++) { - m_index[i] = indexarray[offset+i]; - center += vertexarray[m_index[i]].getLocalXYZ(); - } - - /* note we don't divide center by the number of vertices, since all - * polygons have the same number of vertices, and that we leave out - * the 4-th component of the plane equation since it is constant. */ - m_z = MT_dot(pnorm, center); - } - - void set(KX_IndexArray& indexarray, int offset, int nvert) - { - int i; - - for(i=0; i<nvert; i++) - indexarray[offset+i] = m_index[i]; - } -}; - -struct RAS_MeshObject::backtofront -{ - bool operator()(const polygonSlot &a, const polygonSlot &b) const - { - return a.m_z < b.m_z; - } -}; - -struct RAS_MeshObject::fronttoback -{ - bool operator()(const polygonSlot &a, const polygonSlot &b) const - { - return a.m_z > b.m_z; - } -}; - -void RAS_MeshObject::SortPolygons(const MT_Transform &transform) +void RAS_MeshObject::SortPolygons(RAS_MeshSlot& ms, const MT_Transform &transform) { // Limitations: sorting is quite simple, and handles many // cases wrong, partially due to polygons being sorted per @@ -645,43 +466,34 @@ void RAS_MeshObject::SortPolygons(const MT_Transform &transform) // to avoid excessive state changes while drawing. e) would // require splitting polygons. - if (!m_zsort) - return; + RAS_MeshSlot::iterator it; + size_t j; - // Extract camera Z plane... - const MT_Vector3 pnorm(transform.getBasis()[2]); - // unneeded: const MT_Scalar pval = transform.getOrigin()[2]; + for(ms.begin(it); !ms.end(it); ms.next(it)) { + unsigned int nvert = (int)it.array->m_type; + unsigned int totpoly = it.totindex/nvert; - for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it) - { - if(!(*it)->IsZSort()) + if(totpoly <= 1) + continue; + if(it.array->m_type == RAS_DisplayArray::LINE) continue; - RAS_IPolyMaterial *mat = (*it)->GetPolyMaterial(); - KX_ArrayOptimizer* ao = GetArrayOptimizer(mat); - - vecIndexArrays& indexarrays = ao->m_IndexArrayCache1; - vecVertexArray& vertexarrays = ao->m_VertexArrayCache1; - unsigned int i, j, nvert = (mat->UsesTriangles())? 3: 4; - - for(i=0; i<indexarrays.size(); i++) { - KX_IndexArray& indexarray = *indexarrays[i]; - KX_VertexArray& vertexarray = *vertexarrays[i]; + // Extract camera Z plane... + const MT_Vector3 pnorm(transform.getBasis()[2]); + // unneeded: const MT_Scalar pval = transform.getOrigin()[2]; - unsigned int totpoly = indexarray.size()/nvert; - vector<polygonSlot> slots(totpoly); + vector<polygonSlot> slots(totpoly); - /* get indices and z into temporary array */ - for(j=0; j<totpoly; j++) - slots[j].get(vertexarray, indexarray, j*nvert, nvert, pnorm); + /* get indices and z into temporary array */ + for(j=0; j<totpoly; j++) + slots[j].get(it.vertex, it.index, j*nvert, nvert, pnorm); - /* sort (stable_sort might be better, if flickering happens?) */ - std::sort(slots.begin(), slots.end(), backtofront()); + /* sort (stable_sort might be better, if flickering happens?) */ + std::sort(slots.begin(), slots.end(), backtofront()); - /* get indices from temporary array again */ - for(j=0; j<totpoly; j++) - slots[j].set(indexarray, j*nvert, nvert); - } + /* get indices from temporary array again */ + for(j=0; j<totpoly; j++) + slots[j].set(it.index, j*nvert, nvert); } } @@ -690,37 +502,8 @@ void RAS_MeshObject::SchedulePolygons(int drawingmode) { if (m_bModified) { - int i, numpolys = m_Polygons.size(); - - for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it) - if ((*it)->IsZSort()) - m_zsort = true; - - if (drawingmode == RAS_IRasterizer::KX_WIREFRAME) - { - for (i=0;i<numpolys;i++) - { - RAS_Polygon* poly = m_Polygons[i]; - if (poly->IsVisible()) - ScheduleWireframePoly(poly->GetVertexIndexBase(),poly->VertexCount(),poly->GetEdgeCode(), - poly->GetMaterial()->GetPolyMaterial()); - - } - m_zsort = false; - } - else - { - for (i=0;i<numpolys;i++) - { - RAS_Polygon* poly = m_Polygons[i]; - if (poly->IsVisible()) - SchedulePoly(poly->GetVertexIndexBase(),poly->VertexCount(), - poly->GetMaterial()->GetPolyMaterial()); - } - } - m_bModified = false; - m_MeshMod = true; + m_bMeshModified = true; } } diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.h b/source/gameengine/Rasterizer/RAS_MeshObject.h index 99806666fa6..0d35a2f402b 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.h +++ b/source/gameengine/Rasterizer/RAS_MeshObject.h @@ -36,6 +36,7 @@ #include <vector> #include <set> +#include <list> #include "RAS_Polygon.h" #include "RAS_MaterialBucket.h" @@ -44,194 +45,71 @@ #include "GEN_HashedPtr.h" struct Mesh; -/** - * This class holds an array of vertices and indicies. - */ -class KX_ArrayOptimizer -{ -public: - KX_ArrayOptimizer(int index) - : m_index1(index) - {}; - virtual ~KX_ArrayOptimizer(); - - vector<KX_VertexArray*> m_VertexArrayCache1; - vector<int> m_TriangleArrayCount; - vector<KX_IndexArray*> m_IndexArrayCache1; - - /** - order in which they are stored into the mesh - */ - int m_index1; -}; - -/** - * This struct holds a triangle. - */ -struct RAS_TriangleIndex -{ -public: - int m_index[3]; - int m_array; - RAS_IPolyMaterial* m_matid; - bool m_collider; -}; - -/** - * This class looks horribly broken. Only m_matid is used, and - * m_matid is a (int) RAS_IPolyMaterial*. - * --> m_matid == lhs.m_matid should be *m_matid == *lhs.m_matid - */ -class RAS_MatArrayIndex -{ -public: - int m_arrayindex1; - RAS_IPolyMaterial* m_matid; - int m_array; - int m_index; - -/* - inline bool Less(const RAS_MatArrayIndex& lhs) const { - bool result = - ( (m_matid < lhs.m_matid) || - ((m_matid == lhs.m_matid)&&(m_array < lhs.m_array)) || - ((m_matid == lhs.m_matid) && (m_array == lhs.m_array) && - (m_index < lhs.m_index)) - - ); - return result; - - } -*/ - -}; -/* -inline bool operator <( const RAS_MatArrayIndex& rhs,const RAS_MatArrayIndex& lhs) -{ - return ( rhs.Less(lhs)); -}*/ +/* RAS_MeshObject is a mesh used for rendering. It stores polygons, + * but the actual vertices and index arrays are stored in material + * buckets, referenced by the list of RAS_MeshMaterials. */ -/** - * RAS_MeshObject stores mesh data for the renderer. - */ class RAS_MeshObject { - - // GEN_Map<class RAS_IPolyMaterial,KX_ArrayOptimizer*> m_matVertexArrayS; - //vector<class RAS_IPolyMaterial*,KX_ArrayOptimizer> m_vertexArrays; - virtual KX_ArrayOptimizer* GetArrayOptimizer(RAS_IPolyMaterial* polymat); - //vector<RAS_Polygon*> m_polygons; - +private: unsigned int m_debugcolor; - bool m_bModified; int m_lightlayer; - - vector<class RAS_Polygon*> m_Polygons; + + bool m_bModified; + bool m_bMeshModified; + STR_String m_name; static STR_String s_emptyname; - bool m_zsort; - bool m_MeshMod; + vector<class RAS_Polygon*> m_Polygons; + + /* polygon sorting */ struct polygonSlot; struct backtofront; struct fronttoback; - void SchedulePoly( - const KX_VertexIndex& idx, - int numverts, - RAS_IPolyMaterial* mat - ); - - void ScheduleWireframePoly( - const KX_VertexIndex& idx, - int numverts, - int edgecode, - RAS_IPolyMaterial* mat - ); - protected: - enum { BUCKET_MAX_INDICES = 65535 };//2048};//8192}; - enum { BUCKET_MAX_TRIANGLES = 65535 }; - - GEN_Map<GEN_HashedPtr,KX_ArrayOptimizer*> m_matVertexArrayS; - - RAS_MaterialBucket::Set m_materials; + list<RAS_MeshMaterial> m_materials; Mesh* m_mesh; + bool m_bDeformed; + public: // for now, meshes need to be in a certain layer (to avoid sorting on lights in realtime) RAS_MeshObject(Mesh* mesh, int lightlayer); virtual ~RAS_MeshObject(); - vector<RAS_IPolyMaterial*> m_sortedMaterials; - vector<vector<RAS_MatArrayIndex> > m_xyz_index_to_vertex_index_mapping; - vector<RAS_TriangleIndex > m_triangle_indices; - - int m_class; - unsigned int GetLightLayer(); + bool IsDeformed() { return m_bDeformed; } + + /* materials */ int NumMaterials(); const STR_String& GetMaterialName(unsigned int matid); - RAS_MaterialBucket* GetMaterialBucket(unsigned int matid); const STR_String& GetTextureName(unsigned int matid); - virtual void AddPolygon(RAS_Polygon* poly); - void UpdateMaterialList(); - - int NumPolygons(); - RAS_Polygon* GetPolygon(int num); - - virtual void Bucketize( - double* oglmatrix, - void* clientobj, - bool useObjectColor, - const MT_Vector4& rgbavec - ); - void RemoveFromBuckets( - double* oglmatrix, - void* clientobj - ); + RAS_MeshMaterial* GetMeshMaterial(unsigned int matid); + RAS_MeshMaterial* GetMeshMaterial(RAS_IPolyMaterial *mat); - void MarkVisible( - double* oglmatrix, - void* clientobj, - bool visible, - bool useObjectColor, - const MT_Vector4& rgbavec - ); + list<RAS_MeshMaterial>::iterator GetFirstMaterial(); + list<RAS_MeshMaterial>::iterator GetLastMaterial(); - void DebugColor(unsigned int abgr); - void SetVertexColor(RAS_IPolyMaterial* mat,MT_Vector4 rgba); - - /** - * Sorts the polygons by their transformed z values. - */ - void SortPolygons(const MT_Transform &transform); + unsigned int GetLightLayer(); - void SchedulePolygons(int drawingmode); + /* name */ + void SetName(STR_String name); + const STR_String& GetName(); - void ClearArrayData(); - - RAS_MaterialBucket::Set::iterator GetFirstMaterial(); - RAS_MaterialBucket::Set::iterator GetLastMaterial(); - - virtual RAS_TexVert* GetVertex( - short array, - unsigned int index, - RAS_IPolyMaterial* polymat - ); - - virtual int FindVertexArray( - int numverts, - RAS_IPolyMaterial* polymat - ); + /* modification state */ + bool MeshModified(); + void SetMeshModified(bool v){m_bMeshModified = v;} + /* original blender mesh */ + Mesh* GetMesh() { return m_mesh; } + + /* mesh construction */ - // find (and share) or add vertices - // for some speedup, only the last 20 added vertices are searched for equality - - virtual int FindOrAddVertex( - int vtxarray, + virtual RAS_Polygon* AddPolygon(RAS_MaterialBucket *bucket, int numverts); + virtual void AddVertex(RAS_Polygon *poly, int i, const MT_Point3& xyz, const MT_Point2& uv, const MT_Point2& uv2, @@ -239,27 +117,43 @@ public: const unsigned int rgbacolor, const MT_Vector3& normal, bool flat, - RAS_IPolyMaterial* mat, - int origindex - ); - - vecVertexArray& GetVertexCache (RAS_IPolyMaterial* mat); + int origindex); + + void SchedulePolygons(int drawingmode); + + /* vertex and polygon acces */ + int NumVertices(RAS_IPolyMaterial* mat); + RAS_TexVert* GetVertex(unsigned int matid, unsigned int index); + + int NumPolygons(); + RAS_Polygon* GetPolygon(int num) const; - int GetVertexArrayLength(RAS_IPolyMaterial* mat); + /* buckets */ + virtual void AddMeshUser(void *clientobj); + virtual void UpdateBuckets( + void* clientobj, + double* oglmatrix, + bool useObjectColor, + const MT_Vector4& rgbavec, + bool visible, + bool culled); - RAS_TexVert* GetVertex( - unsigned int matid, - unsigned int index - ); + void RemoveFromBuckets(void *clientobj); - const vecIndexArrays& GetIndexCache (RAS_IPolyMaterial* mat); - void SetName(STR_String name); - const STR_String& GetName(); + /* colors */ + void DebugColor(unsigned int abgr); + void SetVertexColor(RAS_IPolyMaterial* mat,MT_Vector4 rgba); + + /* polygon sorting by Z for alpha */ + void SortPolygons(RAS_MeshSlot& ms, const MT_Transform &transform); - bool MeshModified(); - void SetMeshModified(bool v){m_MeshMod = v;} - Mesh* GetMesh() { return m_mesh; } + /* for construction to find shared vertices */ + struct SharedVertex { + RAS_DisplayArray *m_darray; + int m_offset; + }; + vector<vector<SharedVertex> > m_sharedvertex_map; }; #endif //__RAS_MESHOBJECT diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.h index 33c4b3faab0..81821639489 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.h @@ -28,7 +28,7 @@ #ifndef __RAS_BLUR2DFILTER #define __RAS_BLUR2DFILTER -char * BlurFragmentShader=STRINGIFY( +const char * BlurFragmentShader=STRINGIFY( uniform sampler2D bgl_RenderedTexture; uniform vec2 bgl_TextureCoordinateOffset[9]; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.h index c41e5ac06af..2ee75396f42 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.h @@ -28,7 +28,7 @@ #ifndef __RAS_DILATION2DFILTER #define __RAS_DILATION2DFILTER -char * DilationFragmentShader=STRINGIFY( +const char * DilationFragmentShader=STRINGIFY( uniform sampler2D bgl_RenderedTexture; uniform vec2 bgl_TextureCoordinateOffset[9]; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.h index 2bb357c958a..d3ce829bab0 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.h @@ -28,7 +28,7 @@ #ifndef __RAS_EROSION2DFILTER #define __RAS_EROSION2DFILTER -char * ErosionFragmentShader=STRINGIFY( +const char * ErosionFragmentShader=STRINGIFY( uniform sampler2D bgl_RenderedTexture; uniform vec2 bgl_TextureCoordinateOffset[9]; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_GrayScale2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_GrayScale2DFilter.h index 7324edd4e92..ae51308e9a4 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_GrayScale2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_GrayScale2DFilter.h @@ -28,7 +28,7 @@ #ifndef __RAS_GRAYSCALE2DFILTER #define __RAS_GRAYSCALE2DFILTER -char * GrayScaleFragmentShader=STRINGIFY( +const char * GrayScaleFragmentShader=STRINGIFY( uniform sampler2D bgl_RenderedTexture; void main(void) diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Invert2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Invert2DFilter.h index 5d90fe3475b..f723f619f68 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Invert2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Invert2DFilter.h @@ -28,7 +28,7 @@ #ifndef __RAS_INVERT2DFILTER #define __RAS_INVERT2DFILTER -char * InvertFragmentShader=STRINGIFY( +const char * InvertFragmentShader=STRINGIFY( uniform sampler2D bgl_RenderedTexture; void main(void) diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.h index cbe926976df..bfbb40b2fc9 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.h @@ -28,7 +28,7 @@ #ifndef __RAS_LAPLACION2DFILTER #define __RAS_LAPLACION2DFILTER -char * LaplacionFragmentShader=STRINGIFY( +const char * LaplacionFragmentShader=STRINGIFY( uniform sampler2D bgl_RenderedTexture; uniform vec2 bgl_TextureCoordinateOffset[9]; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.h index 7cd1082e5e3..0cbf8a7a802 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.h @@ -28,7 +28,7 @@ #ifndef __RAS_PREWITT2DFILTER #define __RAS_PREWITT2DFILTER -char * PrewittFragmentShader=STRINGIFY( +const char * PrewittFragmentShader=STRINGIFY( uniform sampler2D bgl_RenderedTexture; uniform vec2 bgl_TextureCoordinateOffset[9]; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sepia2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sepia2DFilter.h index d1c16f39823..ca431af4cd7 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sepia2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sepia2DFilter.h @@ -28,7 +28,7 @@ #ifndef __RAS_SEPIA2DFILTER #define __RAS_SEPIA2DFILTER -char * SepiaFragmentShader=STRINGIFY( +const char * SepiaFragmentShader=STRINGIFY( uniform sampler2D bgl_RenderedTexture; void main(void) diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.h index 14e0be6df9d..5a9661e2617 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.h @@ -28,7 +28,7 @@ #ifndef __RAS_SHARPEN2DFILTER #define __RAS_SHARPEN2DFILTER -char * SharpenFragmentShader=STRINGIFY( +const char * SharpenFragmentShader=STRINGIFY( uniform sampler2D bgl_RenderedTexture; uniform vec2 bgl_TextureCoordinateOffset[9]; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.h index 40c17c285ce..142e4f0e3d4 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.h @@ -28,7 +28,7 @@ #ifndef __RAS_SOBEL2DFILTER #define __RAS_SOBEL2DFILTER -char * SobelFragmentShader=STRINGIFY( +const char * SobelFragmentShader=STRINGIFY( uniform sampler2D bgl_RenderedTexture; uniform vec2 bgl_TextureCoordinateOffset[9]; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt index 2a6d64ecc73..e4403ace69f 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt @@ -32,6 +32,7 @@ SET(INC ../../../../intern/moto/include ../../../../source/gameengine/Rasterizer ../../../../extern/glew/include + ../../../../source/blender/gpu ) BLENDERLIB(bf_oglrasterizer "${SRC}" "${INC}") diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile index f01978b8eb1..aee485a22be 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile @@ -41,12 +41,11 @@ CPPFLAGS += -I$(OPENGL_HEADERS) CPPFLAGS += -I$(NAN_STRING)/include CPPFLAGS += -I$(NAN_MOTO)/include CPPFLAGS += -I../../../kernel/gen_system +CPPFLAGS += -I../../../blender/gpu CPPFLAGS += -I../../BlenderRoutines CPPFLAGS += -I.. + ifeq ($(OS),darwin) CPPFLAGS += -fpascal-strings endif -ifeq ($(WITH_BF_GLEXT),true) - CPPFLAGS += -DWITH_GLEXT -endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp index c2687319717..2c4b55ff964 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp @@ -9,6 +9,7 @@ #include "GL/glew.h" +#include "RAS_MaterialBucket.h" #include "RAS_TexVert.h" #include "MT_assert.h" @@ -125,20 +126,20 @@ void RAS_ListRasterizer::RemoveListSlot(RAS_ListSlot* list) } } -RAS_ListSlot* RAS_ListRasterizer::FindOrAdd(const vecVertexArray& vertexarrays, KX_ListSlot** slot) +RAS_ListSlot* RAS_ListRasterizer::FindOrAdd(RAS_MeshSlot& ms) { /* Keep a copy of constant lists submitted for rendering, this guards against (replicated)new...delete every frame, and we can reuse lists! - :: sorted by vertex array + :: sorted by mesh slot */ - RAS_ListSlot* localSlot = (RAS_ListSlot*)*slot; + RAS_ListSlot* localSlot = (RAS_ListSlot*)ms.m_DisplayList; if(!localSlot) { - RAS_Lists::iterator it = mLists.find(vertexarrays); + RAS_Lists::iterator it = mLists.find(&ms); if(it == mLists.end()) { localSlot = new RAS_ListSlot(this); - mLists.insert(std::pair<vecVertexArray, RAS_ListSlot*>(vertexarrays, localSlot)); + mLists.insert(std::pair<RAS_MeshSlot*, RAS_ListSlot*>(&ms, localSlot)); } else { localSlot = static_cast<RAS_ListSlot*>(it->second->AddRef()); } @@ -157,69 +158,45 @@ void RAS_ListRasterizer::ReleaseAlloc() mLists.clear(); } - -void RAS_ListRasterizer::IndexPrimitives( - const vecVertexArray & vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot) +void RAS_ListRasterizer::IndexPrimitives(RAS_MeshSlot& ms) { RAS_ListSlot* localSlot =0; - // useObjectColor(are we updating every frame?) - if(!useObjectColor && slot) { - localSlot = FindOrAdd(vertexarrays, slot); + if(ms.m_bDisplayList) { + localSlot = FindOrAdd(ms); localSlot->DrawList(); if(localSlot->End()) { // save slot here too, needed for replicas and object using same mesh // => they have the same vertexarray but different mesh slot - *slot = localSlot; + ms.m_DisplayList = localSlot; return; } } - if (mUseVertexArrays) { - RAS_VAOpenGLRasterizer::IndexPrimitives( - vertexarrays, indexarrays, - mode, useObjectColor, - rgbacolor,slot - ); - } else { - RAS_OpenGLRasterizer::IndexPrimitives( - vertexarrays, indexarrays, - mode, useObjectColor, - rgbacolor,slot - ); - } + if (mUseVertexArrays) + RAS_VAOpenGLRasterizer::IndexPrimitives(ms); + else + RAS_OpenGLRasterizer::IndexPrimitives(ms); - if(!useObjectColor && slot) { + if(ms.m_bDisplayList) { localSlot->EndList(); - *slot = localSlot; + ms.m_DisplayList = localSlot; } } -void RAS_ListRasterizer::IndexPrimitivesMulti( - const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot) +void RAS_ListRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms) { RAS_ListSlot* localSlot =0; - // useObjectColor(are we updating every frame?) - if(!useObjectColor && slot) { - localSlot = FindOrAdd(vertexarrays, slot); + if(ms.m_bDisplayList) { + localSlot = FindOrAdd(ms); localSlot->DrawList(); if(localSlot->End()) { // save slot here too, needed for replicas and object using same mesh // => they have the same vertexarray but different mesh slot - *slot = localSlot; + ms.m_DisplayList = localSlot; return; } } @@ -227,23 +204,14 @@ void RAS_ListRasterizer::IndexPrimitivesMulti( // workaround: note how we do not use vertex arrays for making display // lists, since glVertexAttribPointerARB doesn't seem to work correct // in display lists on ATI? either a bug in the driver or in Blender .. - if (mUseVertexArrays && !localSlot) { - RAS_VAOpenGLRasterizer::IndexPrimitivesMulti( - vertexarrays, indexarrays, - mode, useObjectColor, - rgbacolor,slot - ); - } else { - RAS_OpenGLRasterizer::IndexPrimitivesMulti( - vertexarrays, indexarrays, - mode, useObjectColor, - rgbacolor,slot - ); - } + if (mUseVertexArrays && !localSlot) + RAS_VAOpenGLRasterizer::IndexPrimitivesMulti(ms); + else + RAS_OpenGLRasterizer::IndexPrimitivesMulti(ms); - if(!useObjectColor && slot) { + if(ms.m_bDisplayList) { localSlot->EndList(); - *slot = localSlot; + ms.m_DisplayList = localSlot; } } diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h index b1b19144c12..96d6d2a995d 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h @@ -4,6 +4,7 @@ #include "RAS_MaterialBucket.h" #include "RAS_VAOpenGLRasterizer.h" #include <vector> +#include <map> class RAS_ListRasterizer; class RAS_ListSlot : public KX_ListSlot @@ -34,14 +35,14 @@ enum RAS_ListSlotFlags { LIST_REGEN =64 }; -typedef std::map<const vecVertexArray, RAS_ListSlot*> RAS_Lists; +typedef std::map<class RAS_MeshSlot*, RAS_ListSlot*> RAS_Lists; class RAS_ListRasterizer : public RAS_VAOpenGLRasterizer { bool mUseVertexArrays; RAS_Lists mLists; - RAS_ListSlot* FindOrAdd(const vecVertexArray& vertexarrays, KX_ListSlot** slot); + RAS_ListSlot* FindOrAdd(class RAS_MeshSlot& ms); void ReleaseAlloc(); public: @@ -49,23 +50,8 @@ public: RAS_ListRasterizer(RAS_ICanvas* canvas, bool useVertexArrays=false, bool lock=false); virtual ~RAS_ListRasterizer(); - virtual void IndexPrimitives( - const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot - ); - - virtual void IndexPrimitivesMulti( - const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot - ); + virtual void IndexPrimitives(class RAS_MeshSlot& ms); + virtual void IndexPrimitivesMulti(class RAS_MeshSlot& ms); virtual bool Init(); virtual void Exit(); diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp index 1dcc6e70934..87a0a1d8b9e 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp @@ -38,6 +38,9 @@ #include "MT_CmMatrix4x4.h" #include "RAS_IRenderTools.h" // rendering text +#include "GPU_draw.h" +#include "GPU_material.h" + /** * 32x32 bit masks for vinterlace stereo mode */ @@ -67,10 +70,12 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas) m_motionblurvalue(-1.0), m_texco_num(0), m_attrib_num(0), - m_last_blendmode(0), + m_last_blendmode(GPU_BLEND_SOLID), + m_last_frontface(true), m_materialCachingInfo(0) { - m_viewmatrix.Identity(); + m_viewmatrix.setIdentity(); + m_viewinvmatrix.setIdentity(); for (int i = 0; i < 32; i++) { @@ -87,81 +92,9 @@ RAS_OpenGLRasterizer::~RAS_OpenGLRasterizer() { } - - -static void Myinit_gl_stuff(void) -{ - float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 }; - float mat_shininess[] = { 35.0 }; -/* float one= 1.0; */ - int a, x, y; - GLubyte pat[32*32]; - const GLubyte *patc= pat; - - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular); - glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess); - - -#if defined(__FreeBSD) || defined(__linux__) - glDisable(GL_DITHER); /* op sgi/sun hardware && 12 bits */ -#endif - - /* no local viewer, looks ugly in ortho mode */ - /* glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, &one); */ - - glDepthFunc(GL_LEQUAL); - /* scaling matrices */ - glEnable(GL_NORMALIZE); - - glShadeModel(GL_FLAT); - - glDisable(GL_ALPHA_TEST); - glDisable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glDisable(GL_FOG); - glDisable(GL_LIGHTING); - glDisable(GL_LOGIC_OP); - glDisable(GL_STENCIL_TEST); - glDisable(GL_TEXTURE_1D); - glDisable(GL_TEXTURE_2D); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - - glPixelTransferi(GL_MAP_COLOR, GL_FALSE); - glPixelTransferi(GL_RED_SCALE, 1); - glPixelTransferi(GL_RED_BIAS, 0); - glPixelTransferi(GL_GREEN_SCALE, 1); - glPixelTransferi(GL_GREEN_BIAS, 0); - glPixelTransferi(GL_BLUE_SCALE, 1); - glPixelTransferi(GL_BLUE_BIAS, 0); - glPixelTransferi(GL_ALPHA_SCALE, 1); - glPixelTransferi(GL_ALPHA_BIAS, 0); - - a = 0; - for(x=0; x<32; x++) - { - for(y=0; y<4; y++) - { - if( (x) & 1) pat[a++]= 0x88; - else pat[a++]= 0x22; - } - } - - glPolygonStipple(patc); - - glFrontFace(GL_CCW); - glCullFace(GL_BACK); - glEnable(GL_CULL_FACE); -} - - - bool RAS_OpenGLRasterizer::Init() { - - Myinit_gl_stuff(); + GPU_state_init(); m_redback = 0.4375; m_greenback = 0.4375; @@ -172,7 +105,12 @@ bool RAS_OpenGLRasterizer::Init() m_ambg = 0.0f; m_ambb = 0.0f; - SetBlendingMode(0); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + m_last_blendmode = GPU_BLEND_SOLID; + + glFrontFace(GL_CCW); + m_last_frontface = true; glClearColor(m_redback,m_greenback,m_blueback,m_alphaback); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); @@ -316,21 +254,10 @@ void RAS_OpenGLRasterizer::Exit() EndFrame(); } -bool RAS_OpenGLRasterizer::InterlacedStereo() const -{ - return m_stereomode == RAS_STEREO_VINTERLACE || m_stereomode == RAS_STEREO_INTERLACED; -} - bool RAS_OpenGLRasterizer::BeginFrame(int drawingmode, double time) { m_time = time; m_drawingmode = drawingmode; - - if (!InterlacedStereo() || m_curreye == RAS_STEREO_LEFTEYE) - { - m_2DCanvas->ClearColor(m_redback,m_greenback,m_blueback,m_alphaback); - m_2DCanvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER); - } // Blender camera routine destroys the settings if (m_drawingmode < KX_SOLID) @@ -344,7 +271,12 @@ bool RAS_OpenGLRasterizer::BeginFrame(int drawingmode, double time) glEnable (GL_CULL_FACE); } - SetBlendingMode(0); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + m_last_blendmode = GPU_BLEND_SOLID; + + glFrontFace(GL_CCW); + m_last_frontface = true; glShadeModel(GL_SMOOTH); @@ -359,34 +291,28 @@ void RAS_OpenGLRasterizer::SetDrawingMode(int drawingmode) { m_drawingmode = drawingmode; - switch (m_drawingmode) - { - case KX_WIREFRAME: - { - glDisable (GL_CULL_FACE); - break; - } - default: - { - } - } + if(m_drawingmode == KX_WIREFRAME) + glDisable(GL_CULL_FACE); } - - int RAS_OpenGLRasterizer::GetDrawingMode() { return m_drawingmode; } - void RAS_OpenGLRasterizer::SetDepthMask(DepthMask depthmask) { glDepthMask(depthmask == KX_DEPTHMASK_DISABLED ? GL_FALSE : GL_TRUE); } +void RAS_OpenGLRasterizer::ClearColorBuffer() +{ + m_2DCanvas->ClearColor(m_redback,m_greenback,m_blueback,m_alphaback); + m_2DCanvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER); +} + void RAS_OpenGLRasterizer::ClearDepthBuffer() { @@ -497,6 +423,10 @@ bool RAS_OpenGLRasterizer::Stereo() return true; } +bool RAS_OpenGLRasterizer::InterlacedStereo() +{ + return m_stereomode == RAS_STEREO_VINTERLACE || m_stereomode == RAS_STEREO_INTERLACED; +} void RAS_OpenGLRasterizer::SetEye(const StereoEye eye) { @@ -573,294 +503,84 @@ void RAS_OpenGLRasterizer::SwapBuffers() -void RAS_OpenGLRasterizer::GetViewMatrix(MT_Matrix4x4 &mat) const +const MT_Matrix4x4& RAS_OpenGLRasterizer::GetViewMatrix() const { - float viewmat[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, viewmat); - mat.setValue(viewmat); + return m_viewmatrix; } - - -void RAS_OpenGLRasterizer::IndexPrimitives(const vecVertexArray & vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot - ) -{ - const RAS_TexVert* vertexarray; - unsigned int numindices, vt; - - for (vt=0;vt<vertexarrays.size();vt++) - { - vertexarray = &((*vertexarrays[vt]) [0]); - const KX_IndexArray & indexarray = (*indexarrays[vt]); - numindices = indexarray.size(); - - if (!numindices) - break; - - int vindex=0; - switch (mode) - { - case KX_MODE_LINES: - { - glBegin(GL_LINES); - vindex=0; - for (unsigned int i=0;i<numindices;i+=2) - { - glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ()); - glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ()); - } - glEnd(); - } - break; - case KX_MODE_QUADS: - { - glBegin(GL_QUADS); - vindex=0; - if (useObjectColor) - { - for (unsigned int i=0;i<numindices;i+=4) - { - - glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]); - - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - } - } - else - { - for (unsigned int i=0;i<numindices;i+=4) - { - // This looks curiously endian unsafe to me. - // However it depends on the way the colors are packed into - // the m_rgba field of RAS_TexVert - - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - } - } - glEnd(); - break; - } - case KX_MODE_TRIANGLES: - { - glBegin(GL_TRIANGLES); - vindex=0; - if (useObjectColor) - { - for (unsigned int i=0;i<numindices;i+=3) - { - - glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]); - - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - } - } - else - { - for (unsigned int i=0;i<numindices;i+=3) - { - - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - glTexCoord2fv(vertexarray[(indexarray[vindex])].getUV1()); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - } - } - glEnd(); - break; - } - default: - { - } - - } // switch - } // for each vertexarray - +const MT_Matrix4x4& RAS_OpenGLRasterizer::GetViewInvMatrix() const +{ + return m_viewinvmatrix; } -void RAS_OpenGLRasterizer::IndexPrimitives_3DText(const vecVertexArray & vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, +void RAS_OpenGLRasterizer::IndexPrimitives_3DText(RAS_MeshSlot& ms, class RAS_IPolyMaterial* polymat, - class RAS_IRenderTools* rendertools, - bool useObjectColor, - const MT_Vector4& rgbacolor - ) + class RAS_IRenderTools* rendertools) { - const RAS_TexVert* vertexarray; - unsigned int numindices, vt; - - if (useObjectColor) - { + bool obcolor = ms.m_bObjectColor; + MT_Vector4& rgba = ms.m_RGBAcolor; + RAS_MeshSlot::iterator it; + + // handle object color + if (obcolor) { glDisableClientState(GL_COLOR_ARRAY); - glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]); + glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); } else - { glEnableClientState(GL_COLOR_ARRAY); - } - - for (vt=0;vt<vertexarrays.size();vt++) - { - vertexarray = &((*vertexarrays[vt]) [0]); - const KX_IndexArray & indexarray = (*indexarrays[vt]); - numindices = indexarray.size(); - - if (!numindices) - break; + + for(ms.begin(it); !ms.end(it); ms.next(it)) { + RAS_TexVert *vertex; + size_t i, j, numvert; - int vindex=0; - switch (mode) - { - case KX_MODE_LINES: - { - glBegin(GL_LINES); - vindex=0; - for (unsigned int i=0;i<numindices;i+=2) - { - glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ()); - glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ()); - } - glEnd(); - } - break; - case KX_MODE_QUADS: + numvert = it.array->m_type; + + if(it.array->m_type == RAS_DisplayArray::LINE) { + // line drawing, no text + glBegin(GL_LINES); + + for(i=0; i<it.totindex; i+=2) { - vindex=0; - for (unsigned int i=0;i<numindices;i+=4) - { - float v1[3],v2[3],v3[3],v4[3]; - - v1[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0]; - v1[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1]; - v1[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2]; - vindex++; - - v2[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0]; - v2[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1]; - v2[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2]; - vindex++; - - v3[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0]; - v3[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1]; - v3[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2]; - vindex++; - - v4[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0]; - v4[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1]; - v4[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2]; - - vindex++; - - rendertools->RenderText(polymat->GetDrawingMode(),polymat,v1,v2,v3,v4); - ClearCachingInfo(); - } - break; + vertex = &it.vertex[it.index[i]]; + glVertex3fv(vertex->getXYZ()); + + vertex = &it.vertex[it.index[i+1]]; + glVertex3fv(vertex->getXYZ()); } - case KX_MODE_TRIANGLES: + + glEnd(); + } + else { + // triangle and quad text drawing + for(i=0; i<it.totindex; i+=numvert) { - glBegin(GL_TRIANGLES); - vindex=0; - for (unsigned int i=0;i<numindices;i+=3) - { - float v1[3],v2[3],v3[3]; - - v1[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0]; - v1[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1]; - v1[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2]; - vindex++; - - v2[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0]; - v2[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1]; - v2[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2]; - vindex++; - - v3[0] = vertexarray[(indexarray[vindex])].getLocalXYZ()[0]; - v3[1] = vertexarray[(indexarray[vindex])].getLocalXYZ()[1]; - v3[2] = vertexarray[(indexarray[vindex])].getLocalXYZ()[2]; - vindex++; - - rendertools->RenderText(polymat->GetDrawingMode(),polymat,v1,v2,v3,NULL); - ClearCachingInfo(); + float v[4][3]; + int glattrib, unit; + + for(j=0; j<numvert; j++) { + vertex = &it.vertex[it.index[i+j]]; + + v[j][0] = vertex->getXYZ()[0]; + v[j][1] = vertex->getXYZ()[1]; + v[j][2] = vertex->getXYZ()[2]; } - glEnd(); - break; - } - default: - { + + // find the right opengl attribute + glattrib = -1; + if(GLEW_ARB_vertex_program) + for(unit=0; unit<m_attrib_num; unit++) + if(m_attrib[unit] == RAS_TEXCO_UV1) + glattrib = unit; + + rendertools->RenderText(polymat->GetDrawingMode(), polymat, + v[0], v[1], v[2], (numvert == 4)? v[3]: NULL, glattrib); + + ClearCachingInfo(); } - } //switch - } //for each vertexarray + } + } + + glDisableClientState(GL_COLOR_ARRAY); } void RAS_OpenGLRasterizer::SetTexCoordNum(int num) @@ -897,14 +617,14 @@ void RAS_OpenGLRasterizer::TexCoord(const RAS_TexVert &tv) if(GLEW_ARB_multitexture) { for(unit=0; unit<m_texco_num; unit++) { - if(tv.getFlag() & TV_2NDUV && (int)tv.getUnit() == unit) { + if(tv.getFlag() & RAS_TexVert::SECOND_UV && (int)tv.getUnit() == unit) { glMultiTexCoord2fvARB(GL_TEXTURE0_ARB+unit, tv.getUV2()); continue; } switch(m_texco[unit]) { case RAS_TEXCO_ORCO: case RAS_TEXCO_GLOB: - glMultiTexCoord3fvARB(GL_TEXTURE0_ARB+unit, tv.getLocalXYZ()); + glMultiTexCoord3fvARB(GL_TEXTURE0_ARB+unit, tv.getXYZ()); break; case RAS_TEXCO_UV1: glMultiTexCoord2fvARB(GL_TEXTURE0_ARB+unit, tv.getUV1()); @@ -929,7 +649,7 @@ void RAS_OpenGLRasterizer::TexCoord(const RAS_TexVert &tv) switch(m_attrib[unit]) { case RAS_TEXCO_ORCO: case RAS_TEXCO_GLOB: - glVertexAttrib3fvARB(unit, tv.getLocalXYZ()); + glVertexAttrib3fvARB(unit, tv.getXYZ()); break; case RAS_TEXCO_UV1: glVertexAttrib2fvARB(unit, tv.getUV1()); @@ -953,211 +673,80 @@ void RAS_OpenGLRasterizer::TexCoord(const RAS_TexVert &tv) } } -void RAS_OpenGLRasterizer::Tangent( const RAS_TexVert& v1, - const RAS_TexVert& v2, - const RAS_TexVert& v3, - const MT_Vector3 &no) + +void RAS_OpenGLRasterizer::IndexPrimitives(RAS_MeshSlot& ms) { - // TODO: set for deformer... - MT_Vector3 x1(v1.getLocalXYZ()), x2(v2.getLocalXYZ()), x3(v3.getLocalXYZ()); - MT_Vector2 uv1(v1.getUV1()), uv2(v2.getUV1()), uv3(v3.getUV1()); - MT_Vector3 dx1(x2 - x1), dx2(x3 - x1); - MT_Vector2 duv1(uv2 - uv1), duv2(uv3 - uv1); - - MT_Scalar r = 1.0 / (duv1.x() * duv2.y() - duv2.x() * duv1.y()); - duv1 *= r; - duv2 *= r; - MT_Vector3 sdir(duv2.y() * dx1 - duv1.y() * dx2); - MT_Vector3 tdir(duv1.x() * dx2 - duv2.x() * dx1); - - // Gram-Schmidt orthogonalize - MT_Vector3 t(sdir - no.cross(no.cross(sdir))); - if (!MT_fuzzyZero(t)) t /= t.length(); - - float tangent[4]; - t.getValue(tangent); - // Calculate handedness - tangent[3] = no.dot(sdir.cross(tdir)) < 0.0 ? -1.0 : 1.0; + IndexPrimitivesInternal(ms, false); } +void RAS_OpenGLRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms) +{ + IndexPrimitivesInternal(ms, true); +} -void RAS_OpenGLRasterizer::IndexPrimitivesMulti( - const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot - ) +void RAS_OpenGLRasterizer::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi) { + bool obcolor = ms.m_bObjectColor; + bool wireframe = m_drawingmode <= KX_WIREFRAME; + MT_Vector4& rgba = ms.m_RGBAcolor; + RAS_MeshSlot::iterator it; + + // iterate over display arrays, each containing an index + vertex array + for(ms.begin(it); !ms.end(it); ms.next(it)) { + RAS_TexVert *vertex; + size_t i, j, numvert; + + numvert = it.array->m_type; - const RAS_TexVert* vertexarray; - unsigned int numindices,vt; - - for (vt=0;vt<vertexarrays.size();vt++) - { - vertexarray = &((*vertexarrays[vt]) [0]); - const KX_IndexArray & indexarray = (*indexarrays[vt]); - numindices = indexarray.size(); - - if (!numindices) - break; + if(it.array->m_type == RAS_DisplayArray::LINE) { + // line drawing + glBegin(GL_LINES); - int vindex=0; - switch (mode) - { - case KX_MODE_LINES: + for(i=0; i<it.totindex; i+=2) { - glBegin(GL_LINES); - vindex=0; - for (unsigned int i=0;i<numindices;i+=2) - { - glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ()); - glVertex3fv(vertexarray[(indexarray[vindex++])].getLocalXYZ()); - } - glEnd(); + vertex = &it.vertex[it.index[i]]; + glVertex3fv(vertex->getXYZ()); + + vertex = &it.vertex[it.index[i+1]]; + glVertex3fv(vertex->getXYZ()); } - break; - case KX_MODE_QUADS: - { + + glEnd(); + } + else { + // triangle and quad drawing + if(it.array->m_type == RAS_DisplayArray::TRIANGLE) + glBegin(GL_TRIANGLES); + else glBegin(GL_QUADS); - vindex=0; - if (useObjectColor) - { - for (unsigned int i=0;i<numindices;i+=4) - { - - glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]); - - // - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - // - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - // - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - // - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - } - } - else - { - for (unsigned int i=0;i<numindices;i+=4) - { - // This looks curiously endian unsafe to me. - // However it depends on the way the colors are packed into - // the m_rgba field of RAS_TexVert - - // - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - // - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - // - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - // - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - } - } - glEnd(); - break; - } - case KX_MODE_TRIANGLES: + + for(i=0; i<it.totindex; i+=numvert) { - glBegin(GL_TRIANGLES); - vindex=0; - if (useObjectColor) - { - for (unsigned int i=0;i<numindices;i+=3) - { - - glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]); - // - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - // - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - // - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - } - } - else - { - for (unsigned int i=0;i<numindices;i+=3) - { - // - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - // - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; - - // - glColor4ubv((const GLubyte *)(vertexarray[(indexarray[vindex])].getRGBA())); - glNormal3fv(vertexarray[(indexarray[vindex])].getNormal()); - TexCoord(vertexarray[(indexarray[vindex])]); - glVertex3fv(vertexarray[(indexarray[vindex])].getLocalXYZ()); - vindex++; + if(obcolor) + glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); + + for(j=0; j<numvert; j++) { + vertex = &it.vertex[it.index[i+j]]; + + if(!wireframe) { + if(!obcolor) + glColor4ubv((const GLubyte *)(vertex->getRGBA())); + + glNormal3fv(vertex->getNormal()); + + if(multi) + TexCoord(*vertex); + else + glTexCoord2fv(vertex->getUV1()); } + + glVertex3fv(vertex->getXYZ()); } - glEnd(); - break; } - default: - { - } - } // switch - } // for each vertexarray + + glEnd(); + } + } } void RAS_OpenGLRasterizer::SetProjectionMatrix(MT_CmMatrix4x4 &mat) @@ -1232,7 +821,7 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix( void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Vector3& campos, const MT_Point3 &, const MT_Quaternion &camOrientQuat) { - MT_Matrix4x4 viewMat = mat; + m_viewmatrix = mat; // correction for stereo if(m_stereomode != RAS_STEREO_NOSTEREO) @@ -1259,7 +848,7 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Vecto MT_Transform transform; transform.setIdentity(); transform.translate(-(eyeline * m_eyeseparation / 2.0)); - viewMat *= transform; + m_viewmatrix *= transform; } break; case RAS_STEREO_RIGHTEYE: @@ -1268,20 +857,21 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Vecto MT_Transform transform; transform.setIdentity(); transform.translate(eyeline * m_eyeseparation / 2.0); - viewMat *= transform; + m_viewmatrix *= transform; } break; } } - // convert row major matrix 'viewMat' to column major for OpenGL - MT_Scalar cammat[16]; - viewMat.getValue(cammat); - MT_CmMatrix4x4 viewCmmat = cammat; + m_viewinvmatrix = m_viewmatrix; + m_viewinvmatrix.invert(); + + // note: getValue gives back column major as needed by OpenGL + MT_Scalar glviewmat[16]; + m_viewmatrix.getValue(glviewmat); glMatrixMode(GL_MODELVIEW); - m_viewmatrix = viewCmmat; - glLoadMatrixd(&m_viewmatrix(0,0)); + glLoadMatrixd(glviewmat); m_campos = campos; } @@ -1292,20 +882,6 @@ const MT_Point3& RAS_OpenGLRasterizer::GetCameraPosition() } - -void RAS_OpenGLRasterizer::LoadViewMatrix() -{ - glLoadMatrixd(&m_viewmatrix(0,0)); -} - - - -void RAS_OpenGLRasterizer::EnableTextures(bool enable) -{ -} - - - void RAS_OpenGLRasterizer::SetCullFace(bool enable) { if (enable) @@ -1373,7 +949,10 @@ void RAS_OpenGLRasterizer::SetPolygonOffset(float mult, float add) void RAS_OpenGLRasterizer::EnableMotionBlur(float motionblurvalue) { - m_motionblur = 1; + /* don't just set m_motionblur to 1, but check if it is 0 so + * we don't reset a motion blur that is already enabled */ + if(m_motionblur == 0) + m_motionblur = 1; m_motionblurvalue = motionblurvalue; } @@ -1388,23 +967,23 @@ void RAS_OpenGLRasterizer::SetBlendingMode(int blendmode) if(blendmode == m_last_blendmode) return; - if(blendmode == 0) { + if(blendmode == GPU_BLEND_SOLID) { glDisable(GL_BLEND); glDisable(GL_ALPHA_TEST); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } - else if(blendmode == 1) { + else if(blendmode == GPU_BLEND_ADD) { glBlendFunc(GL_ONE, GL_ONE); glEnable(GL_BLEND); glDisable(GL_ALPHA_TEST); } - else if(blendmode == 2) { + else if(blendmode == GPU_BLEND_ALPHA) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.0f); } - else if(blendmode == 4) { + else if(blendmode == GPU_BLEND_CLIP) { glDisable(GL_BLEND); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5f); @@ -1413,3 +992,16 @@ void RAS_OpenGLRasterizer::SetBlendingMode(int blendmode) m_last_blendmode = blendmode; } +void RAS_OpenGLRasterizer::SetFrontFace(bool ccw) +{ + if(m_last_frontface == ccw) + return; + + if(ccw) + glFrontFace(GL_CCW); + else + glFrontFace(GL_CW); + + m_last_frontface = ccw; +} + diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h index 02056cce446..0717cce0ce8 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h @@ -41,7 +41,7 @@ using namespace std; #include "RAS_MaterialBucket.h" #include "RAS_ICanvas.h" -#define RAS_MAX_TEXCO 3 // match in BL_Material +#define RAS_MAX_TEXCO 8 // match in BL_Material #define RAS_MAX_ATTRIB 16 // match in BL_BlenderShader struct OglDebugLine @@ -77,7 +77,8 @@ class RAS_OpenGLRasterizer : public RAS_IRasterizer float m_ambb; double m_time; - MT_CmMatrix4x4 m_viewmatrix; + MT_Matrix4x4 m_viewmatrix; + MT_Matrix4x4 m_viewinvmatrix; MT_Point3 m_campos; StereoMode m_stereomode; @@ -87,7 +88,6 @@ class RAS_OpenGLRasterizer : public RAS_IRasterizer float m_focallength; bool m_setfocallength; int m_noOfScanlines; - bool InterlacedStereo() const; //motion blur int m_motionblur; @@ -100,6 +100,7 @@ protected: int m_texco_num; int m_attrib_num; int m_last_blendmode; + bool m_last_frontface; /** Stores the caching information for the last material activated. */ RAS_IPolyMaterial::TCachingInfo m_materialCachingInfo; @@ -129,6 +130,7 @@ public: virtual bool Init(); virtual void Exit(); virtual bool BeginFrame(int drawingmode, double time); + virtual void ClearColorBuffer(); virtual void ClearDepthBuffer(); virtual void ClearCachingInfo(void); virtual void EndFrame(); @@ -136,6 +138,7 @@ public: virtual void SetStereoMode(const StereoMode stereomode); virtual bool Stereo(); + virtual bool InterlacedStereo(); virtual void SetEye(const StereoEye eye); virtual StereoEye GetEye(); virtual void SetEyeSeparation(const float eyeseparation); @@ -144,33 +147,15 @@ public: virtual float GetFocalLength(); virtual void SwapBuffers(); - virtual void IndexPrimitives( - const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot - ); + virtual void IndexPrimitives(class RAS_MeshSlot& ms); + virtual void IndexPrimitivesMulti(class RAS_MeshSlot& ms); virtual void IndexPrimitives_3DText( - const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, + class RAS_MeshSlot& ms, class RAS_IPolyMaterial* polymat, - class RAS_IRenderTools* rendertools, - bool useObjectColor, - const MT_Vector4& rgbacolor - ); - - virtual void IndexPrimitivesMulti( - const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot); + class RAS_IRenderTools* rendertools); + void IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi); virtual void SetProjectionMatrix(MT_CmMatrix4x4 & mat); virtual void SetProjectionMatrix(const MT_Matrix4x4 & mat); @@ -182,7 +167,6 @@ public: ); virtual const MT_Point3& GetCameraPosition(); - virtual void LoadViewMatrix(); virtual void SetFog( float start, @@ -214,7 +198,6 @@ public: virtual void SetDrawingMode(int drawingmode); virtual int GetDrawingMode(); - virtual void EnableTextures(bool enable); virtual void SetCullFace(bool enable); virtual void SetLines(bool enable); @@ -270,13 +253,10 @@ public: virtual void SetTexCoord(TexCoGen coords, int unit); virtual void SetAttrib(TexCoGen coords, int unit); - void TexCoord(const RAS_TexVert &tv); - virtual void GetViewMatrix(MT_Matrix4x4 &mat) const; + void TexCoord(const RAS_TexVert &tv); - void Tangent(const RAS_TexVert& v1, - const RAS_TexVert& v2, - const RAS_TexVert& v3, - const MT_Vector3 &no); + const MT_Matrix4x4& GetViewMatrix() const; + const MT_Matrix4x4& GetViewInvMatrix() const; virtual void EnableMotionBlur(float motionblurvalue); virtual void DisableMotionBlur(); @@ -293,6 +273,7 @@ public: }; virtual void SetBlendingMode(int blendmode); + virtual void SetFrontFace(bool ccw); }; #endif //__RAS_OPENGLRASTERIZER diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp index c78a97ad7be..2cb3b52adfb 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.cpp @@ -33,6 +33,7 @@ #include <stdlib.h> #include "GL/glew.h" +#include "GPU_extensions.h" #include "STR_String.h" #include "RAS_TexVert.h" @@ -77,16 +78,16 @@ void RAS_VAOpenGLRasterizer::SetDrawingMode(int drawingmode) { case KX_BOUNDINGBOX: case KX_WIREFRAME: - glDisableClientState(GL_COLOR_ARRAY); - glDisable(GL_CULL_FACE); + //glDisableClientState(GL_COLOR_ARRAY); + //glDisable(GL_CULL_FACE); break; case KX_SOLID: - glDisableClientState(GL_COLOR_ARRAY); + //glDisableClientState(GL_COLOR_ARRAY); break; case KX_TEXTURED: case KX_SHADED: case KX_SHADOW: - glEnableClientState(GL_COLOR_ARRAY); + //glEnableClientState(GL_COLOR_ARRAY); default: break; } @@ -98,141 +99,121 @@ void RAS_VAOpenGLRasterizer::Exit() glEnableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); - EnableTextures(false); RAS_OpenGLRasterizer::Exit(); } -void RAS_VAOpenGLRasterizer::IndexPrimitives( const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot) +void RAS_VAOpenGLRasterizer::IndexPrimitives(RAS_MeshSlot& ms) { - static const GLsizei vtxstride = sizeof(RAS_TexVert); + static const GLsizei stride = sizeof(RAS_TexVert); + bool wireframe = m_drawingmode <= KX_WIREFRAME; + RAS_MeshSlot::iterator it; GLenum drawmode; - if(mode == KX_MODE_TRIANGLES) - drawmode = GL_TRIANGLES; - else if(mode == KX_MODE_QUADS) - drawmode = GL_QUADS; - else - drawmode = GL_LINES; - const RAS_TexVert* vertexarray; - unsigned int numindices, vt; - - if (drawmode != GL_LINES) - { - if (useObjectColor) - { - glDisableClientState(GL_COLOR_ARRAY); - glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]); - } else - { - glColor4d(0,0,0,1.0); - glEnableClientState(GL_COLOR_ARRAY); - } - } - else - { - glColor3d(0,0,0); - } - - EnableTextures(false); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if(!wireframe) + glEnableClientState(GL_TEXTURE_COORD_ARRAY); // use glDrawElements to draw each vertexarray - for (vt=0;vt<vertexarrays.size();vt++) - { - vertexarray = &((*vertexarrays[vt]) [0]); - const KX_IndexArray & indexarray = (*indexarrays[vt]); - numindices = indexarray.size(); - - if (!numindices) + for(ms.begin(it); !ms.end(it); ms.next(it)) { + if(it.totindex == 0) continue; - - glVertexPointer(3,GL_FLOAT,vtxstride,vertexarray->getLocalXYZ()); - glNormalPointer(GL_FLOAT,vtxstride,vertexarray->getNormal()); - glTexCoordPointer(2,GL_FLOAT,vtxstride,vertexarray->getUV1()); - if(glIsEnabled(GL_COLOR_ARRAY)) - glColorPointer(4,GL_UNSIGNED_BYTE,vtxstride,vertexarray->getRGBA()); - //if(m_Lock) - // local->Begin(vertexarrays[vt]->size()); + // drawing mode + if(it.array->m_type == RAS_DisplayArray::TRIANGLE) + drawmode = GL_TRIANGLES; + else if(it.array->m_type == RAS_DisplayArray::QUAD) + drawmode = GL_QUADS; + else + drawmode = GL_LINES; + + // colors + if (drawmode != GL_LINES && !wireframe) { + if (ms.m_bObjectColor) { + const MT_Vector4& rgba = ms.m_RGBAcolor; - // here the actual drawing takes places - glDrawElements(drawmode,numindices,GL_UNSIGNED_SHORT,&(indexarray[0])); + glDisableClientState(GL_COLOR_ARRAY); + glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); + } + else { + glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + glEnableClientState(GL_COLOR_ARRAY); + } + } + else + glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + + glVertexPointer(3, GL_FLOAT, stride, it.vertex->getXYZ()); + glNormalPointer(GL_FLOAT, stride, it.vertex->getNormal()); + if(!wireframe) { + glTexCoordPointer(2, GL_FLOAT, stride, it.vertex->getUV1()); + if(glIsEnabled(GL_COLOR_ARRAY)) + glColorPointer(4, GL_UNSIGNED_BYTE, stride, it.vertex->getRGBA()); + } - //if(m_Lock) - // local->End(); + // here the actual drawing takes places + glDrawElements(drawmode, it.totindex, GL_UNSIGNED_SHORT, it.index); } - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + if(!wireframe) { + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + } } -void RAS_VAOpenGLRasterizer::IndexPrimitivesMulti( const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot) +void RAS_VAOpenGLRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms) { - static const GLsizei vtxstride = sizeof(RAS_TexVert); - + static const GLsizei stride = sizeof(RAS_TexVert); + bool wireframe = m_drawingmode <= KX_WIREFRAME; + RAS_MeshSlot::iterator it; GLenum drawmode; - if(mode == KX_MODE_TRIANGLES) - drawmode = GL_TRIANGLES; - else if(mode == KX_MODE_QUADS) - drawmode = GL_QUADS; - else - drawmode = GL_LINES; - const RAS_TexVert* vertexarray; - unsigned int numindices, vt; - - if (drawmode != GL_LINES) - { - if (useObjectColor) - { - glDisableClientState(GL_COLOR_ARRAY); - glColor4d(rgbacolor[0], rgbacolor[1], rgbacolor[2], rgbacolor[3]); - } - else - { - glColor4d(0,0,0,1.0); - glEnableClientState(GL_COLOR_ARRAY); - } - } - else - { - glColor3d(0,0,0); - } + if(!wireframe) + EnableTextures(true); // use glDrawElements to draw each vertexarray - for (vt=0;vt<vertexarrays.size();vt++) - { - vertexarray = &((*vertexarrays[vt]) [0]); - const KX_IndexArray & indexarray = (*indexarrays[vt]); - numindices = indexarray.size(); - - if (!numindices) + for(ms.begin(it); !ms.end(it); ms.next(it)) { + if(it.totindex == 0) continue; - glVertexPointer(3,GL_FLOAT,vtxstride,vertexarray->getLocalXYZ()); - glNormalPointer(GL_FLOAT,vtxstride,vertexarray->getNormal()); - TexCoordPtr(vertexarray); - if(glIsEnabled(GL_COLOR_ARRAY)) - glColorPointer(4,GL_UNSIGNED_BYTE,vtxstride,vertexarray->getRGBA()); + // drawing mode + if(it.array->m_type == RAS_DisplayArray::TRIANGLE) + drawmode = GL_TRIANGLES; + else if(it.array->m_type == RAS_DisplayArray::QUAD) + drawmode = GL_QUADS; + else + drawmode = GL_LINES; + + // colors + if (drawmode != GL_LINES && !wireframe) { + if (ms.m_bObjectColor) { + const MT_Vector4& rgba = ms.m_RGBAcolor; - //if(m_Lock) - // local->Begin(vertexarrays[vt]->size()); + glDisableClientState(GL_COLOR_ARRAY); + glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); + } + else { + glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + glEnableClientState(GL_COLOR_ARRAY); + } + } + else + glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + + glVertexPointer(3, GL_FLOAT, stride, it.vertex->getXYZ()); + glNormalPointer(GL_FLOAT, stride, it.vertex->getNormal()); + if(!wireframe) { + TexCoordPtr(it.vertex); + if(glIsEnabled(GL_COLOR_ARRAY)) + glColorPointer(4, GL_UNSIGNED_BYTE, stride, it.vertex->getRGBA()); + } // here the actual drawing takes places - glDrawElements(drawmode,numindices,GL_UNSIGNED_SHORT,&(indexarray[0])); - - //if(m_Lock) - // local->End(); + glDrawElements(drawmode, it.totindex, GL_UNSIGNED_SHORT, it.index); + } + + if(!wireframe) { + glDisableClientState(GL_COLOR_ARRAY); + EnableTextures(false); } } @@ -248,7 +229,7 @@ void RAS_VAOpenGLRasterizer::TexCoordPtr(const RAS_TexVert *tv) for(unit=0; unit<m_texco_num; unit++) { glClientActiveTextureARB(GL_TEXTURE0_ARB+unit); - if(tv->getFlag() & TV_2NDUV && (int)tv->getUnit() == unit) { + if(tv->getFlag() & RAS_TexVert::SECOND_UV && (int)tv->getUnit() == unit) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(RAS_TexVert), tv->getUV2()); continue; @@ -257,7 +238,7 @@ void RAS_VAOpenGLRasterizer::TexCoordPtr(const RAS_TexVert *tv) { case RAS_TEXCO_ORCO: case RAS_TEXCO_GLOB: - glTexCoordPointer(3, GL_FLOAT, sizeof(RAS_TexVert),tv->getLocalXYZ()); + glTexCoordPointer(3, GL_FLOAT, sizeof(RAS_TexVert),tv->getXYZ()); break; case RAS_TEXCO_UV1: glTexCoordPointer(2, GL_FLOAT, sizeof(RAS_TexVert),tv->getUV1()); @@ -284,7 +265,7 @@ void RAS_VAOpenGLRasterizer::TexCoordPtr(const RAS_TexVert *tv) switch(m_attrib[unit]) { case RAS_TEXCO_ORCO: case RAS_TEXCO_GLOB: - glVertexAttribPointerARB(unit, 3, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getLocalXYZ()); + glVertexAttribPointerARB(unit, 3, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getXYZ()); break; case RAS_TEXCO_UV1: glVertexAttribPointerARB(unit, 2, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getUV1()); @@ -313,11 +294,6 @@ void RAS_VAOpenGLRasterizer::EnableTextures(bool enable) TexCoGen *texco, *attrib; int unit, texco_num, attrib_num; - /* disable previously enabled texture coordinates and attributes. ideally - * this shouldn't be necessary .. */ - if(enable) - EnableTextures(false); - /* we cache last texcoords and attribs to ensure we disable the ones that * were actually last set */ if(enable) { diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.h index e4cc4ace0e8..766bbfbed0e 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_VAOpenGLRasterizer.h @@ -50,22 +50,10 @@ public: virtual void SetDrawingMode(int drawingmode); - virtual void IndexPrimitives( const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot); - - virtual void IndexPrimitivesMulti( - const vecVertexArray& vertexarrays, - const vecIndexArrays & indexarrays, - DrawMode mode, - bool useObjectColor, - const MT_Vector4& rgbacolor, - class KX_ListSlot** slot); - + virtual void IndexPrimitives(class RAS_MeshSlot& ms); + virtual void IndexPrimitivesMulti(class RAS_MeshSlot& ms); +private: virtual void EnableTextures(bool enable); //virtual bool QueryArrays(){return true;} //virtual bool QueryLists(){return m_Lock;} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript index 0cf9c326370..8d46528f7f0 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript @@ -1,12 +1,9 @@ #!/usr/bin/python Import ('env') -if env['WITH_BF_GLEXT'] == 1: - env['CPPFLAGS'].append('-DWITH_GLEXT') - sources = env.Glob('*.cpp') incs = '. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/Rasterizer #source/gameengine/BlenderRoutines ' -incs += ' #extern/glew/include ' + env['BF_OPENGL_INC'] +incs += ' #source/blender/gpu #extern/glew/include ' + env['BF_OPENGL_INC'] env.BlenderLib ( 'bf_oglrasterizer', Split(sources), Split(incs), [], libtype=['game','player'], priority=[40, 120] ) diff --git a/source/gameengine/Rasterizer/RAS_Polygon.cpp b/source/gameengine/Rasterizer/RAS_Polygon.cpp index b74cb9cfcac..50331d7a664 100644 --- a/source/gameengine/Rasterizer/RAS_Polygon.cpp +++ b/source/gameengine/Rasterizer/RAS_Polygon.cpp @@ -26,99 +26,82 @@ * ***** END GPL LICENSE BLOCK ***** */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #ifdef WIN32 - #pragma warning (disable:4786) #endif #include "RAS_Polygon.h" -RAS_Polygon::RAS_Polygon(RAS_MaterialBucket* bucket, - bool visible, - int numverts, - int vtxarrayindex) - :m_bucket(bucket), - m_vertexindexbase(numverts), - m_numverts(numverts), - m_edgecode(65535) +RAS_Polygon::RAS_Polygon(RAS_MaterialBucket* bucket, RAS_DisplayArray *darray, int numvert) { - m_vertexindexbase.m_vtxarray = vtxarrayindex ;//m_bucket->FindVertexArray(numverts); - m_polyFlags.Visible = visible; -} - + m_bucket = bucket; + m_darray = darray; + m_offset[0]= m_offset[1]= m_offset[2]= m_offset[3]= 0; + m_numvert = numvert; + m_edgecode = 255; + m_polyflags = 0; +} int RAS_Polygon::VertexCount() { - return m_numverts; + return m_numvert; } - - -void RAS_Polygon::SetVertex(int i, - unsigned int vertexindex ) //const MT_Point3& xyz,const MT_Point2& uv,const unsigned int rgbacolor,const MT_Vector3& normal) +void RAS_Polygon::SetVertexOffset(int i, unsigned short offset) { - m_vertexindexbase.SetIndex(i,vertexindex); //m_bucket->FindOrAddVertex(m_vertexindexbase.m_vtxarray, - //xyz,uv,rgbacolor,normal)); + m_offset[i] = offset; } - - -const KX_VertexIndex& RAS_Polygon::GetIndexBase() +RAS_TexVert *RAS_Polygon::GetVertex(int i) { - return m_vertexindexbase; + return &m_darray->m_vertex[m_offset[i]]; } - - -void RAS_Polygon::SetVisibleWireframeEdges(int edgecode) +int RAS_Polygon::GetVertexOffset(int i) { - m_edgecode = edgecode; + return m_offset[i]; } - - -// each bit is for a visible edge, starting with bit 1 for the first edge, bit 2 for second etc. int RAS_Polygon::GetEdgeCode() { return m_edgecode; } +void RAS_Polygon::SetEdgeCode(int edgecode) +{ + m_edgecode = edgecode; +} bool RAS_Polygon::IsVisible() { - return m_polyFlags.Visible; + return (m_polyflags & VISIBLE) != 0; } - +void RAS_Polygon::SetVisible(bool visible) +{ + if(visible) m_polyflags |= VISIBLE; + else m_polyflags &= ~VISIBLE; +} bool RAS_Polygon::IsCollider() { - return m_polyFlags.Collider; + return (m_polyflags & COLLIDER) != 0; } - - -void RAS_Polygon::SetCollider(bool col) +void RAS_Polygon::SetCollider(bool visible) { - m_polyFlags.Collider = col; + if(visible) m_polyflags |= COLLIDER; + else m_polyflags &= ~COLLIDER; } - - -KX_VertexIndex& RAS_Polygon::GetVertexIndexBase() +RAS_MaterialBucket* RAS_Polygon::GetMaterial() { - return m_vertexindexbase; + return m_bucket; } - - -RAS_MaterialBucket* RAS_Polygon::GetMaterial() +RAS_DisplayArray* RAS_Polygon::GetDisplayArray() { - return m_bucket; + return m_darray; } diff --git a/source/gameengine/Rasterizer/RAS_Polygon.h b/source/gameengine/Rasterizer/RAS_Polygon.h index 7ce7926a816..18526ba45f7 100644 --- a/source/gameengine/Rasterizer/RAS_Polygon.h +++ b/source/gameengine/Rasterizer/RAS_Polygon.h @@ -35,55 +35,47 @@ #include <vector> using namespace std; - -// -// Bitfield that stores the flags for each CValue derived class -// -struct PolygonFlags { - PolygonFlags() : - Visible(true), - Collider(true) - { - } - unsigned char Visible : 1; - unsigned char Collider : 1; - //int Visible : 1; - //int Collider : 1; -}; +/* polygon flags */ class RAS_Polygon { + /* location */ RAS_MaterialBucket* m_bucket; - KX_VertexIndex m_vertexindexbase; - int m_numverts; - int m_edgecode; - PolygonFlags m_polyFlags; - + RAS_DisplayArray* m_darray; + unsigned short m_offset[4]; + unsigned short m_numvert; + + /* flags */ + unsigned char m_edgecode; + unsigned char m_polyflags; public: - RAS_Polygon(RAS_MaterialBucket* bucket, - bool visible, - int numverts, - int vtxarrayindex) ; + enum { + VISIBLE = 1, + COLLIDER = 2 + }; + + RAS_Polygon(RAS_MaterialBucket* bucket, RAS_DisplayArray* darray, int numvert); virtual ~RAS_Polygon() {}; -// RAS_TexVert* GetVertex(int index); int VertexCount(); - void SetVertex(int i, unsigned int vertexindex); //const MT_Point3& xyz,const MT_Point2& uv,const unsigned int rgbacolor,const MT_Vector3& normal) - - const KX_VertexIndex& GetIndexBase(); + RAS_TexVert* GetVertex(int i); - void SetVisibleWireframeEdges(int edgecode); + void SetVertexOffset(int i, unsigned short offset); + int GetVertexOffset(int i); + // each bit is for a visible edge, starting with bit 1 for the first edge, bit 2 for second etc. int GetEdgeCode(); + void SetEdgeCode(int edgecode); bool IsVisible(); + void SetVisible(bool visible); + bool IsCollider(); - void SetCollider(bool col); + void SetCollider(bool collider); - KX_VertexIndex& GetVertexIndexBase(); RAS_MaterialBucket* GetMaterial(); - + RAS_DisplayArray* GetDisplayArray(); }; #endif diff --git a/source/gameengine/Rasterizer/RAS_TexVert.cpp b/source/gameengine/Rasterizer/RAS_TexVert.cpp index 935633dc636..b92965ed1cc 100644 --- a/source/gameengine/Rasterizer/RAS_TexVert.cpp +++ b/source/gameengine/Rasterizer/RAS_TexVert.cpp @@ -27,12 +27,7 @@ */ #include "RAS_TexVert.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#define SHORT(x) short(x*32767.0) +#include "MT_Matrix4x4.h" RAS_TexVert::RAS_TexVert(const MT_Point3& xyz, const MT_Point2& uv, @@ -40,7 +35,7 @@ RAS_TexVert::RAS_TexVert(const MT_Point3& xyz, const MT_Vector4& tangent, const unsigned int rgba, const MT_Vector3& normal, - const short flag, + const bool flat, const unsigned int origindex) { xyz.getValue(m_localxyz); @@ -49,9 +44,10 @@ RAS_TexVert::RAS_TexVert(const MT_Point3& xyz, SetRGBA(rgba); SetNormal(normal); tangent.getValue(m_tangent); - m_flag = flag; + m_flag = (flat)? FLAT: 0; m_origindex = origindex; m_unit = 2; + m_softBodyIndex = -1; } const MT_Point3& RAS_TexVert::xyz() @@ -101,7 +97,7 @@ void RAS_TexVert::SetFlag(const short flag) void RAS_TexVert::SetUnit(const unsigned int u) { - m_unit = u<=TV_MAX?u:TV_MAX; + m_unit = u<=MAX_UNIT?u:MAX_UNIT; } void RAS_TexVert::SetNormal(const MT_Vector3& normal) @@ -109,12 +105,18 @@ void RAS_TexVert::SetNormal(const MT_Vector3& normal) normal.getValue(m_normal); } +void RAS_TexVert::SetTangent(const MT_Vector3& tangent) +{ + tangent.getValue(m_tangent); +} + // compare two vertices, and return TRUE if both are almost identical (they can be shared) bool RAS_TexVert::closeTo(const RAS_TexVert* other) { return (m_flag == other->m_flag && m_rgba == other->m_rgba && MT_fuzzyEqual(MT_Vector3(m_normal), MT_Vector3(other->m_normal)) && + MT_fuzzyEqual(MT_Vector3(m_tangent), MT_Vector3(other->m_tangent)) && MT_fuzzyEqual(MT_Vector2(m_uv1), MT_Vector2(other->m_uv1)) && MT_fuzzyEqual(MT_Vector2(m_uv2), MT_Vector2(other->m_uv2)) && // p -- MT_fuzzyEqual(MT_Vector3(m_localxyz), MT_Vector3(other->m_localxyz))) ; @@ -131,11 +133,10 @@ unsigned int RAS_TexVert::getUnit() const return m_unit; } - -void RAS_TexVert::getOffsets(void* &xyz, void* &uv1, void* &rgba, void* &normal) const +void RAS_TexVert::Transform(const MT_Matrix4x4& mat, const MT_Matrix4x4& nmat) { - xyz = (void *) m_localxyz; - uv1 = (void *) m_uv1; - rgba = (void *) &m_rgba; - normal = (void *) m_normal; + SetXYZ((mat*MT_Vector4(m_localxyz[0], m_localxyz[1], m_localxyz[2], 1.0)).getValue()); + SetNormal((nmat*MT_Vector4(m_normal[0], m_normal[1], m_normal[2], 1.0)).getValue()); + SetTangent((nmat*MT_Vector4(m_tangent[0], m_tangent[1], m_tangent[2], 1.0)).getValue()); } + diff --git a/source/gameengine/Rasterizer/RAS_TexVert.h b/source/gameengine/Rasterizer/RAS_TexVert.h index bf092b4b230..54da109cbf1 100644 --- a/source/gameengine/Rasterizer/RAS_TexVert.h +++ b/source/gameengine/Rasterizer/RAS_TexVert.h @@ -37,11 +37,6 @@ static MT_Point3 g_pt3; static MT_Point2 g_pt2; -#define TV_CALCFACENORMAL 0x0001 -#define TV_2NDUV 0x0002 - -#define TV_MAX 3//match Def in BL_Material.h - class RAS_TexVert { @@ -49,16 +44,23 @@ class RAS_TexVert float m_uv1[2]; // 2*4 = 8 float m_uv2[2]; // 2*4 = 8 unsigned int m_rgba; // 4 - float m_tangent[4]; // 4*2 = 8 - float m_normal[3]; // 3*2 = 6 + float m_tangent[4]; // 4*4 = 16 + float m_normal[3]; // 3*4 = 12 short m_flag; // 2 + short m_softBodyIndex; //2 unsigned int m_unit; // 4 - unsigned int m_origindex; // 4 + unsigned int m_origindex; // 4 //--------- - // 56 + // 56+6+8+2=72 // 32 bytes total size, fits nice = 56 = not fit nice. - // We'll go for 64 bytes total size - 24 bytes left. + public: + enum { + FLAT = 1, + SECOND_UV = 2, + MAX_UNIT = 8 + }; + short getFlag() const; unsigned int getUnit() const; @@ -70,7 +72,7 @@ public: const MT_Vector4& tangent, const unsigned int rgba, const MT_Vector3& normal, - const short flag, + const bool flat, const unsigned int origindex); ~RAS_TexVert() {}; @@ -82,7 +84,7 @@ public: return m_uv2; }; - const float* getLocalXYZ() const { + const float* getXYZ() const { return m_localxyz; }; @@ -90,6 +92,16 @@ public: return m_normal; } + short int getSoftBodyIndex() const + { + return m_softBodyIndex; + } + + void setSoftBodyIndex(short int sbIndex) + { + m_softBodyIndex = sbIndex; + } + const float* getTangent() const { return m_tangent; } @@ -108,20 +120,19 @@ public: void SetRGBA(const unsigned int rgba); void SetNormal(const MT_Vector3& normal); + void SetTangent(const MT_Vector3& tangent); void SetFlag(const short flag); void SetUnit(const unsigned u); void SetRGBA(const MT_Vector4& rgba); const MT_Point3& xyz(); - // compare two vertices, and return TRUE if both are almost identical (they can be shared) - bool closeTo(const RAS_TexVert* other); + void Transform(const class MT_Matrix4x4& mat, + const class MT_Matrix4x4& nmat); - bool closeTo(const MT_Point3& otherxyz, - const MT_Point2& otheruv, - const unsigned int otherrgba, - short othernormal[3]) const; - void getOffsets(void*&xyz, void *&uv1, void *&rgba, void *&normal) const; + // compare two vertices, to test if they can be shared, used for + // splitting up based on uv's, colors, etc + bool closeTo(const RAS_TexVert* other); }; #endif //__RAS_TEXVERT diff --git a/source/gameengine/Rasterizer/SConscript b/source/gameengine/Rasterizer/SConscript index e6bc657ed6d..a024f7e0ee6 100644 --- a/source/gameengine/Rasterizer/SConscript +++ b/source/gameengine/Rasterizer/SConscript @@ -3,11 +3,8 @@ Import ('env') sources = env.Glob('*.cpp') -if env['WITH_BF_GLEXT'] == 1: - env['CPPFLAGS'].append('-DWITH_GLEXT') - -incs = '. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/BlenderRoutines #extern/glew/include #source/gameengine/Expressions' +incs = '. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/BlenderRoutines #extern/glew/include #source/gameengine/Expressions #source/blender/blenkernel #source/blender/makesdna' incs += ' ' + env['BF_PYTHON_INC'] if env['OURPLATFORM']=='win32-vc': |