diff options
Diffstat (limited to 'source/gameengine/Ketsji')
100 files changed, 8746 insertions, 3074 deletions
diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp new file mode 100644 index 00000000000..8ec463be6ff --- /dev/null +++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp @@ -0,0 +1,170 @@ + +#include "DNA_customdata_types.h" +#include "DNA_material_types.h" +#include "DNA_scene_types.h" + +#include "BKE_global.h" +#include "BKE_main.h" + +#include "BL_BlenderShader.h" +#include "BL_Material.h" + +#include "GPU_extensions.h" +#include "GPU_material.h" + +#include "RAS_BucketManager.h" +#include "RAS_MeshObject.h" +#include "RAS_IRasterizer.h" + +BL_BlenderShader::BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer) +: + mScene(scene), + mMat(ma), + mLightLayer(lightlayer) +{ + mBlenderScene = scene->GetBlenderScene(); + mBlendMode = GPU_BLEND_SOLID; + + if(mMat) + GPU_material_from_blender(mBlenderScene, mMat); +} + +BL_BlenderShader::~BL_BlenderShader() +{ + if(mMat && GPU_material_from_blender(mBlenderScene, mMat)) + GPU_material_unbind(GPU_material_from_blender(mBlenderScene, mMat)); +} + +bool BL_BlenderShader::Ok() +{ + return VerifyShader(); +} + +bool BL_BlenderShader::VerifyShader() +{ + if(mMat) + return (GPU_material_from_blender(mBlenderScene, mMat) != 0); + else + return false; +} + +void BL_BlenderShader::SetProg(bool enable, double time) +{ + if(VerifyShader()) { + if(enable) + GPU_material_bind(GPU_material_from_blender(mBlenderScene, mMat), mLightLayer, ~0, time); + else + GPU_material_unbind(GPU_material_from_blender(mBlenderScene, mMat)); + } +} + +int BL_BlenderShader::GetAttribNum() +{ + GPUVertexAttribs attribs; + int i, enabled = 0; + + if(!VerifyShader()) + return enabled; + + 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) + enabled= attribs.layer[i].glindex+1; + + if(enabled > BL_MAX_ATTRIB) + enabled = BL_MAX_ATTRIB; + + return enabled; +} + +void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat) +{ + 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(gpumat, &attribs); + attrib_num = GetAttribNum(); + + ras->SetTexCoordNum(0); + ras->SetAttribNum(attrib_num); + for(i=0; i<attrib_num; i++) + ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, i); + + for(i = 0; i < attribs.totlayer; i++) { + if(attribs.layer[i].glindex > attrib_num) + continue; + + if(attribs.layer[i].type == CD_MTFACE) { + if(!mat->uvName.IsEmpty() && strcmp(mat->uvName.ReadPtr(), attribs.layer[i].name) == 0) + ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_UV1, attribs.layer[i].glindex); + else if(!mat->uv2Name.IsEmpty() && strcmp(mat->uv2Name.ReadPtr(), attribs.layer[i].name) == 0) + ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_UV2, attribs.layer[i].glindex); + else + ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_UV1, attribs.layer[i].glindex); + } + else if(attribs.layer[i].type == CD_TANGENT) + ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT, attribs.layer[i].glindex); + else if(attribs.layer[i].type == CD_ORCO) + ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_ORCO, attribs.layer[i].glindex); + else if(attribs.layer[i].type == CD_NORMAL) + ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_NORM, attribs.layer[i].glindex); + else if(attribs.layer[i].type == CD_MCOL) + ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_VCOL, attribs.layer[i].glindex); + else + ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, attribs.layer[i].glindex); + } + } +} + +void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) +{ + float obmat[4][4], viewmat[4][4], viewinvmat[4][4], obcol[4]; + GPUMaterial *gpumat; + + gpumat = GPU_material_from_blender(mBlenderScene, mMat); + + if(!gpumat || !GPU_material_bound(gpumat)) + return; + + MT_Matrix4x4 model; + model.setValue(ms.m_OpenGLMatrix); + 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); + 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(gpumat, obmat, viewmat, viewinvmat, obcol); + + mBlendMode = GPU_material_blend_mode(gpumat, obcol); +} + +int BL_BlenderShader::GetBlendMode() +{ + return mBlendMode; +} + +bool BL_BlenderShader::Equals(BL_BlenderShader *blshader) +{ + /* to avoid unneeded state switches */ + 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 new file mode 100644 index 00000000000..5c1f59f94ad --- /dev/null +++ b/source/gameengine/Ketsji/BL_BlenderShader.h @@ -0,0 +1,53 @@ + +#ifndef __BL_GPUSHADER_H__ +#define __BL_GPUSHADER_H__ + +#include "GPU_material.h" + +#include "MT_Matrix4x4.h" +#include "MT_Matrix3x3.h" +#include "MT_Tuple2.h" +#include "MT_Tuple3.h" +#include "MT_Tuple4.h" + +#include "RAS_IPolygonMaterial.h" + +#include "KX_Scene.h" + +struct Material; +struct Scene; +class BL_Material; + +#define BL_MAX_ATTRIB 16 + +/** + * BL_BlenderShader + * Blender GPU shader material + */ +class BL_BlenderShader +{ +private: + KX_Scene *mScene; + struct Scene *mBlenderScene; + struct Material *mMat; + int mLightLayer; + int mBlendMode; + + bool VerifyShader(); + +public: + BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer); + virtual ~BL_BlenderShader(); + + bool Ok(); + void SetProg(bool enable, double time=0.0); + + int GetAttribNum(); + void SetAttribs(class RAS_IRasterizer* ras, const BL_Material *mat); + void Update(const class RAS_MeshSlot & ms, class RAS_IRasterizer* rasty); + int GetBlendMode(); + + bool Equals(BL_BlenderShader *blshader); +}; + +#endif//__BL_GPUSHADER_H__ diff --git a/source/gameengine/Ketsji/BL_Material.cpp b/source/gameengine/Ketsji/BL_Material.cpp index 7ed2da590a9..7e3d6984f19 100644 --- a/source/gameengine/Ketsji/BL_Material.cpp +++ b/source/gameengine/Ketsji/BL_Material.cpp @@ -34,6 +34,7 @@ BL_Material::BL_Material() rgb[3] = 0; IdMode = 0; ras_mode = 0; + glslmat = 0; tile = 0; matname = "NoMaterial"; matcolor[0] = 0.5f; @@ -104,7 +105,8 @@ void BL_Material::GetConversionRGB(unsigned int *nrgb) { *nrgb = rgb[3]; } -void BL_Material::SetConversionUV(MT_Point2 *nuv) { +void BL_Material::SetConversionUV(const STR_String& name, MT_Point2 *nuv) { + uvName = name; uv[0] = *nuv++; uv[1] = *nuv++; uv[2] = *nuv++; @@ -117,7 +119,8 @@ void BL_Material::GetConversionUV(MT_Point2 *nuv){ *nuv++ = uv[2]; *nuv = uv[3]; } -void BL_Material::SetConversionUV2(MT_Point2 *nuv) { +void BL_Material::SetConversionUV2(const STR_String& name, MT_Point2 *nuv) { + uv2Name = name; uv2[0] = *nuv++; uv2[1] = *nuv++; uv2[2] = *nuv++; diff --git a/source/gameengine/Ketsji/BL_Material.h b/source/gameengine/Ketsji/BL_Material.h index 8be91316237..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 @@ -47,6 +47,7 @@ public: int IdMode; unsigned int ras_mode; + bool glslmat; STR_String texname[MAXTEX]; unsigned int flag[MAXTEX]; @@ -82,13 +83,16 @@ public: MT_Point2 uv[4]; MT_Point2 uv2[4]; + STR_String uvName; + STR_String uv2Name; + void SetConversionRGB(unsigned int *rgb); void GetConversionRGB(unsigned int *rgb); - void SetConversionUV(MT_Point2 *uv); + void SetConversionUV(const STR_String& name, MT_Point2 *uv); void GetConversionUV(MT_Point2 *uv); - void SetConversionUV2(MT_Point2 *uv); + void SetConversionUV2(const STR_String& name, MT_Point2 *uv); void GetConversionUV2(MT_Point2 *uv); void SetSharedMaterial(bool v); @@ -125,8 +129,7 @@ enum BL_flag TEXALPHA=8, // use alpha combiner functions TEXNEG=16, // negate blending HASIPO=32, - USENEGALPHA=64, - ALPHA_TEST=128 + USENEGALPHA=64 }; // BL_Material::ras_mode @@ -135,8 +138,8 @@ enum BL_ras_mode POLY_VIS=1, COLLIDER=2, ZSORT=4, - TRANSP=8, - TRIANGLE=16, + ALPHA=8, + // TRIANGLE=16, USE_LIGHT=32, WIRE=64 }; diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp index 3b74b74727a..80892764089 100644 --- a/source/gameengine/Ketsji/BL_Shader.cpp +++ b/source/gameengine/Ketsji/BL_Shader.cpp @@ -1,20 +1,5 @@ - -#ifdef WIN32 -#include <windows.h> -#endif // WIN32 -#ifdef __APPLE__ -#define GL_GLEXT_LEGACY 1 -#include <OpenGL/gl.h> -#include <OpenGL/glu.h> -#else -#include <GL/gl.h> -#if defined(__sun__) && !defined(__sparc__) -#include <mesa/glu.h> -#else -#include <GL/glu.h> -#endif -#endif +#include "GL/glew.h" #include <iostream> #include "BL_Shader.h" @@ -30,7 +15,6 @@ #include "RAS_MeshObject.h" #include "RAS_IRasterizer.h" -//using namespace bgl; #define spit(x) std::cout << x << std::endl; #define SORT_UNIFORMS 1 @@ -45,7 +29,7 @@ BL_Uniform::BL_Uniform(int data_size) mDataLen(data_size) { #ifdef SORT_UNIFORMS - MT_assert(mDataLen <= UNIFORM_MAX_LEN); + MT_assert((int)mDataLen <= UNIFORM_MAX_LEN); mData = (void*)MEM_mallocN(mDataLen, "shader-uniform-alloc"); #endif } @@ -62,7 +46,6 @@ BL_Uniform::~BL_Uniform() void BL_Uniform::Apply(class BL_Shader *shader) { -#ifdef GL_ARB_shader_objects #ifdef SORT_UNIFORMS MT_assert(mType > UNI_NONE && mType < UNI_MAX && mData); @@ -73,48 +56,47 @@ void BL_Uniform::Apply(class BL_Shader *shader) { case UNI_FLOAT: { float *f = (float*)mData; - bgl::blUniform1fARB(mLoc,(GLfloat)*f); + glUniform1fARB(mLoc,(GLfloat)*f); }break; case UNI_INT: { int *f = (int*)mData; - bgl::blUniform1iARB(mLoc, (GLint)*f); + glUniform1iARB(mLoc, (GLint)*f); }break; case UNI_FLOAT2: { float *f = (float*)mData; - bgl::blUniform2fvARB(mLoc,1, (GLfloat*)f); + glUniform2fvARB(mLoc,1, (GLfloat*)f); }break; case UNI_FLOAT3: { float *f = (float*)mData; - bgl::blUniform3fvARB(mLoc,1,(GLfloat*)f); + glUniform3fvARB(mLoc,1,(GLfloat*)f); }break; case UNI_FLOAT4: { float *f = (float*)mData; - bgl::blUniform4fvARB(mLoc,1,(GLfloat*)f); + glUniform4fvARB(mLoc,1,(GLfloat*)f); }break; case UNI_INT2: { int *f = (int*)mData; - bgl::blUniform2ivARB(mLoc,1,(GLint*)f); + glUniform2ivARB(mLoc,1,(GLint*)f); }break; case UNI_INT3: { int *f = (int*)mData; - bgl::blUniform3ivARB(mLoc,1,(GLint*)f); + glUniform3ivARB(mLoc,1,(GLint*)f); }break; case UNI_INT4: { int *f = (int*)mData; - bgl::blUniform4ivARB(mLoc,1,(GLint*)f); + glUniform4ivARB(mLoc,1,(GLint*)f); }break; case UNI_MAT4: { float *f = (float*)mData; - bgl::blUniformMatrix4fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f); + glUniformMatrix4fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f); }break; case UNI_MAT3: { float *f = (float*)mData; - bgl::blUniformMatrix3fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f); + glUniformMatrix3fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f); }break; } mDirty = false; #endif -#endif } void BL_Uniform::SetData(int location, int type,bool transpose) @@ -143,17 +125,14 @@ BL_Shader::BL_Shader(PyTypeObject *T) mError(0), mDirty(true) { - // if !RAS_EXT_support._ARB_shader_objects this class will not be used + // if !GLEW_ARB_shader_objects this class will not be used //for (int i=0; i<MAXTEX; i++) { // mSampler[i] = BL_Sampler(); //} } -using namespace bgl; - BL_Shader::~BL_Shader() { -#ifdef GL_ARB_shader_objects //for (int i=0; i<MAXTEX; i++){ // if(mSampler[i].mOwn) { // if(mSampler[i].mTexture) @@ -163,14 +142,13 @@ BL_Shader::~BL_Shader() ClearUniforms(); if( mShader ) { - bgl::blDeleteObjectARB(mShader); + glDeleteObjectARB(mShader); mShader = 0; } vertProg = 0; fragProg = 0; mOk = 0; - bgl::blUseProgramObjectARB(0); -#endif//GL_ARB_shader_objects + glUseProgramObjectARB(0); } void BL_Shader::ClearUniforms() @@ -265,8 +243,6 @@ void BL_Shader::UnloadShader() bool BL_Shader::LinkProgram() { -#ifdef GL_ARB_shader_objects - int vertlen = 0, fraglen=0, proglen=0; int vertstatus=0, fragstatus=0, progstatus=0; unsigned int tmpVert=0, tmpFrag=0, tmpProg=0; @@ -280,25 +256,25 @@ bool BL_Shader::LinkProgram() spit("Invalid GLSL sources"); return false; } - if( !RAS_EXT_support._ARB_fragment_shader) { + if( !GLEW_ARB_fragment_shader) { spit("Fragment shaders not supported"); return false; } - if( !RAS_EXT_support._ARB_vertex_shader) { + if( !GLEW_ARB_vertex_shader) { spit("Vertex shaders not supported"); return false; } // -- vertex shader ------------------ - tmpVert = bgl::blCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); - bgl::blShaderSourceARB(tmpVert, 1, (const char**)&vertProg, 0); - bgl::blCompileShaderARB(tmpVert); - bgl::blGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB,(GLint*) &vertlen); + tmpVert = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); + glShaderSourceARB(tmpVert, 1, (const char**)&vertProg, 0); + glCompileShaderARB(tmpVert); + glGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB,(GLint*) &vertlen); // print info if any if( vertlen > 0 && vertlen < MAX_LOG_LEN){ logInf = (char*)MEM_mallocN(vertlen, "vert-log"); - bgl::blGetInfoLogARB(tmpVert, vertlen, (GLsizei*)&char_len, logInf); + glGetInfoLogARB(tmpVert, vertlen, (GLsizei*)&char_len, logInf); if(char_len >0) { spit("---- Vertex Shader Error ----"); spit(logInf); @@ -307,20 +283,20 @@ bool BL_Shader::LinkProgram() logInf=0; } // check for compile errors - bgl::blGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB,(GLint*)&vertstatus); + glGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB,(GLint*)&vertstatus); if(!vertstatus) { spit("---- Vertex shader failed to compile ----"); goto programError; } // -- fragment shader ---------------- - tmpFrag = bgl::blCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); - bgl::blShaderSourceARB(tmpFrag, 1,(const char**)&fragProg, 0); - bgl::blCompileShaderARB(tmpFrag); - bgl::blGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &fraglen); + tmpFrag = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); + glShaderSourceARB(tmpFrag, 1,(const char**)&fragProg, 0); + glCompileShaderARB(tmpFrag); + glGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &fraglen); if(fraglen >0 && fraglen < MAX_LOG_LEN){ logInf = (char*)MEM_mallocN(fraglen, "frag-log"); - bgl::blGetInfoLogARB(tmpFrag, fraglen,(GLsizei*) &char_len, logInf); + glGetInfoLogARB(tmpFrag, fraglen,(GLsizei*) &char_len, logInf); if(char_len >0) { spit("---- Fragment Shader Error ----"); spit(logInf); @@ -329,7 +305,7 @@ bool BL_Shader::LinkProgram() logInf=0; } - bgl::blGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*) &fragstatus); + glGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*) &fragstatus); if(!fragstatus){ spit("---- Fragment shader failed to compile ----"); goto programError; @@ -338,17 +314,17 @@ bool BL_Shader::LinkProgram() // -- program ------------------------ // set compiled vert/frag shader & link - tmpProg = bgl::blCreateProgramObjectARB(); - bgl::blAttachObjectARB(tmpProg, tmpVert); - bgl::blAttachObjectARB(tmpProg, tmpFrag); - bgl::blLinkProgramARB(tmpProg); - bgl::blGetObjectParameterivARB(tmpProg, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &proglen); - bgl::blGetObjectParameterivARB(tmpProg, GL_OBJECT_LINK_STATUS_ARB, (GLint*) &progstatus); + tmpProg = glCreateProgramObjectARB(); + glAttachObjectARB(tmpProg, tmpVert); + glAttachObjectARB(tmpProg, tmpFrag); + glLinkProgramARB(tmpProg); + glGetObjectParameterivARB(tmpProg, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &proglen); + glGetObjectParameterivARB(tmpProg, GL_OBJECT_LINK_STATUS_ARB, (GLint*) &progstatus); if(proglen > 0 && proglen < MAX_LOG_LEN) { logInf = (char*)MEM_mallocN(proglen, "prog-log"); - bgl::blGetInfoLogARB(tmpProg, proglen, (GLsizei*)&char_len, logInf); + glGetInfoLogARB(tmpProg, proglen, (GLsizei*)&char_len, logInf); if(char_len >0) { spit("---- GLSL Program ----"); spit(logInf); @@ -364,24 +340,24 @@ bool BL_Shader::LinkProgram() // set mShader = tmpProg; - bgl::blDeleteObjectARB(tmpVert); - bgl::blDeleteObjectARB(tmpFrag); + glDeleteObjectARB(tmpVert); + glDeleteObjectARB(tmpFrag); mOk = 1; mError = 0; return true; programError: if(tmpVert) { - bgl::blDeleteObjectARB(tmpVert); + glDeleteObjectARB(tmpVert); tmpVert=0; } if(tmpFrag) { - bgl::blDeleteObjectARB(tmpFrag); + glDeleteObjectARB(tmpFrag); tmpFrag=0; } if(tmpProg) { - bgl::blDeleteObjectARB(tmpProg); + glDeleteObjectARB(tmpProg); tmpProg=0; } @@ -389,9 +365,6 @@ programError: mUse = 0; mError = 1; return false; -#else - return false; -#endif//GL_ARB_shader_objects } const char *BL_Shader::GetVertPtr() @@ -427,15 +400,13 @@ unsigned int BL_Shader::GetProg() void BL_Shader::SetSampler(int loc, int unit) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { - bgl::blUniform1iARB(loc, unit); + glUniform1iARB(loc, unit); } -#endif } // //void BL_Shader::InitializeSampler(int unit, BL_Texture* texture) @@ -448,37 +419,33 @@ void BL_Shader::SetSampler(int loc, int unit) void BL_Shader::SetProg(bool enable) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { if( mShader != 0 && mOk && enable) { - bgl::blUseProgramObjectARB(mShader); + glUseProgramObjectARB(mShader); } else { - bgl::blUseProgramObjectARB(0); + glUseProgramObjectARB(0); } } -#endif } -void BL_Shader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty ) +void BL_Shader::Update( const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) { -#ifdef GL_ARB_shader_objects if(!Ok() || !mPreDef.size()) return; - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { 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); @@ -557,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; } @@ -577,210 +546,186 @@ void BL_Shader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty ) } } } -#endif } int BL_Shader::GetAttribLocation(const STR_String& name) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { - return bgl::blGetAttribLocationARB(mShader, name.ReadPtr()); + return glGetAttribLocationARB(mShader, name.ReadPtr()); } -#endif + return -1; } void BL_Shader::BindAttribute(const STR_String& attr, int loc) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { - bgl::blBindAttribLocationARB(mShader, loc, attr.ReadPtr()); + glBindAttribLocationARB(mShader, loc, attr.ReadPtr()); } -#endif } int BL_Shader::GetUniformLocation(const STR_String& name) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { MT_assert(mShader!=0); - int location = bgl::blGetUniformLocationARB(mShader, name.ReadPtr()); + int location = glGetUniformLocationARB(mShader, name.ReadPtr()); if(location == -1) spit("Invalid uniform value: " << name.ReadPtr() << "."); return location; } -#endif + return -1; } void BL_Shader::SetUniform(int uniform, const MT_Tuple2& vec) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { float value[2]; vec.getValue(value); - bgl::blUniform2fvARB(uniform, 1, value); + glUniform2fvARB(uniform, 1, value); } -#endif } void BL_Shader::SetUniform(int uniform, const MT_Tuple3& vec) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { float value[3]; vec.getValue(value); - bgl::blUniform3fvARB(uniform, 1, value); + glUniform3fvARB(uniform, 1, value); } -#endif } void BL_Shader::SetUniform(int uniform, const MT_Tuple4& vec) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { float value[4]; vec.getValue(value); - bgl::blUniform4fvARB(uniform, 1, value); + glUniform4fvARB(uniform, 1, value); } -#endif } void BL_Shader::SetUniform(int uniform, const unsigned int& val) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { - bgl::blUniform1iARB(uniform, val); + glUniform1iARB(uniform, val); } -#endif } void BL_Shader::SetUniform(int uniform, const int val) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { - bgl::blUniform1iARB(uniform, val); + glUniform1iARB(uniform, val); } -#endif } void BL_Shader::SetUniform(int uniform, const float& val) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { - bgl::blUniform1fARB(uniform, val); + glUniform1fARB(uniform, val); } -#endif } void BL_Shader::SetUniform(int uniform, const MT_Matrix4x4& vec, bool transpose) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { float value[16]; + // note: getValue gives back column major as needed by OpenGL vec.getValue(value); - bgl::blUniformMatrix4fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value); + glUniformMatrix4fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value); } -#endif } void BL_Shader::SetUniform(int uniform, const MT_Matrix3x3& vec, bool transpose) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { float value[9]; value[0] = (float)vec[0][0]; value[1] = (float)vec[1][0]; value[2] = (float)vec[2][0]; value[3] = (float)vec[0][1]; value[4] = (float)vec[1][1]; value[5] = (float)vec[2][1]; value[6] = (float)vec[0][2]; value[7] = (float)vec[1][2]; value[7] = (float)vec[2][2]; - bgl::blUniformMatrix3fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value); + glUniformMatrix3fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value); } -#endif } void BL_Shader::SetUniform(int uniform, const float* val, int len) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { if(len == 2) - bgl::blUniform2fvARB(uniform, 1,(GLfloat*)val); + glUniform2fvARB(uniform, 1,(GLfloat*)val); else if (len == 3) - bgl::blUniform3fvARB(uniform, 1,(GLfloat*)val); + glUniform3fvARB(uniform, 1,(GLfloat*)val); else if (len == 4) - bgl::blUniform4fvARB(uniform, 1,(GLfloat*)val); + glUniform4fvARB(uniform, 1,(GLfloat*)val); else MT_assert(0); } -#endif } void BL_Shader::SetUniform(int uniform, const int* val, int len) { -#ifdef GL_ARB_shader_objects - if( RAS_EXT_support._ARB_fragment_shader && - RAS_EXT_support._ARB_vertex_shader && - RAS_EXT_support._ARB_shader_objects + if( GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { if(len == 2) - bgl::blUniform2ivARB(uniform, 1, (GLint*)val); + glUniform2ivARB(uniform, 1, (GLint*)val); else if (len == 3) - bgl::blUniform3ivARB(uniform, 1, (GLint*)val); + glUniform3ivARB(uniform, 1, (GLint*)val); else if (len == 4) - bgl::blUniform4ivARB(uniform, 1, (GLint*)val); + glUniform4ivARB(uniform, 1, (GLint*)val); else MT_assert(0); } -#endif } @@ -848,7 +793,6 @@ PyParentObject BL_Shader::Parents[] = { KX_PYMETHODDEF_DOC( BL_Shader, setSource," setSource(vertexProgram, fragmentProgram)" ) { -#ifdef GL_ARB_shader_objects if(mShader !=0 && mOk ) { // already set... @@ -861,7 +805,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setSource," setSource(vertexProgram, fragmentProg vertProg = v; fragProg = f; if( LinkProgram() ) { - bgl::blUseProgramObjectARB( mShader ); + glUseProgramObjectARB( mShader ); mUse = apply!=0; Py_Return; } @@ -871,23 +815,18 @@ KX_PYMETHODDEF_DOC( BL_Shader, setSource," setSource(vertexProgram, fragmentProg Py_Return; } return NULL; -#else - Py_Return; -#endif } KX_PYMETHODDEF_DOC( BL_Shader, delSource, "delSource( )" ) { -#ifdef GL_ARB_shader_objects ClearUniforms(); - bgl::blUseProgramObjectARB(0); + glUseProgramObjectARB(0); - bgl::blDeleteObjectARB(mShader); + glDeleteObjectARB(mShader); mShader = 0; mOk = 0; mUse = 0; -#endif Py_Return; } @@ -908,25 +847,23 @@ KX_PYMETHODDEF_DOC( BL_Shader, getFragmentProg ,"getFragmentProg( )" ) KX_PYMETHODDEF_DOC( BL_Shader, validate, "validate()") { -#ifdef GL_ARB_shader_objects if(mError) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } if(mShader==0) { PyErr_Format(PyExc_TypeError, "invalid shader object"); return NULL; } int stat = 0; - bgl::blValidateProgramARB(mShader); - bgl::blGetObjectParameterivARB(mShader, GL_OBJECT_VALIDATE_STATUS_ARB,(GLint*) &stat); + glValidateProgramARB(mShader); + glGetObjectParameterivARB(mShader, GL_OBJECT_VALIDATE_STATUS_ARB,(GLint*) &stat); if(stat > 0 && stat < MAX_LOG_LEN) { int char_len=0; char *logInf = (char*)MEM_mallocN(stat, "validate-log"); - bgl::blGetInfoLogARB(mShader, stat,(GLsizei*) &char_len, logInf); + glGetInfoLogARB(mShader, stat,(GLsizei*) &char_len, logInf); if(char_len >0) { spit("---- GLSL Validation ----"); spit(logInf); @@ -934,7 +871,6 @@ KX_PYMETHODDEF_DOC( BL_Shader, validate, "validate()") MEM_freeN(logInf); logInf=0; } -#endif//GL_ARB_shader_objects Py_Return; } @@ -942,11 +878,10 @@ KX_PYMETHODDEF_DOC( BL_Shader, validate, "validate()") KX_PYMETHODDEF_DOC( BL_Shader, setSampler, "setSampler(name, index)" ) { if(mError) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; int index=-1; if(PyArg_ParseTuple(args, "si", &uniform, &index)) { @@ -965,7 +900,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setSampler, "setSampler(name, index)" ) //else // spit("Invalid texture sample index: " << index); } - Py_Return; + Py_RETURN_NONE; } return NULL; } @@ -984,11 +919,10 @@ KX_PYMETHODDEF_DOC( BL_Shader, setNumberOfPasses, "setNumberOfPasses( max-pass ) KX_PYMETHODDEF_DOC( BL_Shader, setUniform1f, "setUniform1f(name, fx)" ) { if(mError) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; float value=0; if(PyArg_ParseTuple(args, "sf", &uniform, &value )) { @@ -1010,10 +944,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1f, "setUniform1f(name, fx)" ) KX_PYMETHODDEF_DOC( BL_Shader, setUniform2f , "setUniform2f(name, fx, fy)") { if(mError) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; float array[2]={ 0,0 }; if(PyArg_ParseTuple(args, "sff", &uniform, &array[0],&array[1] )) { @@ -1035,10 +968,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2f , "setUniform2f(name, fx, fy)") KX_PYMETHODDEF_DOC( BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ") { if(mError) { - Py_INCREF(Py_None); - return Py_None; + 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])) { @@ -1061,10 +993,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ") KX_PYMETHODDEF_DOC( BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ") { if(mError) { - Py_INCREF(Py_None); - return Py_None; + 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])) { @@ -1086,10 +1017,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) " KX_PYMETHODDEF_DOC( BL_Shader, setUniform1i, "setUniform1i(name, ix)" ) { if(mError) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; int value=0; if(PyArg_ParseTuple(args, "si", &uniform, &value )) { @@ -1111,10 +1041,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1i, "setUniform1i(name, ix)" ) KX_PYMETHODDEF_DOC( BL_Shader, setUniform2i , "setUniform2i(name, ix, iy)") { if(mError) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } - char *uniform=""; + const char *uniform=""; int array[2]={ 0,0 }; if(PyArg_ParseTuple(args, "sii", &uniform, &array[0],&array[1] )) { @@ -1136,11 +1065,10 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2i , "setUniform2i(name, ix, iy)") KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ") { if(mError) { - Py_INCREF(Py_None); - return Py_None; + 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])) { @@ -1161,10 +1089,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ") KX_PYMETHODDEF_DOC( BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) ") { if(mError) { - Py_INCREF(Py_None); - return Py_None; + 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] )) { @@ -1185,10 +1112,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) " KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv , "setUniformfv( float (list2 or list3 or list4) )") { if(mError) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } - char*uniform = ""; + const char *uniform = ""; PyObject *listPtr =0; float array_data[4] = {0.f,0.f,0.f,0.f}; @@ -1255,10 +1181,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv , "setUniformfv( float (list2 or lis KX_PYMETHODDEF_DOC( BL_Shader, setUniformiv, "setUniformiv( int (list2 or list3 or list4) )") { if(mError) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } - char*uniform = ""; + const char *uniform = ""; PyObject *listPtr =0; int array_data[4] = {0,0,0,0}; @@ -1328,8 +1253,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix4, "setUniformMatrix4(uniform-name, mat-4x4, transpose(row-major=true, col-major=false)" ) { if(mError) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } float matr[16] = { @@ -1339,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)) @@ -1371,8 +1295,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix3, "setUniformMatrix3(uniform-name, list[3x3], transpose(row-major=true, col-major=false)" ) { if(mError) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } float matr[9] = { @@ -1381,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)) @@ -1411,10 +1334,8 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix3, KX_PYMETHODDEF_DOC( BL_Shader, setAttrib, "setAttrib(enum)" ) { -#ifdef GL_ARB_shader_objects if(mError) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } int attr=0; if(PyArg_ParseTuple(args, "i", &attr )) { @@ -1423,23 +1344,21 @@ KX_PYMETHODDEF_DOC( BL_Shader, setAttrib, "setAttrib(enum)" ) return NULL; } mAttr=SHD_TANGENT; - bgl::blUseProgramObjectARB(mShader); - bgl::blBindAttribLocationARB(mShader, mAttr, "Tangent"); + glUseProgramObjectARB(mShader); + glBindAttribLocationARB(mShader, mAttr, "Tangent"); Py_Return; } return NULL; -#endif } KX_PYMETHODDEF_DOC( BL_Shader, setUniformDef, "setUniformDef(name, enum)" ) { if(mError) { - Py_INCREF(Py_None); - return Py_None; + 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/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp index 53e1af46e4e..f0ef84032f7 100644 --- a/source/gameengine/Ketsji/BL_Texture.cpp +++ b/source/gameengine/Ketsji/BL_Texture.cpp @@ -1,22 +1,10 @@ // ------------------------------------ -#ifdef WIN32 -#include <windows.h> -#endif // WIN32 -#ifdef __APPLE__ -#define GL_GLEXT_LEGACY 1 -#include <OpenGL/gl.h> -#include <OpenGL/glu.h> -#else -#include <GL/gl.h> -#if defined(__sun__) && !defined(__sparc__) -#include <mesa/glu.h> -#else -#include <GL/glu.h> -#endif -#endif + +#include "GL/glew.h" #include <iostream> #include <map> +#include <stdlib.h> #include "BL_Material.h" #include "BL_Texture.h" @@ -29,15 +17,11 @@ #include "BLI_blenlib.h" #include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h" -#include "RAS_OpenGLRasterizer/ARB_multitexture.h" #include "RAS_ICanvas.h" #include "RAS_Rect.h" #include "KX_GameObject.h" - -using namespace bgl; - #define spit(x) std::cout << x << std::endl; #include "MEM_guardedalloc.h" @@ -219,9 +203,7 @@ void BL_Texture::InitNonPow2Tex(unsigned int *pix,int x,int y,bool mipmap) bool BL_Texture::InitCubeMap(int unit, EnvMap *cubemap) { -#ifdef GL_ARB_texture_cube_map - - if (!RAS_EXT_support._ARB_texture_cube_map) + if (!GLEW_ARB_texture_cube_map) { spit("cubemaps not supported"); mOk = false; @@ -311,9 +293,8 @@ bool BL_Texture::InitCubeMap(int unit, EnvMap *cubemap) glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - #ifdef GL_VERSION_1_2 - glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); - #endif + if(GLEW_VERSION_1_2) + glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); if (needs_split) my_free_envmapdata(cubemap); @@ -325,13 +306,6 @@ bool BL_Texture::InitCubeMap(int unit, EnvMap *cubemap) mOk = IsValid(); return mOk; - -#else - - mOk = false; - return mOk; - -#endif//GL_ARB_texture_cube_map } bool BL_Texture::IsValid() @@ -360,51 +334,41 @@ unsigned int BL_Texture::GetTextureType() const int BL_Texture::GetMaxUnits() { GLint unit=0; -#ifdef GL_ARB_multitexture - if(RAS_EXT_support._ARB_multitexture) { + + if(GLEW_ARB_multitexture) { glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &unit); return (MAXTEX>=unit?unit:MAXTEX); } -#endif + return 0; } void BL_Texture::ActivateFirst() { -#ifdef GL_ARB_multitexture - if(RAS_EXT_support._ARB_multitexture) - bgl::blActiveTextureARB(GL_TEXTURE0_ARB); -#endif + if(GLEW_ARB_multitexture) + glActiveTextureARB(GL_TEXTURE0_ARB); } void BL_Texture::ActivateUnit(int unit) { -#ifdef GL_ARB_multitexture - if(RAS_EXT_support._ARB_multitexture) + if(GLEW_ARB_multitexture) if(unit <= MAXTEX) - bgl::blActiveTextureARB(GL_TEXTURE0_ARB+unit); -#endif + glActiveTextureARB(GL_TEXTURE0_ARB+unit); } void BL_Texture::DisableUnit() { -#ifdef GL_ARB_multitexture - if(RAS_EXT_support._ARB_multitexture) - bgl::blActiveTextureARB(GL_TEXTURE0_ARB+mUnit); - -#endif - + if(GLEW_ARB_multitexture) + glActiveTextureARB(GL_TEXTURE0_ARB+mUnit); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); - #ifdef GL_ARB_texture_cube_map - if(RAS_EXT_support._ARB_texture_cube_map && glIsEnabled(GL_TEXTURE_CUBE_MAP_ARB)) + if(GLEW_ARB_texture_cube_map && glIsEnabled(GL_TEXTURE_CUBE_MAP_ARB)) glDisable(GL_TEXTURE_CUBE_MAP_ARB); else - #endif { if (glIsEnabled(GL_TEXTURE_2D)) glDisable(GL_TEXTURE_2D); @@ -420,11 +384,9 @@ void BL_Texture::DisableUnit() void BL_Texture::DisableAllTextures() { -#ifdef GL_ARB_multitexture - glDisable(GL_BLEND); for(int i=0; i<MAXTEX; i++) { - if(RAS_EXT_support._ARB_multitexture) - bgl::blActiveTextureARB(GL_TEXTURE0_ARB+i); + if(GLEW_ARB_multitexture) + glActiveTextureARB(GL_TEXTURE0_ARB+i); glMatrixMode(GL_TEXTURE); glLoadIdentity(); @@ -436,38 +398,29 @@ void BL_Texture::DisableAllTextures() glDisable(GL_TEXTURE_GEN_Q); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); } - if(RAS_EXT_support._ARB_multitexture) - bgl::blActiveTextureARB(GL_TEXTURE0_ARB); -#endif + if(GLEW_ARB_multitexture) + glActiveTextureARB(GL_TEXTURE0_ARB); } void BL_Texture::ActivateTexture() { -#ifdef GL_ARB_multitexture - if(RAS_EXT_support._ARB_multitexture) - bgl::blActiveTextureARB(GL_TEXTURE0_ARB+mUnit); + if(GLEW_ARB_multitexture) + glActiveTextureARB(GL_TEXTURE0_ARB+mUnit); -#ifdef GL_ARB_texture_cube_map - if (mType == GL_TEXTURE_CUBE_MAP_ARB && RAS_EXT_support._ARB_texture_cube_map) + if (mType == GL_TEXTURE_CUBE_MAP_ARB && GLEW_ARB_texture_cube_map) { glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, mTexture ); glEnable(GL_TEXTURE_CUBE_MAP_ARB); } - else -#endif - { - - #ifdef GL_ARB_texture_cube_map - if(RAS_EXT_support._ARB_texture_cube_map ) + else { + if(GLEW_ARB_texture_cube_map ) glDisable(GL_TEXTURE_CUBE_MAP_ARB); - #endif glBindTexture( GL_TEXTURE_2D, mTexture ); glEnable(GL_TEXTURE_2D); } -#endif } void BL_Texture::SetMapping(int mode) @@ -481,9 +434,8 @@ void BL_Texture::SetMapping(int mode) return; } -#ifdef GL_ARB_texture_cube_map if( mType == GL_TEXTURE_CUBE_MAP_ARB && - RAS_EXT_support._ARB_texture_cube_map && + GLEW_ARB_texture_cube_map && mode &USEREFL) { glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB ); @@ -497,7 +449,6 @@ void BL_Texture::SetMapping(int mode) return; } else -#endif { glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP ); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP ); @@ -512,11 +463,7 @@ void BL_Texture::SetMapping(int mode) void BL_Texture::setTexEnv(BL_Material *mat, bool modulate) { -#ifndef GL_ARB_texture_env_combine - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - return; -#else - if(modulate || !RAS_EXT_support._ARB_texture_env_combine){ + if(modulate || !GLEW_ARB_texture_env_combine){ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); return; } @@ -650,7 +597,6 @@ void BL_Texture::setTexEnv(BL_Material *mat, bool modulate) glTexEnvf( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0); glEndList(); -#endif //!GL_ARB_texture_env_combine } int BL_Texture::GetPow2(int n) diff --git a/source/gameengine/Ketsji/BL_Texture.h b/source/gameengine/Ketsji/BL_Texture.h index 0d0c7a277f2..830ffceb0f7 100644 --- a/source/gameengine/Ketsji/BL_Texture.h +++ b/source/gameengine/Ketsji/BL_Texture.h @@ -59,6 +59,14 @@ public: void SetMapping(int mode); void DisableUnit(); void setTexEnv(BL_Material *mat, bool modulate=false); + unsigned int swapTexture (unsigned int newTex) { + // swap texture codes + unsigned int tmp = mTexture; + mTexture = newTex; + // return original texture code + return tmp; + } + }; #endif//__BL_TEXTURE_H__ diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index a10b07ff491..d054894589f 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -26,6 +26,19 @@ FILE(GLOB SRC *.cpp) +#XXX disabled for 2.5 because of missing python +#SET(SRC +# ${SRC} +# ../../../source/blender/python/api2_2x/Mathutils.c +# ../../../source/blender/python/api2_2x/constant.c +# ../../../source/blender/python/api2_2x/euler.c +# ../../../source/blender/python/api2_2x/gen_utils.c +# ../../../source/blender/python/api2_2x/matrix.c +# ../../../source/blender/python/api2_2x/point.c +# ../../../source/blender/python/api2_2x/quat.c +# ../../../source/blender/python/api2_2x/vector.c +#) + SET(INC . ../../../source/kernel/gen_system @@ -39,7 +52,8 @@ SET(INC ../../../intern/moto/include ../../../source/gameengine/Ketsji ../../../source/blender/blenlib - ../../../source/blender/blenkernel + ../../../source/blender/blenkernel + ../../../source/blender/python/api2_2x ../../../source/blender ../../../source/blender/include ../../../source/blender/makesdna @@ -57,8 +71,10 @@ SET(INC ../../../intern/SoundSystem ../../../source/blender/misc ../../../source/blender/blenloader + ../../../source/blender/gpu ../../../extern/bullet2/src ../../../extern/solid + ../../../extern/glew/include ${PYTHON_INC} ${SDL_INC} ) diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp index 7b5b7fdf78c..eee8e9f6827 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp @@ -55,28 +55,13 @@ KX_NetworkEventManager::~KX_NetworkEventManager() //printf("KX_NetworkEventManager destructor\n"); } -void KX_NetworkEventManager::RegisterSensor(class SCA_ISensor* sensor) -{ - //printf("KX_NetworkEventManager RegisterSensor\n"); - m_sensors.push_back(sensor); -} - -void KX_NetworkEventManager::RemoveSensor(class SCA_ISensor* sensor) -{ - //printf("KX_NetworkEventManager RemoveSensor\n"); - // Network specific RemoveSensor stuff goes here - - // parent - SCA_EventManager::RemoveSensor(sensor); -} - void KX_NetworkEventManager::NextFrame() { // printf("KX_NetworkEventManager::proceed %.2f - %.2f\n", curtime, deltatime); // each frame, the logicmanager will call the network // eventmanager to look for network events, and process it's // 'network' sensors - vector<class SCA_ISensor*>::iterator it; + set<class SCA_ISensor*>::iterator it; for (it = m_sensors.begin(); !(it==m_sensors.end()); it++) { // printf("KX_NetworkEventManager::proceed sensor %.2f\n", curtime); diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h index 0b097ba2ef6..ae88f1d4987 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h @@ -42,9 +42,6 @@ public: class NG_NetworkDeviceInterface *ndi); virtual ~KX_NetworkEventManager (); - virtual void RegisterSensor(class SCA_ISensor* sensor); - virtual void RemoveSensor(class SCA_ISensor* sensor); - virtual void NextFrame(); virtual void EndFrame(); diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp index 3ade810c394..85921ae75ca 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp @@ -158,6 +158,9 @@ PyObject* KX_NetworkMessageActuator::PySetToPropName( if (PyArg_ParseTuple(args, "s", &ToPropName)) { m_toPropName = ToPropName; } + else { + return NULL; + } Py_Return; } @@ -173,7 +176,10 @@ PyObject* KX_NetworkMessageActuator::PySetSubject( if (PyArg_ParseTuple(args, "s", &Subject)) { m_subject = Subject; } - + else { + return NULL; + } + Py_Return; } @@ -188,6 +194,9 @@ PyObject* KX_NetworkMessageActuator::PySetBodyType( if (PyArg_ParseTuple(args, "i", &BodyType)) { m_bodyType = BodyType; } + else { + return NULL; + } Py_Return; } @@ -203,6 +212,9 @@ PyObject* KX_NetworkMessageActuator::PySetBody( if (PyArg_ParseTuple(args, "s", &Body)) { m_body = Body; } + else { + return NULL; + } Py_Return; } diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp index c9fa920a426..8956df9c96b 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp @@ -58,10 +58,15 @@ KX_NetworkMessageSensor::KX_NetworkMessageSensor( m_NetworkScene(NetworkScene), m_subject(subject), m_frame_message_count (0), - m_IsUp(false), m_BodyList(NULL), m_SubjectList(NULL) { + Init(); +} + +void KX_NetworkMessageSensor::Init() +{ + m_IsUp = false; } KX_NetworkMessageSensor::~KX_NetworkMessageSensor() @@ -139,7 +144,11 @@ bool KX_NetworkMessageSensor::Evaluate(CValue* event) result = (WasUp != m_IsUp); - // Return true if the message received state has changed. + // Return always true if a message was received otherwise we can loose messages + if (m_IsUp) + return true; + // Is it usefull to return also true when the first frame without a message?? + // This will cause a fast on/off cycle that seems useless! return result; } @@ -187,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 }; @@ -209,85 +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; + 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 d051b715aab..8cdfd6cdb5a 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h @@ -65,6 +65,7 @@ public: virtual CValue* GetReplica(); virtual bool Evaluate(CValue* event); virtual bool IsPositiveTrigger(); + virtual void Init(); void EndFrame(); /* ------------------------------------------------------------- */ @@ -73,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 bbf5640f8e0..f92200780d5 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -6,21 +6,7 @@ #include <config.h> #endif -#ifdef WIN32 -#include <windows.h> -#endif // WIN32 -#ifdef __APPLE__ -#define GL_GLEXT_LEGACY 1 -#include <OpenGL/gl.h> -#include <OpenGL/glu.h> -#else -#include <GL/gl.h> -#if defined(__sun__) && !defined(__sparc__) -#include <mesa/glu.h> -#else -#include <GL/glu.h> -#endif -#endif +#include "GL/glew.h" #include "KX_BlenderMaterial.h" #include "BL_Material.h" @@ -33,14 +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" -#include "RAS_OpenGLRasterizer/ARB_multitexture.h" -extern "C" { -//XXX #include "BDR_drawmesh.h" -} +#include "GPU_draw.h" #include "STR_HashedString.h" @@ -51,9 +35,11 @@ extern "C" { #include "DNA_meshdata_types.h" #include "BKE_mesh.h" // ------------------------------------ -using namespace bgl; #define spit(x) std::cout << x << std::endl; +BL_Shader *KX_BlenderMaterial::mLastShader = NULL; +BL_BlenderShader *KX_BlenderMaterial::mLastBlenderShader = NULL; + //static PyObject *gTextureDict = 0; KX_BlenderMaterial::KX_BlenderMaterial( @@ -61,7 +47,6 @@ KX_BlenderMaterial::KX_BlenderMaterial( BL_Material *data, bool skin, int lightlayer, - void *clientobject, PyTypeObject *T ) : PyObjectPlus(T), @@ -72,35 +57,33 @@ KX_BlenderMaterial::KX_BlenderMaterial( data->tilexrep[0], data->tileyrep[0], data->mode, - ((data->ras_mode &TRANSP)!=0), + data->transp, + ((data->ras_mode &ALPHA)!=0), ((data->ras_mode &ZSORT)!=0), - lightlayer, - ((data->ras_mode &TRIANGLE)!=0), - clientobject + lightlayer ), mMaterial(data), mShader(0), + mBlenderShader(0), mScene(scene), mUserDefBlend(0), mModified(0), + mConstructed(false), mPass(0) { // -------------------------------- // 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 |=(mMaterial->ras_mode &ALPHA_TEST)!=0?RAS_FORCEALPHA: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; int max = BL_Texture::GetMaxUnits(); mMaterial->num_enabled = enabled>=max?max:enabled; - // base class - m_enabled = mMaterial->num_enabled; - // test the sum of the various modes for equality // so we can ether accept or reject this material // as being equal, this is rather important to @@ -111,14 +94,16 @@ 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)); } KX_BlenderMaterial::~KX_BlenderMaterial() { // cleanup work - OnExit(); + if (mConstructed) + // clean only if material was actually used + OnExit(); } @@ -137,41 +122,77 @@ unsigned int* KX_BlenderMaterial::GetMCol(void) const void KX_BlenderMaterial::OnConstruction() { + if (mConstructed) + // when material are reused between objects + return; + + if(mMaterial->glslmat) + SetBlenderGLSLShader(); + // for each unique material... int i; for(i=0; i<mMaterial->num_enabled; i++) { if( mMaterial->mapping[i].mapping & USEENV ) { - if(!RAS_EXT_support._ARB_texture_cube_map) { + if(!GLEW_ARB_texture_cube_map) { spit("CubeMap textures not supported"); continue; } if(!mTextures[i].InitCubeMap(i, mMaterial->cubemap[i] ) ) spit("unable to initialize image("<<i<<") in "<< - mMaterial->matname<< ", image will not be available"); + mMaterial->matname<< ", image will not be available"); } else { if( mMaterial->img[i] ) { if( ! mTextures[i].InitFromImage(i, mMaterial->img[i], (mMaterial->flag[i] &MIPMAP)!=0 )) spit("unable to initialize image("<<i<<") in "<< - mMaterial->matname<< ", image will not be available"); + mMaterial->matname<< ", image will not be available"); } } } + mBlendFunc[0] =0; mBlendFunc[1] =0; + mConstructed = true; +} + +void KX_BlenderMaterial::EndFrame() +{ + if(mLastBlenderShader) { + mLastBlenderShader->SetProg(false); + mLastBlenderShader = NULL; + } + + if(mLastShader) { + mLastShader->SetProg(false); + mLastShader = NULL; + } } void KX_BlenderMaterial::OnExit() { if( mShader ) { - //note, the shader here is allocated, per unique material - //and this function is called per face - mShader->SetProg(0); + //note, the shader here is allocated, per unique material + //and this function is called per face + if(mShader == mLastShader) { + mShader->SetProg(false); + mLastShader = NULL; + } + delete mShader; mShader = 0; } + if( mBlenderShader ) { + if(mBlenderShader == mLastBlenderShader) { + mBlenderShader->SetProg(false); + mLastBlenderShader = NULL; + } + + delete mBlenderShader; + mBlenderShader = 0; + } + BL_Texture::ActivateFirst(); for(int i=0; i<mMaterial->num_enabled; i++) { BL_Texture::ActivateUnit(i); @@ -180,24 +201,30 @@ void KX_BlenderMaterial::OnExit() } if( mMaterial->tface ) - ; //XXX set_tpage(mMaterial->tface); + GPU_set_tpage(mMaterial->tface); } void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras) { - MT_assert(RAS_EXT_support._ARB_shader_objects && mShader); + MT_assert(GLEW_ARB_shader_objects && mShader); int i; if( !enable || !mShader->Ok() ) { // frame cleanup. - mShader->SetProg(false); + if(mShader == mLastShader) { + mShader->SetProg(false); + mLastShader = NULL; + } + + ras->SetBlendingMode(TF_SOLID); BL_Texture::DisableAllTextures(); return; } BL_Texture::DisableAllTextures(); mShader->SetProg(true); + mLastShader = mShader; BL_Texture::ActivateFirst(); @@ -211,29 +238,60 @@ void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras) } if(!mUserDefBlend) { - setDefaultBlending(); + ras->SetBlendingMode(mMaterial->transp); } else { + ras->SetBlendingMode(TF_SOLID); + ras->SetBlendingMode(-1); // indicates custom mode + // tested to be valid enums glEnable(GL_BLEND); glBlendFunc(mBlendFunc[0], mBlendFunc[1]); } } +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(); + + return; + } + + if(!mBlenderShader->Equals(mLastBlenderShader)) { + ras->SetBlendingMode(mMaterial->transp); + + if(mLastBlenderShader) + mLastBlenderShader->SetProg(false); + else + BL_Texture::DisableAllTextures(); + + mBlenderShader->SetProg(true, ras->GetTime()); + mLastBlenderShader= mBlenderShader; + } +} void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras) { - if(RAS_EXT_support._ARB_shader_objects && mShader) - mShader->SetProg(false); - BL_Texture::DisableAllTextures(); - if( !enable ) + + if( !enable ) { + ras->SetBlendingMode(TF_SOLID); return; + } BL_Texture::ActivateFirst(); if( mMaterial->IdMode == DEFAULT_BLENDER ) { - setDefaultBlending(); + ras->SetBlendingMode(mMaterial->transp); return; } @@ -243,7 +301,7 @@ void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras) mTextures[0].ActivateTexture(); mTextures[0].setTexEnv(0, true); mTextures[0].SetMapping(mMaterial->mapping[0].mapping); - setDefaultBlending(); + ras->SetBlendingMode(mMaterial->transp); } return; } @@ -266,9 +324,12 @@ void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras) } if(!mUserDefBlend) { - setDefaultBlending(); + ras->SetBlendingMode(mMaterial->transp); } else { + ras->SetBlendingMode(TF_SOLID); + ras->SetBlendingMode(-1); // indicates custom mode + glEnable(GL_BLEND); glBlendFunc(mBlendFunc[0], mBlendFunc[1]); } @@ -284,29 +345,31 @@ KX_BlenderMaterial::ActivatShaders( // reset... if(tmp->mMaterial->IsShared()) cachingInfo =0; - + + if(mLastBlenderShader) { + mLastBlenderShader->SetProg(false); + mLastBlenderShader= NULL; + } + 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); - rasty->EnableTextures(true); - } - else { - tmp->setShaderData( false, rasty); - rasty->EnableTextures(false); - } + if(rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) + tmp->setShaderData(true, rasty); + else + 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); @@ -321,33 +384,84 @@ KX_BlenderMaterial::ActivatShaders( } void +KX_BlenderMaterial::ActivateBlenderShaders( + RAS_IRasterizer* rasty, + TCachingInfo& cachingInfo)const +{ + KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this); + + if(mLastShader) { + mLastShader->SetProg(false); + mLastShader= NULL; + } + + if (GetCachingInfo() != cachingInfo) { + if (!cachingInfo) + tmp->setBlenderShaderData(false, rasty); + + cachingInfo = GetCachingInfo(); + + if(rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) + tmp->setBlenderShaderData(true, rasty); + else + tmp->setBlenderShaderData(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) || + (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) + { + if((mMaterial->ras_mode &WIRE)!=0) + rasty->SetCullFace(false); + rasty->SetLines(true); + } + else + rasty->SetLines(false); + + ActivatGLMaterials(rasty); + mBlenderShader->SetAttribs(rasty, mMaterial); + } +} + +void KX_BlenderMaterial::ActivateMat( RAS_IRasterizer* rasty, TCachingInfo& cachingInfo )const { KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this); + + if(mLastShader) { + mLastShader->SetProg(false); + mLastShader= NULL; + } + + if(mLastBlenderShader) { + mLastBlenderShader->SetProg(false); + mLastBlenderShader= NULL; + } + if (GetCachingInfo() != cachingInfo) { if (!cachingInfo) tmp->setTexData( false,rasty ); cachingInfo = GetCachingInfo(); - if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) { + if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) tmp->setTexData( true,rasty ); - rasty->EnableTextures(true); - } - else{ + else tmp->setTexData( 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); @@ -356,77 +470,113 @@ KX_BlenderMaterial::ActivateMat( else rasty->SetLines(false); } + ActivatGLMaterials(rasty); ActivateTexGen(rasty); } - bool KX_BlenderMaterial::Activate( RAS_IRasterizer* rasty, TCachingInfo& cachingInfo )const { - bool dopass = false; - if( RAS_EXT_support._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) { + mShader->SetProg(false); + mLastShader = NULL; + } + mPass = 0; + return false; + } + } + else if( GLEW_ARB_shader_objects && (mBlenderShader && mBlenderShader->Ok() ) ) { + if(mPass++ == 0) { + ActivateBlenderShaders(rasty, cachingInfo); + return true; } else { - mShader->SetProg(false); 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; } -void KX_BlenderMaterial::ActivateMeshSlot(const KX_MeshSlot & ms, RAS_IRasterizer* rasty) const +bool KX_BlenderMaterial::UsesLighting(RAS_IRasterizer *rasty) const { - if(mShader && RAS_EXT_support._ARB_shader_objects) + if(!RAS_IPolyMaterial::UsesLighting(rasty)) + return false; + + if(mShader && mShader->Ok()) + return true; + else if(mBlenderShader && mBlenderShader->Ok()) + return false; + else + return true; +} + +void KX_BlenderMaterial::ActivateMeshSlot(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty) const +{ + if(mShader && GLEW_ARB_shader_objects) { mShader->Update(ms, rasty); + } + else if(mBlenderShader && GLEW_ARB_shader_objects) { + int blendmode; + + mBlenderShader->Update(ms, rasty); + + /* we do blend modes here, because they can change per object + * 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; + + rasty->SetBlendingMode(blendmode); + } } void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const { - rasty->SetSpecularity( - mMaterial->speccolor[0]*mMaterial->spec_f, - mMaterial->speccolor[1]*mMaterial->spec_f, - mMaterial->speccolor[2]*mMaterial->spec_f, - mMaterial->spec_f - ); + if(mShader || !mBlenderShader) { + rasty->SetSpecularity( + mMaterial->speccolor[0]*mMaterial->spec_f, + mMaterial->speccolor[1]*mMaterial->spec_f, + mMaterial->speccolor[2]*mMaterial->spec_f, + mMaterial->spec_f + ); - rasty->SetShinyness( mMaterial->hard ); + rasty->SetShinyness( mMaterial->hard ); - rasty->SetDiffuse( - mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit, - mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit, - mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit, - 1.0f); + rasty->SetDiffuse( + mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit, + mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit, + mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit, + 1.0f); - rasty->SetEmissive( - mMaterial->matcolor[0]*mMaterial->emit, - mMaterial->matcolor[1]*mMaterial->emit, - mMaterial->matcolor[2]*mMaterial->emit, - 1.0 ); + rasty->SetEmissive( + mMaterial->matcolor[0]*mMaterial->emit, + mMaterial->matcolor[1]*mMaterial->emit, + mMaterial->matcolor[2]*mMaterial->emit, + 1.0 ); + + rasty->SetAmbient(mMaterial->amb); + } - rasty->SetAmbient(mMaterial->amb); if (mMaterial->material) rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0); } @@ -434,52 +584,43 @@ void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const { - if(mShader && RAS_EXT_support._ARB_shader_objects) - if(mShader->GetAttribute() == BL_Shader::SHD_TANGENT) - ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT); + if(ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) { + ras->SetAttribNum(0); + if(mShader && GLEW_ARB_shader_objects) { + if(mShader->GetAttribute() == BL_Shader::SHD_TANGENT) { + ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, 0); + ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT, 1); + ras->SetAttribNum(2); + } + } - for(int i=0; i<mMaterial->num_enabled; i++) { - int mode = mMaterial->mapping[i].mapping; + ras->SetTexCoordNum(mMaterial->num_enabled); - if (mode &USECUSTOMUV) - { - STR_String str = mMaterial->mapping[i].uvCoName; - if (!str.IsEmpty()) - ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_UV2, i); - continue; - } + for(int i=0; i<mMaterial->num_enabled; i++) { + int mode = mMaterial->mapping[i].mapping; - if( mode &(USEREFL|USEOBJ)) - ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_GEN, i); - else if(mode &USEORCO) - ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_ORCO, i); - else if(mode &USENORM) - ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_NORM, i); - else if(mode &USEUV) - ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_UV1, i); - else if(mode &USETANG) - ras->SetTexCoords(RAS_IRasterizer::RAS_TEXTANGENT, i); - else - ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_DISABLE, i); - } -} + if (mode &USECUSTOMUV) + { + STR_String str = mMaterial->mapping[i].uvCoName; + if (!str.IsEmpty()) + ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV2, i); + continue; + } -bool KX_BlenderMaterial::setDefaultBlending() -{ - if( mMaterial->transp &TF_ADD) { - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - return true; - } - - if( mMaterial->transp & TF_ALPHA ) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - return true; + if( mode &(USEREFL|USEOBJ)) + ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_GEN, i); + else if(mode &USEORCO) + ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_ORCO, i); + else if(mode &USENORM) + ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_NORM, i); + else if(mode &USEUV) + ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV1, i); + else if(mode &USETANG) + ras->SetTexCoord(RAS_IRasterizer::RAS_TEXTANGENT, i); + else + ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_DISABLE, i); + } } - - glDisable(GL_BLEND); - return false; } void KX_BlenderMaterial::setTexMatrixData(int i) @@ -487,8 +628,7 @@ void KX_BlenderMaterial::setTexMatrixData(int i) glMatrixMode(GL_TEXTURE); glLoadIdentity(); -#ifdef GL_ARB_texture_cube_map - if( RAS_EXT_support._ARB_texture_cube_map && + if( GLEW_ARB_texture_cube_map && mTextures[i].GetTextureType() == GL_TEXTURE_CUBE_MAP_ARB && mMaterial->mapping[i].mapping & USEREFL) { glScalef( @@ -498,7 +638,6 @@ void KX_BlenderMaterial::setTexMatrixData(int i) ); } else -#endif { glScalef( mMaterial->mapping[i].scale[0], @@ -556,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(); @@ -647,28 +785,23 @@ int KX_BlenderMaterial::_setattr(const STR_String& attr, PyObject *pyvalue) KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()") { -#ifdef GL_ARB_fragment_shader - if( !RAS_EXT_support._ARB_fragment_shader) { + if( !GLEW_ARB_fragment_shader) { if(!mModified) spit("Fragment shaders not supported"); mModified = true; Py_Return; } -#endif -#ifdef GL_ARB_vertex_shader - if( !RAS_EXT_support._ARB_vertex_shader) { + if( !GLEW_ARB_vertex_shader) { if(!mModified) spit("Vertex shaders not supported"); mModified = true; Py_Return; } -#endif -#ifdef GL_ARB_shader_objects - if(!RAS_EXT_support._ARB_shader_objects) { + if(!GLEW_ARB_shader_objects) { if(!mModified) spit("GLSL not supported"); mModified = true; @@ -684,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 @@ -707,13 +842,20 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()") } PyErr_Format(PyExc_ValueError, "GLSL Error"); return NULL; - -#else - Py_Return; -#endif//GL_ARB_shader_objects } +void KX_BlenderMaterial::SetBlenderGLSLShader(void) +{ + if(!mBlenderShader) + mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, m_lightlayer); + + if(!mBlenderShader->Ok()) { + delete mBlenderShader; + mBlenderShader = 0; + } +} + KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()") { return PyInt_FromLong( mMaterial->material_index ); diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h index 2b1264154d0..6e5db1b56c1 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.h +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h @@ -8,6 +8,7 @@ #include "BL_Material.h" #include "BL_Texture.h" #include "BL_Shader.h" +#include "BL_BlenderShader.h" #include "PyObjectPlus.h" @@ -27,7 +28,6 @@ public: BL_Material* mat, bool skin, int lightlayer, - void* clientobject, PyTypeObject* T=&Type ); @@ -46,7 +46,7 @@ public: virtual void ActivateMeshSlot( - const KX_MeshSlot & ms, + const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) const; @@ -60,9 +60,19 @@ public: TCachingInfo& cachingInfo )const; + void ActivateBlenderShaders( + RAS_IRasterizer* rasty, + TCachingInfo& cachingInfo + )const; MTFace* GetMTFace(void) const; unsigned int* GetMCol(void) const; + BL_Texture * getTex (unsigned int idx) { + return (idx < MAXTEX) ? mTextures + idx : NULL; + } + Image * getImage (unsigned int idx) { + return (idx < MAXTEX && mMaterial) ? mMaterial->img[idx] : NULL; + } // for ipos void UpdateIPO( @@ -85,24 +95,32 @@ public: // -------------------------------- // pre calculate to avoid pops/lag at startup virtual void OnConstruction( ); + + static void EndFrame(); + private: - BL_Material* mMaterial; - BL_Shader* mShader; + BL_Material* mMaterial; + BL_Shader* mShader; + BL_BlenderShader* mBlenderShader; KX_Scene* mScene; BL_Texture mTextures[MAXTEX]; // texture array bool mUserDefBlend; unsigned int mBlendFunc[2]; bool mModified; + bool mConstructed; // if false, don't clean on exit + + void SetBlenderGLSLShader(); void ActivatGLMaterials( RAS_IRasterizer* rasty )const; void ActivateTexGen( RAS_IRasterizer *ras ) const; + bool UsesLighting(RAS_IRasterizer *rasty) const; // message centers void setTexData( bool enable,RAS_IRasterizer *ras); + void setBlenderShaderData( bool enable, RAS_IRasterizer *ras); void setShaderData( bool enable, RAS_IRasterizer *ras); - bool setDefaultBlending(); void setObjectMatrixData(int i, RAS_IRasterizer *ras); void setTexMatrixData(int i); @@ -111,6 +129,10 @@ private: // cleanup stuff void OnExit(); + // shader chacing + static BL_BlenderShader *mLastBlenderShader; + static BL_Shader *mLastShader; + mutable int mPass; }; diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp index aa5d1f1cec1..bf838e60210 100644 --- a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp +++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp @@ -13,18 +13,32 @@ #include "KX_ClientObjectInfo.h" #include "PHY_IPhysicsEnvironment.h" +#include "CcdPhysicsEnvironment.h" +#include "BulletSoftBody/btSoftBody.h" KX_BulletPhysicsController::KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna) : KX_IPhysicsController(dyna,(PHY_IPhysicsController*)this), -CcdPhysicsController(ci) +CcdPhysicsController(ci), +m_savedCollisionFlags(0) { } KX_BulletPhysicsController::~KX_BulletPhysicsController () { - + // The game object has a direct link to + if (m_pObject) + { + // If we cheat in SetObject, we must also cheat here otherwise the + // object will still things it has a physical controller + // Note that it requires that m_pObject is reset in case the object is deleted + // before the controller (usual case, see KX_Scene::RemoveNodeDestructObjec) + // The non usual case is when the object is not deleted because its reference is hanging + // in a AddObject actuator but the node is deleted. This case is covered here. + KX_GameObject* gameobj = (KX_GameObject*) m_pObject->GetSGClientObject(); + gameobj->SetPhysicsController(NULL,false); + } } void KX_BulletPhysicsController::resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) @@ -58,6 +72,7 @@ void KX_BulletPhysicsController::SetObject (SG_IObject* object) } + void KX_BulletPhysicsController::setMargin (float collisionMargin) { CcdPhysicsController::SetMargin(collisionMargin); @@ -90,10 +105,17 @@ MT_Vector3 KX_BulletPhysicsController::GetLinearVelocity() CcdPhysicsController::GetLinearVelocity(angVel[0],angVel[1],angVel[2]);//rcruiz return MT_Vector3(angVel[0],angVel[1],angVel[2]); } +MT_Vector3 KX_BulletPhysicsController::GetAngularVelocity() +{ + float angVel[3]; + //CcdPhysicsController::GetAngularVelocity(angVel[0],angVel[1],angVel[2]); + CcdPhysicsController::GetAngularVelocity(angVel[0],angVel[1],angVel[2]);//rcruiz + return MT_Vector3(angVel[0],angVel[1],angVel[2]); +} 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]); } @@ -112,9 +134,10 @@ void KX_BulletPhysicsController::getOrientation(MT_Quaternion& orn) CcdPhysicsController::getOrientation(myorn[0],myorn[1],myorn[2],myorn[3]); orn = MT_Quaternion(myorn[0],myorn[1],myorn[2],myorn[3]); } -void KX_BulletPhysicsController::setOrientation(const MT_Quaternion& orn) +void KX_BulletPhysicsController::setOrientation(const MT_Matrix3x3& orn) { - CcdPhysicsController::setOrientation(orn.x(),orn.y(),orn.z(),orn.w()); + btMatrix3x3 btmat(orn[0][0], orn[0][1], orn[0][2], orn[1][0], orn[1][1], orn[1][2], orn[2][0], orn[2][1], orn[2][2]); + CcdPhysicsController::setWorldOrientation(btmat); } void KX_BulletPhysicsController::setPosition(const MT_Point3& pos) { @@ -126,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); @@ -142,14 +175,37 @@ void KX_BulletPhysicsController::setRigidBody(bool rigid) { } -void KX_BulletPhysicsController::SuspendDynamics() +void KX_BulletPhysicsController::SuspendDynamics(bool ghost) { - GetRigidBody()->setActivationState(DISABLE_SIMULATION); - + btRigidBody *body = GetRigidBody(); + if (body && body->getActivationState() != DISABLE_SIMULATION) + { + btBroadphaseProxy* handle = body->getBroadphaseHandle(); + m_savedCollisionFlags = body->getCollisionFlags(); + m_savedMass = GetMass(); + m_savedCollisionFilterGroup = handle->m_collisionFilterGroup; + m_savedCollisionFilterMask = handle->m_collisionFilterMask; + body->setActivationState(DISABLE_SIMULATION); + GetPhysicsEnvironment()->updateCcdPhysicsController(this, + 0.0, + btCollisionObject::CF_STATIC_OBJECT|((ghost)?btCollisionObject::CF_NO_CONTACT_RESPONSE:(m_savedCollisionFlags&btCollisionObject::CF_NO_CONTACT_RESPONSE)), + btBroadphaseProxy::StaticFilter, + btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter); + } } + void KX_BulletPhysicsController::RestoreDynamics() { - GetRigidBody()->forceActivationState(ACTIVE_TAG); + btRigidBody *body = GetRigidBody(); + if (body && body->getActivationState() == DISABLE_SIMULATION) + { + GetPhysicsEnvironment()->updateCcdPhysicsController(this, + m_savedMass, + m_savedCollisionFlags, + m_savedCollisionFilterGroup, + m_savedCollisionFilterMask); + GetRigidBody()->forceActivationState(ACTIVE_TAG); + } } SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode) @@ -161,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()) { @@ -180,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; @@ -196,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 619ac42503f..cdcb82c87ca 100644 --- a/source/gameengine/Ketsji/KX_BulletPhysicsController.h +++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.h @@ -7,6 +7,11 @@ class KX_BulletPhysicsController : public KX_IPhysicsController ,public CcdPhysicsController { +private: + int m_savedCollisionFlags; + short int m_savedCollisionFilterGroup; + short int m_savedCollisionFilterMask; + MT_Scalar m_savedMass; public: @@ -25,11 +30,12 @@ public: virtual void ApplyTorque(const MT_Vector3& torque,bool local); virtual void ApplyForce(const MT_Vector3& force,bool local); virtual MT_Vector3 GetLinearVelocity(); + virtual MT_Vector3 GetAngularVelocity(); virtual MT_Vector3 GetVelocity(const MT_Point3& pos); virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local); virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local); virtual void getOrientation(MT_Quaternion& orn); - virtual void setOrientation(const MT_Quaternion& orn); + virtual void setOrientation(const MT_Matrix3x3& orn); virtual void setPosition(const MT_Point3& pos); virtual void setScaling(const MT_Vector3& scaling); virtual MT_Scalar GetMass(); @@ -38,14 +44,12 @@ public: virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ); - virtual void SuspendDynamics(); + virtual void SuspendDynamics(bool ghost); virtual void RestoreDynamics(); 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_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp index 86dbd06871f..53b3e348a36 100644 --- a/source/gameengine/Ketsji/KX_Camera.cpp +++ b/source/gameengine/Ketsji/KX_Camera.cpp @@ -29,7 +29,8 @@ */ #include "KX_Camera.h" - +#include "KX_Scene.h" +#include "KX_PythonInit.h" #include "KX_Python.h" #include "KX_PyMath.h" #ifdef HAVE_CONFIG_H @@ -54,7 +55,9 @@ KX_Camera::KX_Camera(void* sgReplicationInfo, m_name = "cam"; m_projection_matrix.setIdentity(); m_modelview_matrix.setIdentity(); - SetProperty("camera",new CIntValue(1)); + CValue* val = new CIntValue(1); + SetProperty("camera",val); + val->Release(); } @@ -63,7 +66,22 @@ KX_Camera::~KX_Camera() } +CValue* KX_Camera::GetReplica() +{ + KX_Camera* replica = new KX_Camera(*this); + + // this will copy properties and so on... + CValue::AddDataToReplica(replica); + ProcessReplica(replica); + + return replica; +} +void KX_Camera::ProcessReplica(KX_Camera* replica) +{ + KX_GameObject::ProcessReplica(replica); +} + MT_Transform KX_Camera::GetWorldToCamera() const { MT_Transform camtrans; @@ -186,6 +204,11 @@ float KX_Camera::GetCameraFar() const return m_camdata.m_clipend; } +float KX_Camera::GetFocalLength() const +{ + return m_camdata.m_focallength; +} + RAS_CameraData* KX_Camera::GetCameraData() @@ -388,6 +411,7 @@ PyMethodDef KX_Camera::Methods[] = { KX_PYMETHODTABLE(KX_Camera, setProjectionMatrix), KX_PYMETHODTABLE(KX_Camera, enableViewport), KX_PYMETHODTABLE(KX_Camera, setViewport), + KX_PYMETHODTABLE(KX_Camera, setOnTop), {NULL,NULL} //Sentinel }; @@ -564,7 +588,7 @@ KX_PYMETHODDEF_DOC(KX_Camera, sphereInsideFrustum, PyErr_SetString(PyExc_TypeError, "sphereInsideFrustum: Expected arguments: (center, radius)"); - Py_Return; + return NULL; } KX_PYMETHODDEF_DOC(KX_Camera, boxInsideFrustum, @@ -742,6 +766,10 @@ KX_PYMETHODDEF_DOC(KX_Camera, enableViewport, else EnableViewport(false); } + else { + return NULL; + } + Py_Return; } @@ -753,6 +781,20 @@ KX_PYMETHODDEF_DOC(KX_Camera, setViewport, if (PyArg_ParseTuple(args,"iiii",&left, &bottom, &right, &top)) { SetViewport(left, bottom, right, top); + } else { + return NULL; } Py_Return; } + +KX_PYMETHODDEF_DOC(KX_Camera, setOnTop, +"setOnTop()\n" +"Sets this camera's viewport on top\n") +{ + class KX_Scene* scene; + + scene = KX_GetActiveScene(); + MT_assert(scene); + scene->SetCameraOnTop(this); + Py_Return; +} diff --git a/source/gameengine/Ketsji/KX_Camera.h b/source/gameengine/Ketsji/KX_Camera.h index a276397c9c3..75d574cd697 100644 --- a/source/gameengine/Ketsji/KX_Camera.h +++ b/source/gameengine/Ketsji/KX_Camera.h @@ -131,6 +131,24 @@ public: KX_Camera(void* sgReplicationInfo,SG_Callbacks callbacks,const RAS_CameraData& camdata, bool frustum_culling = true, PyTypeObject *T = &Type); virtual ~KX_Camera(); + /** + * Inherited from CValue -- return a new copy of this + * instance allocated on the heap. Ownership of the new + * object belongs with the caller. + */ + virtual CValue* + GetReplica( + ); + + /** + * Inherited from CValue -- Makes sure any internal + * data owned by this class is deep copied. Called internally + */ + virtual void + ProcessReplica( + KX_Camera* replica + ); + MT_Transform GetWorldToCamera() const; MT_Transform GetCameraToWorld() const; @@ -166,12 +184,14 @@ public: */ const MT_Matrix4x4& GetModelviewMatrix() const; - /** Gets the focal length. */ + /** Gets the aperture. */ float GetLens() const; /** Gets the near clip distance. */ float GetCameraNear() const; /** Gets the far clip distance. */ float GetCameraFar() const; + /** Gets the focal length (only used for stereo rendering) */ + float GetFocalLength() const; /** Gets all camera data. */ RAS_CameraData* GetCameraData(); @@ -248,6 +268,7 @@ public: KX_PYMETHOD_DOC(KX_Camera, enableViewport); KX_PYMETHOD_DOC(KX_Camera, setViewport); + KX_PYMETHOD_DOC(KX_Camera, setOnTop); virtual PyObject* _getattr(const STR_String& attr); /* lens, near, far, projection_matrix */ virtual int _setattr(const STR_String& attr, PyObject *pyvalue); diff --git a/source/gameengine/Ketsji/KX_CameraActuator.cpp b/source/gameengine/Ketsji/KX_CameraActuator.cpp index cb3180cb05e..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"; @@ -49,7 +51,7 @@ STR_String KX_CameraActuator::Y_AXIS_STRING = "y"; KX_CameraActuator::KX_CameraActuator( SCA_IObject* gameobj, - CValue *obj, + SCA_IObject *obj, MT_Scalar hght, MT_Scalar minhght, MT_Scalar maxhght, @@ -63,11 +65,14 @@ KX_CameraActuator::KX_CameraActuator( m_maxHeight (maxhght), m_x (xytog) { + if (m_ob) + m_ob->RegisterActuator(this); } KX_CameraActuator::~KX_CameraActuator() { - //nothing to do + if (m_ob) + m_ob->UnregisterActuator(this); } CValue* @@ -81,8 +86,35 @@ GetReplica( return replica; }; +void KX_CameraActuator::ProcessReplica() +{ + if (m_ob) + m_ob->RegisterActuator(this); + SCA_IActuator::ProcessReplica(); +} + +bool KX_CameraActuator::UnlinkObject(SCA_IObject* clientobj) +{ + if (clientobj == m_ob) + { + // this object is being deleted, we cannot continue to track it. + m_ob = NULL; + return true; + } + return false; +} +void KX_CameraActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + void **h_obj = (*obj_map)[m_ob]; + if (h_obj) { + if (m_ob) + m_ob->UnregisterActuator(this); + m_ob = (SCA_IObject*)(*h_obj); + m_ob->RegisterActuator(this); + } +} /* three functions copied from blender arith... don't know if there's an equivalent */ @@ -155,14 +187,25 @@ static void Kx_VecUpMat3(float *vec, float mat[][3], short axis) mat[coz][0]= vec[0]; mat[coz][1]= vec[1]; mat[coz][2]= vec[2]; - Kx_Normalize((float *)mat[coz]); + if (Kx_Normalize((float *)mat[coz]) == 0.f) { + /* this is a very abnormal situation: the camera has reach the object center exactly + We will choose a completely arbitrary direction */ + mat[coz][0] = 1.0f; + mat[coz][1] = 0.0f; + mat[coz][2] = 0.0f; + } inp= mat[coz][2]; mat[coy][0]= - inp*mat[coz][0]; mat[coy][1]= - inp*mat[coz][1]; mat[coy][2]= 1.0 - inp*mat[coz][2]; - Kx_Normalize((float *)mat[coy]); + if (Kx_Normalize((float *)mat[coy]) == 0.f) { + /* the camera is vertical, chose the y axis arbitrary */ + mat[coy][0] = 0.f; + mat[coy][1] = 1.f; + mat[coy][2] = 0.f; + } Kx_Crossf(mat[cox], mat[coy], mat[coz]); @@ -170,8 +213,14 @@ static void Kx_VecUpMat3(float *vec, float mat[][3], short axis) bool KX_CameraActuator::Update(double curtime, bool frame) { - bool result = true; + /* wondering... is it really neccesary/desirable to suppress negative */ + /* events here? */ + bool bNegativeEvent = IsNegativeEvent(); + RemoveAllEvents(); + if (bNegativeEvent || !m_ob) + return false; + KX_GameObject *obj = (KX_GameObject*) GetParent(); MT_Point3 from = obj->NodeGetWorldPosition(); MT_Matrix3x3 frommat = obj->NodeGetWorldOrientation(); @@ -184,13 +233,6 @@ bool KX_CameraActuator::Update(double curtime, bool frame) float mindistsq, maxdistsq, distsq; float mat[3][3]; - /* wondering... is it really neccesary/desirable to suppress negative */ - /* events here? */ - bool bNegativeEvent = IsNegativeEvent(); - RemoveAllEvents(); - - if (bNegativeEvent) return false; - /* The rules: */ /* CONSTRAINT 1: not implemented */ /* CONSTRAINT 2: can camera see actor? */ @@ -304,7 +346,7 @@ bool KX_CameraActuator::Update(double curtime, bool frame) actormat[2][0]= mat[0][2]; actormat[2][1]= mat[1][2]; actormat[2][2]= mat[2][2]; obj->NodeSetLocalOrientation(actormat); - return result; + return true; } CValue *KX_CameraActuator::findObject(char *obName) @@ -355,16 +397,16 @@ PyParentObject KX_CameraActuator::Parents[] = { }; PyMethodDef KX_CameraActuator::Methods[] = { - {"setObject",(PyCFunction) KX_CameraActuator::sPySetObject, METH_VARARGS, SetObject_doc}, - {"getObject",(PyCFunction) KX_CameraActuator::sPyGetObject, METH_NOARGS, 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 }; @@ -372,48 +414,48 @@ PyObject* KX_CameraActuator::_getattr(const STR_String& attr) { _getattr_up(SCA_IActuator); } /* get obj ---------------------------------------------------------- */ -char KX_CameraActuator::GetObject_doc[] = -"getObject\n" +const char KX_CameraActuator::GetObject_doc[] = +"getObject(name_only = 1)\n" +"name_only - optional arg, when true will return the KX_GameObject rather then its name\n" "\tReturns the object this sensor reacts to.\n"; -PyObject* KX_CameraActuator::PyGetObject(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_CameraActuator::PyGetObject(PyObject* self, PyObject* args) { - return PyString_FromString(m_ob->GetName()); + int ret_name_only = 1; + if (!PyArg_ParseTuple(args, "|i", &ret_name_only)) + return NULL; + + if (!m_ob) + Py_RETURN_NONE; + + if (ret_name_only) + return PyString_FromString(m_ob->GetName()); + else + return m_ob->AddRef(); } /* set obj ---------------------------------------------------------- */ -char KX_CameraActuator::SetObject_doc[] = -"setObject\n" +const char KX_CameraActuator::SetObject_doc[] = +"setObject(object)\n" +"\t- object: KX_GameObject, string or None\n" "\tSets the object this sensor reacts to.\n"; -PyObject* KX_CameraActuator::PySetObject(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_CameraActuator::PySetObject(PyObject* self, PyObject* value) { - - PyObject* gameobj; - if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj)) - { - m_ob = (CValue*)gameobj; - Py_Return; - } - PyErr_Clear(); + KX_GameObject *gameobj; - char* objectname; - if (PyArg_ParseTuple(args, "s", &objectname)) - { - CValue *object = (CValue*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname)); - if(object) - { - m_ob = object; - Py_Return; - } - } + if (!ConvertPythonToGameObject(value, &gameobj, true)) + return NULL; // ConvertPythonToGameObject sets the error - return NULL; + if (m_ob != NULL) + m_ob->UnregisterActuator(this); + + m_ob = (SCA_IObject*)gameobj; + if (m_ob) + m_ob->RegisterActuator(this); + + Py_RETURN_NONE; } /* 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, @@ -423,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, @@ -439,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, @@ -449,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, @@ -465,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, @@ -475,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, @@ -491,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"; @@ -509,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_CameraActuator.h b/source/gameengine/Ketsji/KX_CameraActuator.h index eb007e403ec..d53d12b3b82 100644 --- a/source/gameengine/Ketsji/KX_CameraActuator.h +++ b/source/gameengine/Ketsji/KX_CameraActuator.h @@ -49,7 +49,7 @@ class KX_CameraActuator : public SCA_IActuator Py_Header; private : /** Object that will be tracked. */ - CValue *m_ob; + SCA_IObject *m_ob; /** height (float), */ //const MT_Scalar m_height; @@ -87,7 +87,7 @@ private : SCA_IObject *gameobj, //const CValue *ob, - CValue *ob, + SCA_IObject *ob, MT_Scalar hght, MT_Scalar minhght, MT_Scalar maxhght, @@ -103,6 +103,7 @@ private : /** Methods Inherited from CValue */ CValue* GetReplica(); + virtual void ProcessReplica(); /** Methods inherited from SCA_IActuator */ @@ -110,7 +111,10 @@ private : double curtime, bool frame ); + virtual bool UnlinkObject(SCA_IObject* clientobj); + /** Methods inherited from SCA_ILogicBrick */ + virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map); /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ @@ -119,9 +123,9 @@ private : virtual PyObject* _getattr(const STR_String& attr); /* set object to look at */ - KX_PYMETHOD_DOC(KX_CameraActuator,SetObject); + KX_PYMETHOD_DOC_O(KX_CameraActuator,SetObject); /* get current object */ - KX_PYMETHOD_DOC(KX_CameraActuator,GetObject); + KX_PYMETHOD_DOC_VARARGS(KX_CameraActuator,GetObject); KX_PYMETHOD_DOC(KX_CameraActuator,SetMin); KX_PYMETHOD_DOC(KX_CameraActuator,GetMin); KX_PYMETHOD_DOC(KX_CameraActuator,SetMax); diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp index bd843d97199..76357e9c58f 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp @@ -35,6 +35,7 @@ #include "MT_Point3.h" #include "MT_Matrix3x3.h" #include "KX_GameObject.h" +#include "KX_RayCast.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -45,35 +46,60 @@ /* ------------------------------------------------------------------------- */ KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj, - int dampTime, + int posDampTime, + int rotDampTime, float minBound, float maxBound, + float refDir[3], int locrotxyz, - PyTypeObject* T) - : SCA_IActuator(gameobj, T) + int time, + int option, + char *property, + PyTypeObject* T) : + m_refDirection(refDir), + m_currentTime(0), + SCA_IActuator(gameobj, T) { - m_dampTime = dampTime; + m_posDampTime = posDampTime; + m_rotDampTime = rotDampTime; m_locrot = locrotxyz; + m_option = option; + m_activeTime = time; + if (property) { + strncpy(m_property, property, sizeof(m_property)); + m_property[sizeof(m_property)-1] = 0; + } else { + m_property[0] = 0; + } /* The units of bounds are determined by the type of constraint. To */ /* make the constraint application easier and more transparent later on, */ /* I think converting the bounds to the applicable domain makes more */ /* sense. */ switch (m_locrot) { - case KX_ACT_CONSTRAINT_LOCX: - case KX_ACT_CONSTRAINT_LOCY: - case KX_ACT_CONSTRAINT_LOCZ: + case KX_ACT_CONSTRAINT_ORIX: + case KX_ACT_CONSTRAINT_ORIY: + case KX_ACT_CONSTRAINT_ORIZ: + { + MT_Scalar len = m_refDirection.length(); + if (MT_fuzzyZero(len)) { + // missing a valid direction + std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no valid reference direction!" << std::endl; + m_locrot = KX_ACT_CONSTRAINT_NODEF; + } else { + m_refDirection /= len; + } + m_minimumBound = cos(minBound); + m_maximumBound = cos(maxBound); + m_minimumSine = sin(minBound); + m_maximumSine = sin(maxBound); + } + break; + default: m_minimumBound = minBound; m_maximumBound = maxBound; + m_minimumSine = 0.f; + m_maximumSine = 0.f; break; - case KX_ACT_CONSTRAINT_ROTX: - case KX_ACT_CONSTRAINT_ROTY: - case KX_ACT_CONSTRAINT_ROTZ: - /* The user interface asks for degrees, we are radian. */ - m_minimumBound = MT_radians(minBound); - m_maximumBound = MT_radians(maxBound); - break; - default: - ; /* error */ } } /* End of constructor */ @@ -83,77 +109,426 @@ KX_ConstraintActuator::~KX_ConstraintActuator() // there's nothing to be done here, really.... } /* end of destructor */ -bool KX_ConstraintActuator::Update(double curtime, bool frame) +bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { - bool result = false; - bool bNegativeEvent = IsNegativeEvent(); - RemoveAllEvents(); - - if (bNegativeEvent) - return false; // do nothing on negative events - - /* Constraint clamps the values to the specified range, with a sort of */ - /* low-pass filtered time response, if the damp time is unequal to 0. */ - - /* Having to retrieve location/rotation and setting it afterwards may not */ - /* be efficient enough... Somthing to look at later. */ - KX_GameObject *parent = (KX_GameObject*) GetParent(); - MT_Point3 position = parent->NodeGetWorldPosition(); - MT_Matrix3x3 rotation = parent->NodeGetWorldOrientation(); -// MT_Vector3 eulerrot = rotation.getEuler(); - - switch (m_locrot) { - case KX_ACT_CONSTRAINT_LOCX: - Clamp(position[0], m_minimumBound, m_maximumBound); - result = true; - break; - case KX_ACT_CONSTRAINT_LOCY: - Clamp(position[1], m_minimumBound, m_maximumBound); - result = true; - break; - case KX_ACT_CONSTRAINT_LOCZ: - Clamp(position[2], m_minimumBound, m_maximumBound); - result = true; - break; + m_hitObject = client->m_gameobject; -// case KX_ACT_CONSTRAINT_ROTX: -// /* The angles are Euler angles (I think that's what they are called) */ -// /* but we need to convert from/to the MT_Matrix3x3. */ -// Clamp(eulerrot[0], m_minimumBound, m_maximumBound); -// break; -// case KX_ACT_CONSTRAINT_ROTY: -// Clamp(eulerrot[1], m_minimumBound, m_maximumBound); -// break; -// case KX_ACT_CONSTRAINT_ROTZ: -// Clamp(eulerrot[2], m_minimumBound, m_maximumBound); -// break; -// default: -// ; /* error */ - } + bool bFound = false; - /* Will be replaced by a filtered clamp. */ - + if (m_property[0] == 0) + { + bFound = true; + } + else + { + if (m_option & KX_ACT_CONSTRAINT_MATERIAL) + { + if (client->m_auxilary_info) + { + bFound = !strcmp(m_property, ((char*)client->m_auxilary_info)); + } + } + else + { + bFound = m_hitObject->GetProperty(m_property) != NULL; + } + } + // update the hit status + result->m_hitFound = bFound; + // stop looking + return true; +} - switch (m_locrot) { - case KX_ACT_CONSTRAINT_LOCX: - case KX_ACT_CONSTRAINT_LOCY: - case KX_ACT_CONSTRAINT_LOCZ: - parent->NodeSetLocalPosition(position); - break; +/* 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) +{ -// case KX_ACT_CONSTRAINT_ROTX: -// case KX_ACT_CONSTRAINT_ROTY: -// case KX_ACT_CONSTRAINT_ROTZ: -// rotation.setEuler(eulerrot); -// parent->NodeSetLocalOrientation(rotation); - break; + bool result = false; + bool bNegativeEvent = IsNegativeEvent(); + RemoveAllEvents(); - default: - ; /* error */ + if (!bNegativeEvent) { + /* Constraint clamps the values to the specified range, with a sort of */ + /* low-pass filtered time response, if the damp time is unequal to 0. */ + + /* Having to retrieve location/rotation and setting it afterwards may not */ + /* be efficient enough... Somthing to look at later. */ + KX_GameObject *obj = (KX_GameObject*) GetParent(); + MT_Point3 position = obj->NodeGetWorldPosition(); + MT_Point3 newposition; + 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: + case KX_ACT_CONSTRAINT_ORIY: + case KX_ACT_CONSTRAINT_ORIZ: + switch (m_locrot) { + case KX_ACT_CONSTRAINT_ORIX: + direction[0] = rotation[0][0]; + direction[1] = rotation[1][0]; + direction[2] = rotation[2][0]; + axis = 0; + break; + case KX_ACT_CONSTRAINT_ORIY: + direction[0] = rotation[0][1]; + direction[1] = rotation[1][1]; + direction[2] = rotation[2][1]; + axis = 1; + break; + default: + direction[0] = rotation[0][2]; + direction[1] = rotation[1][2]; + direction[2] = rotation[2][2]; + axis = 2; + break; + } + if ((m_maximumBound < (1.0f-FLT_EPSILON)) || (m_minimumBound < (1.0f-FLT_EPSILON))) { + // reference direction needs to be evaluated + // 1. get the cosine between current direction and target + cosangle = direction.dot(m_refDirection); + if (cosangle >= (m_maximumBound-FLT_EPSILON) && cosangle <= (m_minimumBound+FLT_EPSILON)) { + // no change to do + result = true; + goto CHECK_TIME; + } + // 2. define a new reference direction + // compute local axis with reference direction as X and + // Y in direction X refDirection plane + MT_Vector3 zaxis = m_refDirection.cross(direction); + if (MT_fuzzyZero2(zaxis.length2())) { + // direction and refDirection are identical, + // choose any other direction to define plane + if (direction[0] < 0.9999) + zaxis = m_refDirection.cross(MT_Vector3(1.0,0.0,0.0)); + else + zaxis = m_refDirection.cross(MT_Vector3(0.0,1.0,0.0)); + } + MT_Vector3 yaxis = zaxis.cross(m_refDirection); + yaxis.normalize(); + if (cosangle > m_minimumBound) { + // angle is too close to reference direction, + // choose a new reference that is exactly at minimum angle + refDirection = m_minimumBound * m_refDirection + m_minimumSine * yaxis; + } else { + // angle is too large, choose new reference direction at maximum angle + refDirection = m_maximumBound * m_refDirection + m_maximumSine * yaxis; + } + } else { + refDirection = m_refDirection; + } + // apply damping on the direction + direction = filter*direction + (1.0-filter)*refDirection; + obj->AlignAxisToVect(direction, axis); + result = true; + goto CHECK_TIME; + case KX_ACT_CONSTRAINT_DIRPX: + case KX_ACT_CONSTRAINT_DIRPY: + case KX_ACT_CONSTRAINT_DIRPZ: + case KX_ACT_CONSTRAINT_DIRNX: + case KX_ACT_CONSTRAINT_DIRNY: + case KX_ACT_CONSTRAINT_DIRNZ: + switch (m_locrot) { + case KX_ACT_CONSTRAINT_DIRPX: + normal[0] = rotation[0][0]; + normal[1] = rotation[1][0]; + normal[2] = rotation[2][0]; + axis = 0; // axis according to KX_GameObject::AlignAxisToVect() + sign = 0; // X axis will be parrallel to direction of ray + break; + case KX_ACT_CONSTRAINT_DIRPY: + normal[0] = rotation[0][1]; + normal[1] = rotation[1][1]; + normal[2] = rotation[2][1]; + axis = 1; + sign = 0; + break; + case KX_ACT_CONSTRAINT_DIRPZ: + normal[0] = rotation[0][2]; + normal[1] = rotation[1][2]; + normal[2] = rotation[2][2]; + axis = 2; + sign = 0; + break; + case KX_ACT_CONSTRAINT_DIRNX: + normal[0] = -rotation[0][0]; + normal[1] = -rotation[1][0]; + normal[2] = -rotation[2][0]; + axis = 0; + sign = 1; + break; + case KX_ACT_CONSTRAINT_DIRNY: + normal[0] = -rotation[0][1]; + normal[1] = -rotation[1][1]; + normal[2] = -rotation[2][1]; + axis = 1; + sign = 1; + break; + case KX_ACT_CONSTRAINT_DIRNZ: + normal[0] = -rotation[0][2]; + normal[1] = -rotation[1][2]; + normal[2] = -rotation[2][2]; + axis = 2; + sign = 1; + break; + } + 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; + 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) { + // the object is not physical, we probably want to avoid hitting its own parent + KX_GameObject *parent = obj->GetParent(); + if (parent) { + spc = parent->GetPhysicsController(); + parent->Release(); + } + } + 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 + // (works like a sensor) + goto CHECK_TIME; + } + if (m_option & KX_ACT_CONSTRAINT_NORMAL) { + MT_Scalar rotFilter; + // apply damping on the direction + if (m_rotDampTime) { + 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(); + } + } + if (m_option & KX_ACT_CONSTRAINT_DISTANCE) { + if (m_posDampTime) { + 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-callback.m_hitPoint).length(); + } + newposition = callback.m_hitPoint-newdistance*direction; + } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) { + // no contact but still keep running + result = true; + goto CHECK_TIME; + } + } + 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 = obj->GetSGNode()->GetLocalPosition(); + switch (m_locrot) { + case KX_ACT_CONSTRAINT_LOCX: + Clamp(newposition[0], m_minimumBound, m_maximumBound); + break; + case KX_ACT_CONSTRAINT_LOCY: + Clamp(newposition[1], m_minimumBound, m_maximumBound); + break; + case KX_ACT_CONSTRAINT_LOCZ: + Clamp(newposition[2], m_minimumBound, m_maximumBound); + break; + } + result = true; + if (m_posDampTime) { + newposition = filter*position + (1.0-filter)*newposition; + } + obj->NodeSetLocalPosition(newposition); + goto CHECK_TIME; + } + if (result) { + // set the new position but take into account parent if any + obj->NodeSetWorldPosition(newposition); + } + CHECK_TIME: + if (result && m_activeTime > 0 ) { + if (++m_currentTime >= m_activeTime) + result = false; + } + } + if (!result) { + m_currentTime = 0; } - return result; } /* end of KX_ConstraintActuator::Update(double curtime,double deltatime) */ @@ -212,14 +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_VARARGS, GetDamp_doc}, - {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetMin_doc}, - {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_VARARGS, GetMin_doc}, - {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetMax_doc}, - {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_VARARGS, GetMax_doc}, - {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, SetLimit_doc}, - {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_VARARGS, 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 }; @@ -228,10 +617,10 @@ 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 with which the constraint application is delayed.\n" +"\tSets the time constant of the orientation and distance constraint.\n" "\tIf the duration is negative, it is set to 0.\n"; PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self, PyObject* args, @@ -241,23 +630,182 @@ PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self, return NULL; } - m_dampTime = dampArg; - if (m_dampTime < 0) m_dampTime = 0; + m_posDampTime = dampArg; + if (m_posDampTime < 0) m_posDampTime = 0; Py_Return; } /* 3. getDamp */ -char KX_ConstraintActuator::GetDamp_doc[] = -"GetDamp()\n" +const char KX_ConstraintActuator::GetDamp_doc[] = +"getDamp()\n" +"\tReturns the damping parameter.\n"; +PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self){ + return PyInt_FromLong(m_posDampTime); +} + +/* 2. setRotDamp */ +const char KX_ConstraintActuator::SetRotDamp_doc[] = +"setRotDamp(duration)\n" +"\t- duration: integer\n" +"\tSets the time constant of the orientation constraint.\n" +"\tIf the duration is negative, it is set to 0.\n"; +PyObject* KX_ConstraintActuator::PySetRotDamp(PyObject* self, + PyObject* args, + PyObject* kwds) { + int dampArg; + if(!PyArg_ParseTuple(args, "i", &dampArg)) { + return NULL; + } + + m_rotDampTime = dampArg; + if (m_rotDampTime < 0) m_rotDampTime = 0; + + Py_Return; +} +/* 3. getRotDamp */ +const char KX_ConstraintActuator::GetRotDamp_doc[] = +"getRotDamp()\n" "\tReturns the damping time for application of the constraint.\n"; -PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self, +PyObject* KX_ConstraintActuator::PyGetRotDamp(PyObject* self){ + return PyInt_FromLong(m_rotDampTime); +} + +/* 2. setDirection */ +const char KX_ConstraintActuator::SetDirection_doc[] = +"setDirection(vector)\n" +"\t- vector: 3-tuple\n" +"\tSets the reference direction in world coordinate for the orientation constraint.\n"; +PyObject* KX_ConstraintActuator::PySetDirection(PyObject* self, + PyObject* args, + PyObject* kwds) { + float x, y, z; + MT_Scalar len; + MT_Vector3 dir; + + if(!PyArg_ParseTuple(args, "(fff)", &x, &y, &z)) { + return NULL; + } + dir[0] = x; + dir[1] = y; + dir[2] = z; + len = dir.length(); + if (MT_fuzzyZero(len)) { + std::cout << "Invalid direction" << std::endl; + return NULL; + } + m_refDirection = dir/len; + + Py_Return; +} +/* 3. getDirection */ +const char KX_ConstraintActuator::GetDirection_doc[] = +"getDirection()\n" +"\tReturns the reference direction of the orientation constraint as a 3-tuple.\n"; +PyObject* KX_ConstraintActuator::PyGetDirection(PyObject* self){ + PyObject *retVal = PyList_New(3); + + PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_refDirection[0])); + PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_refDirection[1])); + PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_refDirection[2])); + return retVal; +} + +/* 2. setOption */ +const char KX_ConstraintActuator::SetOption_doc[] = +"setOption(option)\n" +"\t- option: integer\n" +"\tSets several options of the distance constraint.\n" +"\tBinary combination of the following values:\n" +"\t\t 64 : Activate alignment to surface\n" +"\t\t128 : Detect material rather than property\n" +"\t\t256 : No deactivation if ray does not hit target\n" +"\t\t512 : Activate distance control\n"; +PyObject* KX_ConstraintActuator::PySetOption(PyObject* self, + PyObject* args, + PyObject* kwds) { + int option; + if(!PyArg_ParseTuple(args, "i", &option)) { + return NULL; + } + + m_option = option; + + Py_Return; +} +/* 3. getOption */ +const char KX_ConstraintActuator::GetOption_doc[] = +"getOption()\n" +"\tReturns the option parameter.\n"; +PyObject* KX_ConstraintActuator::PyGetOption(PyObject* self){ + return PyInt_FromLong(m_option); +} + +/* 2. setTime */ +const char KX_ConstraintActuator::SetTime_doc[] = +"setTime(duration)\n" +"\t- duration: integer\n" +"\tSets the activation time of the actuator.\n" +"\tThe actuator disables itself after this many frame.\n" +"\tIf set to 0 or negative, the actuator is not limited in time.\n"; +PyObject* KX_ConstraintActuator::PySetTime(PyObject* self, PyObject* args, - PyObject* kwds){ - return PyInt_FromLong(m_dampTime); + PyObject* kwds) { + int t; + if(!PyArg_ParseTuple(args, "i", &t)) { + return NULL; + } + + if (t < 0) + t = 0; + m_activeTime = t; + + Py_Return; +} +/* 3. getTime */ +const char KX_ConstraintActuator::GetTime_doc[] = +"getTime()\n" +"\tReturns the time parameter.\n"; +PyObject* KX_ConstraintActuator::PyGetTime(PyObject* self){ + return PyInt_FromLong(m_activeTime); } +/* 2. setProperty */ +const char KX_ConstraintActuator::SetProperty_doc[] = +"setProperty(property)\n" +"\t- property: string\n" +"\tSets the name of the property or material for the ray detection of the distance constraint.\n" +"\tIf empty, the ray will detect any collisioning object.\n"; +PyObject* KX_ConstraintActuator::PySetProperty(PyObject* self, + PyObject* args, + PyObject* kwds) { + char *property; + if (!PyArg_ParseTuple(args, "s", &property)) { + return NULL; + } + if (property == NULL) { + m_property[0] = 0; + } else { + strncpy(m_property, property, sizeof(m_property)); + m_property[sizeof(m_property)-1] = 0; + } + + Py_Return; +} +/* 3. getProperty */ +const char KX_ConstraintActuator::GetProperty_doc[] = +"getProperty()\n" +"\tReturns the property parameter.\n"; +PyObject* KX_ConstraintActuator::PyGetProperty(PyObject* self){ + return PyString_FromString(m_property); +} + +/* 4. setDistance */ +const char KX_ConstraintActuator::SetDistance_doc[] = +"setDistance(distance)\n" +"\t- distance: float\n" +"\tSets the target distance in distance constraint\n"; /* 4. setMin */ -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" @@ -271,9 +819,7 @@ PyObject* KX_ConstraintActuator::PySetMin(PyObject* self, } switch (m_locrot) { - case KX_ACT_CONSTRAINT_LOCX: - case KX_ACT_CONSTRAINT_LOCY: - case KX_ACT_CONSTRAINT_LOCZ: + default: m_minimumBound = minArg; break; case KX_ACT_CONSTRAINT_ROTX: @@ -281,25 +827,30 @@ PyObject* KX_ConstraintActuator::PySetMin(PyObject* self, case KX_ACT_CONSTRAINT_ROTZ: m_minimumBound = MT_radians(minArg); break; - default: - ; /* error */ } Py_Return; } +/* 5. getDistance */ +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"; -PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self, - PyObject* args, - PyObject* kwds) { +PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self) { return PyFloat_FromDouble(m_minimumBound); } +/* 6. setRayLength */ +const char KX_ConstraintActuator::SetRayLength_doc[] = +"setRayLength(length)\n" +"\t- length: float\n" +"\tSets the maximum ray length of the distance constraint\n"; /* 6. setMax */ -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" @@ -313,9 +864,7 @@ PyObject* KX_ConstraintActuator::PySetMax(PyObject* self, } switch (m_locrot) { - case KX_ACT_CONSTRAINT_LOCX: - case KX_ACT_CONSTRAINT_LOCY: - case KX_ACT_CONSTRAINT_LOCZ: + default: m_maximumBound = maxArg; break; case KX_ACT_CONSTRAINT_ROTX: @@ -323,31 +872,41 @@ PyObject* KX_ConstraintActuator::PySetMax(PyObject* self, case KX_ACT_CONSTRAINT_ROTZ: m_maximumBound = MT_radians(maxArg); break; - default: - ; /* error */ } Py_Return; } +/* 7. getRayLength */ +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"; -PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self, - PyObject* args, - PyObject* kwds) { +PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self) { return PyFloat_FromDouble(m_maximumBound); } /* 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: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY,\n" -"\t KX_CONSTRAINTACT_LOCZ, KX_CONSTRAINTACT_ROTX,\n" -"\t KX_CONSTRAINTACT_ROTY, or KX_CONSTRAINTACT_ROTZ.\n" +"\t- type: integer\n" +"\t 1 : LocX\n" +"\t 2 : LocY\n" +"\t 3 : LocZ\n" +"\t 7 : Distance along +X axis\n" +"\t 8 : Distance along +Y axis\n" +"\t 9 : Distance along +Z axis\n" +"\t 10 : Distance along -X axis\n" +"\t 11 : Distance along -Y axis\n" +"\t 12 : Distance along -Z axis\n" +"\t 13 : Align X axis\n" +"\t 14 : Align Y axis\n" +"\t 15 : Align Z axis\n" "\tSets the type of constraint.\n"; PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self, PyObject* args, @@ -362,12 +921,10 @@ PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self, Py_Return; } /* 9. getLimit */ -char KX_ConstraintActuator::GetLimit_doc[] = -"getLimit(type)\n" +const char KX_ConstraintActuator::GetLimit_doc[] = +"getLimit()\n" "\tReturns the type of constraint.\n"; -PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self, - PyObject* args, - PyObject* kwds) { +PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self) { return PyInt_FromLong(m_locrot); } diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.h b/source/gameengine/Ketsji/KX_ConstraintActuator.h index a21a5f30de6..28b9b1e6a0b 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.h +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.h @@ -34,19 +34,40 @@ #include "SCA_IActuator.h" #include "MT_Scalar.h" +#include "MT_Vector3.h" +#include "KX_ClientObjectInfo.h" + +class KX_RayCast; +class KX_GameObject; class KX_ConstraintActuator : public SCA_IActuator { Py_Header; protected: // Damp time (int), - int m_dampTime; - // min (float), + int m_posDampTime; + int m_rotDampTime; + // min (float) float m_minimumBound; - // max (float), + // max (float) float m_maximumBound; + // sinus of minimum angle + float m_minimumSine; + // sinus of maximum angle + float m_maximumSine; + // reference direction + MT_Vector3 m_refDirection; // locrotxyz choice (pick one): only one choice allowed at a time! int m_locrot; + // active time of actuator + int m_activeTime; + int m_currentTime; + // option + 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 @@ -56,6 +77,7 @@ protected: public: + // m_locrot enum KX_CONSTRAINTTYPE { KX_ACT_CONSTRAINT_NODEF = 0, KX_ACT_CONSTRAINT_LOCX, @@ -64,16 +86,46 @@ protected: KX_ACT_CONSTRAINT_ROTX, KX_ACT_CONSTRAINT_ROTY, KX_ACT_CONSTRAINT_ROTZ, + KX_ACT_CONSTRAINT_DIRPX, + KX_ACT_CONSTRAINT_DIRPY, + KX_ACT_CONSTRAINT_DIRPZ, + KX_ACT_CONSTRAINT_DIRNX, + KX_ACT_CONSTRAINT_DIRNY, + KX_ACT_CONSTRAINT_DIRNZ, + 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 + enum KX_CONSTRAINTOPT { + KX_ACT_CONSTRAINT_NORMAL = 64, + KX_ACT_CONSTRAINT_MATERIAL = 128, + KX_ACT_CONSTRAINT_PERMANENT = 256, + 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, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo*); KX_ConstraintActuator(SCA_IObject* gameobj, - int damptime, + int posDamptime, + int rotDampTime, float min, float max, + float refDir[3], int locrot, + int time, + int option, + char *property, PyTypeObject* T=&Type); virtual ~KX_ConstraintActuator(); virtual CValue* GetReplica() { @@ -93,14 +145,27 @@ protected: virtual PyObject* _getattr(const STR_String& attr); KX_PYMETHOD_DOC(KX_ConstraintActuator,SetDamp); - KX_PYMETHOD_DOC(KX_ConstraintActuator,GetDamp); + KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetDamp); + KX_PYMETHOD_DOC(KX_ConstraintActuator,SetRotDamp); + KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetRotDamp); + KX_PYMETHOD_DOC(KX_ConstraintActuator,SetDirection); + KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetDirection); + KX_PYMETHOD_DOC(KX_ConstraintActuator,SetOption); + KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetOption); + KX_PYMETHOD_DOC(KX_ConstraintActuator,SetTime); + KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetTime); + KX_PYMETHOD_DOC(KX_ConstraintActuator,SetProperty); + KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetProperty); KX_PYMETHOD_DOC(KX_ConstraintActuator,SetMin); - KX_PYMETHOD_DOC(KX_ConstraintActuator,GetMin); + KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetMin); + static const char SetDistance_doc[]; + static const char GetDistance_doc[]; KX_PYMETHOD_DOC(KX_ConstraintActuator,SetMax); - KX_PYMETHOD_DOC(KX_ConstraintActuator,GetMax); + KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetMax); + static const char SetRayLength_doc[]; + static const char GetRayLength_doc[]; KX_PYMETHOD_DOC(KX_ConstraintActuator,SetLimit); - KX_PYMETHOD_DOC(KX_ConstraintActuator,GetLimit); - + KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetLimit); }; #endif //__KX_CONSTRAINTACTUATOR diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp index 987125ca9ba..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" @@ -53,8 +54,7 @@ PyObject* KX_ConstraintWrapper::PyTestMethod(PyObject* self, PyObject* kwds) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyObject* KX_ConstraintWrapper::PyGetConstraintId(PyObject* self, 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 26e0b47b84b..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,196 +667,107 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj, #endif //WIN32 -static GEN_Map<GEN_HashedPtr,btCollisionShape*> map_gamemesh_to_bulletshape; - -// 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; - - btCollisionShape** shapeptr = map_gamemesh_to_bulletshape[GEN_HashedPtr(meshobj)]; - - // Mesh has already been converted: reuse - if (shapeptr) - { - //return *shapeptr; - } - - // Mesh has no polygons! - int numpolys = meshobj->NumPolygons(); - if (!numpolys) - { - return NULL; - } - - // Count the number of collision polygons and check they all come from the same - // vertex array - int numvalidpolys = 0; - int vtxarray = -1; - RAS_IPolyMaterial *poly_material = NULL; - bool reinstance = true; - - for (int p=0; p<numpolys; p++) + + class KX_SoftBodyDeformer : public RAS_Deformer { - RAS_Polygon* poly = meshobj->GetPolygon(p); + class RAS_MeshObject* m_pMeshObject; + class KX_GameObject* m_gameobj; - // 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"); } - } - - // No collision polygons - if (numvalidpolys < 1) - return NULL; + virtual bool Apply(class RAS_IPolyMaterial *polymat) + { + KX_BulletPhysicsController* ctrl = (KX_BulletPhysicsController*) m_gameobj->GetPhysicsController(); + if (!ctrl) + return false; + btSoftBody* softBody= ctrl->GetSoftBody(); + if (!softBody) + return false; - if (polytope) - { - convexHullShape = new btConvexHullShape(&points[0].getX(),numPoints); - collisionMeshShape = convexHullShape; - } else - { - collisionMeshData = new btTriangleMesh(); -// concaveShape = new btTriangleMeshShape(collisionMeshData); - //collisionMeshShape = concaveShape; + //printf("apply\n"); + RAS_MeshSlot::iterator it; + RAS_MeshMaterial *mmat; + RAS_MeshSlot *slot; + size_t i; - } + // 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) - { - - //map_gamemesh_to_bulletshape.insert(GEN_HashedPtr(meshobj),collisionMeshShape); - if (!polytope) + } + } + return true; + } + virtual bool Update(void) { - bool useQuantization = true; - concaveShape = new btBvhTriangleMeshShape( collisionMeshData, useQuantization ); - //concaveShape = new btTriangleMeshShape( collisionMeshData ); - - concaveShape->recalcLocalAabb(); - 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; + } - return collisionMeshShape; - } + virtual bool SkipVertexTransform() + { + return true; + } - delete collisionMeshShape; - return NULL; + protected: + //class RAS_MeshObject *m_pMesh; + }; -} +// forward declarations void KX_ConvertBulletObject( class KX_GameObject* gameobj, class RAS_MeshObject* meshobj, @@ -885,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(); @@ -892,125 +792,108 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, { ci.m_collisionFlags |= btCollisionObject::CF_STATIC_OBJECT; } + if (objprop->m_ghost) + { + ci.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE; + } ci.m_MotionState = motionstate; 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; } } @@ -1018,10 +901,13 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, // ci.m_localInertiaTensor.setValue(0.1f,0.1f,0.1f); if (!bm) + { + delete motionstate; + delete shapeInfo; return; + } - bm->setMargin(0.06); - + bm->setMargin(ci.m_margin); if (objprop->m_isCompoundChild) @@ -1030,30 +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); + shapeInfo->m_childTrans.setBasis(newRot); + parentShapeInfo->AddShape(shapeInfo); + + compoundShape->addChildShape(shapeInfo->m_childTrans,bm); //do some recalc? //recalc inertia for rigidbody if (!rigidbody->isStaticOrKinematicObject()) @@ -1068,12 +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); + compoundShape->addChildShape(shapeInfo->m_childTrans,bm); + // now replace the shape bm = compoundShape; + shapeInfo = compoundShapeInfo; } @@ -1109,9 +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,7 +1025,69 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, //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); + // shapeInfo is reference counted, decrement now as we don't use it anymore + if (shapeInfo) + shapeInfo->Release(); if (objprop->m_in_active_layer) { @@ -1132,15 +1098,23 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, gameobj->SetPhysicsController(physicscontroller,isbulletdyna); physicscontroller->setNewClientInfo(gameobj->getClientInfo()); - btRigidBody* rbody = physicscontroller->GetRigidBody(); - - if (objprop->m_disableSleeping) - rbody->setActivationState(DISABLE_DEACTIVATION); - - if (objprop->m_ghost) { - rbody->setCollisionFlags(rbody->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE); + 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); + + + //Now done directly in ci.m_collisionFlags so that it propagates to replica + //if (objprop->m_ghost) + //{ + // rbody->setCollisionFlags(rbody->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE); + //} + if (objprop->m_dyna && !objprop->m_angular_rigidbody) { /* @@ -1155,8 +1129,10 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj, */ //env->createConstraint(physicscontroller,0,PHY_ANGULAR_CONSTRAINT,0,0,0,0,0,1); - physicscontroller->GetRigidBody()->setAngularFactor(0.f); - + + //Now done directly in ci.m_bRigid so that it propagates to replica + //physicscontroller->GetRigidBody()->setAngularFactor(0.f); + ; } bool isActor = objprop->m_isactor; @@ -1180,22 +1156,25 @@ 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); + + } + } + } void KX_ClearBulletSharedShapes() { - int numshapes = map_gamemesh_to_bulletshape.size(); - int i; - btCollisionShape*shape=0; - for (i=0;i<numshapes ;i++) - { - shape = *map_gamemesh_to_bulletshape.at(i); - //delete shape; - } - - map_gamemesh_to_bulletshape.clear(); - } #endif 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 1cb64585ff8..a168beb9a70 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" @@ -58,8 +59,13 @@ typedef unsigned long uint_ptr; #include "SG_Controller.h" #include "KX_ClientObjectInfo.h" #include "RAS_BucketManager.h" - +#include "KX_RayCast.h" +#include "KX_PythonInit.h" #include "KX_PyMath.h" +#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. @@ -73,36 +79,56 @@ KX_GameObject::KX_GameObject( ) : SCA_IObject(T), 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) { m_ignore_activity_culling = false; m_pClient_info = new KX_ClientObjectInfo(this, KX_ClientObjectInfo::ACTOR); m_pSGNode = new SG_Node(this,sgReplicationInfo,callbacks); - + // define the relationship between this node and it's parent. KX_NormalParentRelation * parent_relation = KX_NormalParentRelation::New(); m_pSGNode->SetParentRelation(parent_relation); - - }; KX_GameObject::~KX_GameObject() { + RemoveMeshes(); + // is this delete somewhere ? //if (m_sumoObj) // delete m_sumoObj; delete m_pClient_info; //if (m_pSGNode) // delete m_pSGNode; - + if (m_pSGNode) + { + // must go through controllers and make sure they will not use us anymore + // This is important for KX_BulletPhysicsControllers that unregister themselves + // from the object when they are deleted. + SGControllerList::iterator contit; + SGControllerList& controllers = m_pSGNode->GetSGControllerList(); + for (contit = controllers.begin();contit!=controllers.end();++contit) + { + (*contit)->ClearObject(); + } + m_pSGNode->SetSGClientObject(NULL); + } } @@ -186,7 +212,73 @@ KX_GameObject* KX_GameObject::GetParent() } +void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj) +{ + // check on valid node in case a python controller holds a reference to a deleted object + if (obj && GetSGNode() && obj->GetSGNode() && GetSGNode()->GetSGParent() != obj->GetSGNode()) + { + // Make sure the objects have some scale + MT_Vector3 scale1 = NodeGetWorldScaling(); + MT_Vector3 scale2 = obj->NodeGetWorldScaling(); + if (fabs(scale2[0]) < FLT_EPSILON || + fabs(scale2[1]) < FLT_EPSILON || + fabs(scale2[2]) < FLT_EPSILON || + fabs(scale1[0]) < FLT_EPSILON || + fabs(scale1[1]) < FLT_EPSILON || + fabs(scale1[2]) < FLT_EPSILON) { return; } + + // Remove us from our old parent and set our new parent + RemoveParent(scene); + obj->GetSGNode()->AddChild(GetSGNode()); + + if (m_pPhysicsController1) + { + m_pPhysicsController1->SuspendDynamics(true); + } + // Set us to our new scale, position, and orientation + 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())*scale2; + + NodeSetLocalScale(scale1); + NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2])); + NodeSetLocalOrientation(invori*NodeGetWorldOrientation()); + NodeUpdateGS(0.f,true); + // object will now be a child, it must be removed from the parent list + CListValue* rootlist = scene->GetRootParentList(); + if (rootlist->RemoveValue(this)) + // the object was in parent list, decrement ref count as it's now removed + Release(); + } +} + +void KX_GameObject::RemoveParent(KX_Scene *scene) +{ + // check on valid node in case a python controller holds a reference to a deleted object + if (GetSGNode() && GetSGNode()->GetSGParent()) + { + // Set us to the right spot + GetSGNode()->SetLocalScale(GetSGNode()->GetWorldScaling()); + GetSGNode()->SetLocalOrientation(GetSGNode()->GetWorldOrientation()); + GetSGNode()->SetLocalPosition(GetSGNode()->GetWorldPosition()); + // Remove us from our parent + GetSGNode()->DisconnectFromParent(); + NodeUpdateGS(0.f,true); + // the object is now a root object, add it to the parentlist + CListValue* rootlist = scene->GetRootParentList(); + if (!rootlist->SearchValue(this)) + // object was not in root list, add it now and increment ref count + rootlist->Add(AddRef()); + if (m_pPhysicsController1) + { + m_pPhysicsController1->RestoreDynamics(); + } + } +} void KX_GameObject::ProcessReplica(KX_GameObject* replica) { @@ -194,6 +286,7 @@ void KX_GameObject::ProcessReplica(KX_GameObject* replica) replica->m_pSGNode = NULL; replica->m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info); replica->m_pClient_info->m_gameobject = replica; + replica->m_state = 0; } @@ -201,11 +294,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; } @@ -241,12 +334,12 @@ void KX_GameObject::ApplyMovement(const MT_Vector3& dloc,bool local) void KX_GameObject::ApplyRotation(const MT_Vector3& drot,bool local) { MT_Matrix3x3 rotmat(drot); - rotmat.transpose(); - - if (m_pPhysicsController1) // (IsDynamic()) - m_pPhysicsController1->RelativeRotate(rotmat,local); - // in worldspace + GetSGNode()->RelativeRotate(rotmat,local); + + if (m_pPhysicsController1) { // (IsDynamic()) + m_pPhysicsController1->RelativeRotate(rotmat,local); + } } @@ -264,31 +357,54 @@ double* KX_GameObject::GetOpenGLMatrix() trans.setBasis(GetSGNode()->GetWorldOrientation()); MT_Vector3 scaling = GetSGNode()->GetWorldScaling(); - + m_bIsNegativeScaling = ((scaling[0] < 0.0) ^ (scaling[1] < 0.0) ^ (scaling[2] < 0.0)) ? true : false; trans.scale(scaling[0], scaling[1], scaling[2]); trans.getValue(fl); 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(); + 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::Bucketize() +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 @@ -332,34 +448,25 @@ void KX_GameObject::ResetDebugColor() SetDebugColor(0xff000000); } +void KX_GameObject::InitIPO(bool ipo_as_force, + bool ipo_add, + bool ipo_local) +{ + SGControllerList::iterator it = GetSGNode()->GetSGControllerList().begin(); + while (it != GetSGNode()->GetSGControllerList().end()) { + (*it)->SetOption(SG_Controller::SG_CONTR_IPO_RESET, true); + (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, ipo_as_force); + (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_ADD, ipo_add); + (*it)->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, ipo_local); + it++; + } +} void KX_GameObject::UpdateIPO(float curframetime, - bool recurse, - bool ipo_as_force, - bool force_local) + bool recurse) { - - // The ipo-actuator needs a sumo reference... this is retrieved (unfortunately) - // by the iposgcontr itself... -// ipocontr->SetSumoReference(gameobj->GetSumoScene(), -// gameobj->GetSumoObject()); - - - // The ipo has to be treated as a force, and not a displacement! - // For this case, we send some settings to the controller. This - // may need some caching... - if (ipo_as_force) { - SGControllerList::iterator it = GetSGNode()->GetSGControllerList().begin(); - - while (it != GetSGNode()->GetSGControllerList().end()) { - (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, ipo_as_force); - (*it)->SetOption(SG_Controller::SG_CONTR_IPO_FORCES_ACT_LOCAL, force_local); - it++; - } - } - - // The rest is the 'normal' update procedure. + // just the 'normal' update procedure. GetSGNode()->SetSimulatedTime(curframetime,recurse); GetSGNode()->UpdateWorldData(curframetime); UpdateTransform(); @@ -368,6 +475,7 @@ void KX_GameObject::UpdateIPO(float curframetime, // IPO update void KX_GameObject::UpdateMaterialData( + dword matname_hash, MT_Vector4 rgba, MT_Vector3 specrgb, MT_Scalar hard, @@ -380,15 +488,34 @@ 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(); + RAS_IPolyMaterial* poly = mit->m_bucket->GetPolyMaterial(); + if(poly->GetFlag() & RAS_BLENDERMAT ) { - SetObjectColor(rgba); KX_BlenderMaterial *m = static_cast<KX_BlenderMaterial*>(poly); - m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha); + + if (matname_hash == NULL) + { + 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) + SetObjectColor(rgba); + } + else + { + if (matname_hash == poly->GetMaterialNameHash()) + { + m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha); + m_meshes[mesh]->SetVertexColor(poly,rgba); + + // no break here, because one blender material can be split into several game engine materials + // (e.g. one uvsphere material is split into one material at poles with ras_mode TRIANGLE and one material for the body + // if here was a break then would miss some vertices if material was split + } + } } } } @@ -401,56 +528,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); } -// used by Python, and the actuatorshould _not_ be misused by the -// scene! -void -KX_GameObject::MarkVisible( - bool visible +bool +KX_GameObject::GetCulled( + void ) { - /* 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); - } + return m_bCulled; } +void +KX_GameObject::SetCulled( + bool c + ) +{ + m_bCulled = c; +} -// Always use the flag? -void -KX_GameObject::MarkVisible( - void + +void +KX_GameObject::SetLayer( + int l ) { - 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 - ); - } + m_layer = l; } +int +KX_GameObject::GetLayer( + void + ) +{ + 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); + } } @@ -492,62 +638,205 @@ void KX_GameObject::SetObjectColor(const MT_Vector4& rgbavec) m_objectColor = rgbavec; } +void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac) +{ + MT_Matrix3x3 orimat; + MT_Vector3 vect,ori,z,x,y; + MT_Scalar len; + // check on valid node in case a python controller holds a reference to a deleted object + if (!GetSGNode()) + return; -MT_Vector3 KX_GameObject::GetLinearVelocity() -{ - MT_Vector3 velocity(0.0,0.0,0.0); + vect = dir; + len = vect.length(); + if (MT_fuzzyZero(len)) + { + cout << "alignAxisToVect() Error: Null vector!\n"; + return; + } + + if (fac<=0.0) { + return; + } + // normalize + vect /= len; + orimat = GetSGNode()->GetWorldOrientation(); + switch (axis) + { + case 0: //x axis + ori = MT_Vector3(orimat[0][2], orimat[1][2], orimat[2][2]); //pivot axis + if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON) //is the vector paralell to the pivot? + ori = MT_Vector3(orimat[0][1], orimat[1][1], orimat[2][1]); //change the pivot! + if (fac == 1.0) { + x = vect; + } else { + x = (vect * fac) + ((orimat * MT_Vector3(1.0, 0.0, 0.0)) * (1-fac)); + len = x.length(); + if (MT_fuzzyZero(len)) x = vect; + else x /= len; + } + y = ori.cross(x); + z = x.cross(y); + break; + case 1: //y axis + ori = MT_Vector3(orimat[0][0], orimat[1][0], orimat[2][0]); + if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON) + ori = MT_Vector3(orimat[0][2], orimat[1][2], orimat[2][2]); + if (fac == 1.0) { + y = vect; + } else { + y = (vect * fac) + ((orimat * MT_Vector3(0.0, 1.0, 0.0)) * (1-fac)); + len = y.length(); + if (MT_fuzzyZero(len)) y = vect; + else y /= len; + } + z = ori.cross(y); + x = y.cross(z); + break; + case 2: //z axis + ori = MT_Vector3(orimat[0][1], orimat[1][1], orimat[2][1]); + if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON) + ori = MT_Vector3(orimat[0][0], orimat[1][0], orimat[2][0]); + if (fac == 1.0) { + z = vect; + } else { + z = (vect * fac) + ((orimat * MT_Vector3(0.0, 0.0, 1.0)) * (1-fac)); + len = z.length(); + if (MT_fuzzyZero(len)) z = vect; + else z /= len; + } + x = ori.cross(z); + y = z.cross(x); + break; + default: //wrong input? + cout << "alignAxisToVect(): Wrong axis '" << axis <<"'\n"; + return; + } + x.normalize(); //normalize the vectors + y.normalize(); + z.normalize(); + orimat = MT_Matrix3x3( x[0],y[0],z[0], + x[1],y[1],z[1], + x[2],y[2],z[2]); + if (GetSGNode()->GetSGParent() != NULL) + { + // the object is a child, adapt its local orientation so that + // the global orientation is aligned as we want. + MT_Matrix3x3 invori = GetSGNode()->GetSGParent()->GetWorldOrientation().inverse(); + NodeSetLocalOrientation(invori*orimat); + } + else + NodeSetLocalOrientation(orimat); +} + +MT_Scalar KX_GameObject::GetMass() +{ + if (m_pPhysicsController1) + { + return m_pPhysicsController1->GetMass(); + } + return 0.0; +} + +MT_Vector3 KX_GameObject::GetLinearVelocity(bool local) +{ + MT_Vector3 velocity(0.0,0.0,0.0), locvel; + MT_Matrix3x3 ori; if (m_pPhysicsController1) { velocity = m_pPhysicsController1->GetLinearVelocity(); + + if (local) + { + ori = GetSGNode()->GetWorldOrientation(); + + locvel = velocity * ori; + return locvel; + } } - return velocity; - + return velocity; +} + +MT_Vector3 KX_GameObject::GetAngularVelocity(bool local) +{ + MT_Vector3 velocity(0.0,0.0,0.0), locvel; + MT_Matrix3x3 ori; + if (m_pPhysicsController1) + { + velocity = m_pPhysicsController1->GetAngularVelocity(); + + if (local) + { + ori = GetSGNode()->GetWorldOrientation(); + + locvel = velocity * ori; + return locvel; + } + } + 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 void KX_GameObject::NodeSetLocalPosition(const MT_Point3& trans) { - if (m_pPhysicsController1) + // check on valid node in case a python controller holds a reference to a deleted object + if (!GetSGNode()) + return; + + if (m_pPhysicsController1 && !GetSGNode()->GetSGParent()) { + // don't update physic controller if the object is a child: + // 1) the transformation will not be right + // 2) in this case, the physic controller is necessarily a static object + // that is updated from the normal kinematic synchronization m_pPhysicsController1->setPosition(trans); } - if (GetSGNode()) - GetSGNode()->SetLocalPosition(trans); + GetSGNode()->SetLocalPosition(trans); } void KX_GameObject::NodeSetLocalOrientation(const MT_Matrix3x3& rot) { - if (m_pPhysicsController1) - { - m_pPhysicsController1->setOrientation(rot.getRotation()); - } - if (GetSGNode()) - GetSGNode()->SetLocalOrientation(rot); - else + // check on valid node in case a python controller holds a reference to a deleted object + if (!GetSGNode()) + return; + + if (m_pPhysicsController1 && !GetSGNode()->GetSGParent()) { - int i; - i=0; + // see note above + m_pPhysicsController1->setOrientation(rot); } + GetSGNode()->SetLocalOrientation(rot); } void KX_GameObject::NodeSetLocalScale(const MT_Vector3& scale) { - if (m_pPhysicsController1) + // check on valid node in case a python controller holds a reference to a deleted object + if (!GetSGNode()) + return; + + if (m_pPhysicsController1 && !GetSGNode()->GetSGParent()) { + // see note above m_pPhysicsController1->setScaling(scale); } - - if (GetSGNode()) - GetSGNode()->SetLocalScale(scale); + GetSGNode()->SetLocalScale(scale); } @@ -555,9 +844,44 @@ 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) +{ + SG_Node* parent = m_pSGNode->GetSGParent(); + if (parent != NULL) + { + // Make sure the objects have some scale + MT_Vector3 scale = parent->GetWorldScaling(); + if (fabs(scale[0]) < FLT_EPSILON || + fabs(scale[1]) < FLT_EPSILON || + fabs(scale[2]) < FLT_EPSILON) + { + return; + } + scale[0] = 1.0/scale[0]; + scale[1] = 1.0/scale[1]; + scale[2] = 1.0/scale[2]; + MT_Matrix3x3 invori = parent->GetWorldOrientation().inverse(); + MT_Vector3 newpos = invori*(trans-parent->GetWorldPosition())*scale; + NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2])); + } + else + { + NodeSetLocalPosition(trans); + } +} void KX_GameObject::NodeUpdateGS(double time,bool bInitiator) @@ -570,6 +894,13 @@ void KX_GameObject::NodeUpdateGS(double time,bool bInitiator) const MT_Matrix3x3& KX_GameObject::NodeGetWorldOrientation() const { + static MT_Matrix3x3 defaultOrientation = MT_Matrix3x3( 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); + + // check on valid node in case a python controller holds a reference to a deleted object + if (!GetSGNode()) + return defaultOrientation; return GetSGNode()->GetWorldOrientation(); } @@ -577,6 +908,12 @@ const MT_Matrix3x3& KX_GameObject::NodeGetWorldOrientation() const const MT_Vector3& KX_GameObject::NodeGetWorldScaling() const { + static MT_Vector3 defaultScaling = MT_Vector3(1.0, 1.0, 1.0); + + // check on valid node in case a python controller holds a reference to a deleted object + if (!GetSGNode()) + return defaultScaling; + return GetSGNode()->GetWorldScaling(); } @@ -584,6 +921,12 @@ const MT_Vector3& KX_GameObject::NodeGetWorldScaling() const const MT_Point3& KX_GameObject::NodeGetWorldPosition() const { + static MT_Point3 defaultPosition = MT_Point3(0.0, 0.0, 0.0); + + // check on valid node in case a python controller holds a reference to a deleted object + if (!GetSGNode()) + return defaultPosition; + return GetSGNode()->GetWorldPosition(); } @@ -604,7 +947,7 @@ void KX_GameObject::Resume(void) } } -void KX_GameObject::Suspend(void) +void KX_GameObject::Suspend() { if ((!m_ignore_activity_culling) && (!m_suspended)) { @@ -623,25 +966,44 @@ void KX_GameObject::Suspend(void) PyMethodDef KX_GameObject::Methods[] = { - {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS}, - {"setPosition", (PyCFunction) KX_GameObject::sPySetPosition, METH_VARARGS}, - {"getPosition", (PyCFunction) KX_GameObject::sPyGetPosition, METH_VARARGS}, - {"getOrientation", (PyCFunction) KX_GameObject::sPyGetOrientation, METH_VARARGS}, - {"setOrientation", (PyCFunction) KX_GameObject::sPySetOrientation, METH_VARARGS}, + {"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_VARARGS}, - {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_VARARGS}, + {"getMass", (PyCFunction) KX_GameObject::sPyGetMass, METH_NOARGS}, + {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_NOARGS}, + {"getOrientation", (PyCFunction) KX_GameObject::sPyGetOrientation, METH_NOARGS}, + {"setOrientation", (PyCFunction) KX_GameObject::sPySetOrientation, METH_O}, + {"getVisible",(PyCFunction) KX_GameObject::sPyGetVisible, METH_NOARGS}, + {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS}, + {"getState",(PyCFunction) KX_GameObject::sPyGetState, METH_NOARGS}, + {"setState",(PyCFunction) KX_GameObject::sPySetState, METH_O}, + {"alignAxisToVect",(PyCFunction) KX_GameObject::sPyAlignAxisToVect, METH_VARARGS}, + {"getAxisVect",(PyCFunction) KX_GameObject::sPyGetAxisVect, METH_O}, + {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics,METH_NOARGS}, + {"restoreDynamics", (PyCFunction)KX_GameObject::sPyRestoreDynamics,METH_NOARGS}, + {"enableRigidBody", (PyCFunction)KX_GameObject::sPyEnableRigidBody,METH_NOARGS}, + {"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_NOARGS}, {"applyImpulse", (PyCFunction) KX_GameObject::sPyApplyImpulse, METH_VARARGS}, - {"setCollisionMargin", (PyCFunction) KX_GameObject::sPySetCollisionMargin, METH_VARARGS}, - {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics,METH_VARARGS}, - {"restoreDynamics", (PyCFunction)KX_GameObject::sPyRestoreDynamics,METH_VARARGS}, - {"enableRigidBody", (PyCFunction)KX_GameObject::sPyEnableRigidBody,METH_VARARGS}, - {"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_VARARGS}, - {"getParent", (PyCFunction)KX_GameObject::sPyGetParent,METH_VARARGS}, + {"setCollisionMargin", (PyCFunction) KX_GameObject::sPySetCollisionMargin, METH_O}, + {"getParent", (PyCFunction)KX_GameObject::sPyGetParent,METH_NOARGS}, + {"setParent", (PyCFunction)KX_GameObject::sPySetParent,METH_O}, + {"removeParent", (PyCFunction)KX_GameObject::sPyRemoveParent,METH_NOARGS}, + {"getChildren", (PyCFunction)KX_GameObject::sPyGetChildren,METH_NOARGS}, + {"getChildrenRecursive", (PyCFunction)KX_GameObject::sPyGetChildrenRecursive,METH_NOARGS}, {"getMesh", (PyCFunction)KX_GameObject::sPyGetMesh,METH_VARARGS}, - {"getPhysicsId", (PyCFunction)KX_GameObject::sPyGetPhysicsId,METH_VARARGS}, + {"getPhysicsId", (PyCFunction)KX_GameObject::sPyGetPhysicsId,METH_NOARGS}, + {"getPropertyNames", (PyCFunction)KX_GameObject::sPyGetPropertyNames,METH_NOARGS}, + {"replaceMesh",(PyCFunction) KX_GameObject::sPyReplaceMesh, METH_O}, + {"endObject",(PyCFunction) KX_GameObject::sPyEndObject, METH_NOARGS}, + KX_PYMETHODTABLE(KX_GameObject, rayCastTo), + KX_PYMETHODTABLE(KX_GameObject, rayCast), KX_PYMETHODTABLE(KX_GameObject, getDistanceTo), + KX_PYMETHODTABLE(KX_GameObject, getVectTo), {NULL,NULL} //Sentinel }; @@ -663,19 +1025,40 @@ bool KX_GameObject::ConvertPythonVectorArgs(PyObject* args, } */ - -PyObject* KX_GameObject::sPySetPosition(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyReplaceMesh(PyObject* self, PyObject* value) { - return ((KX_GameObject*) self)->PySetPosition(self, args, kwds); + KX_Scene *scene = KX_GetActiveScene(); + char* meshname; + void* mesh_pt; + + meshname = PyString_AsString(value); + if (meshname==NULL) { + PyErr_SetString(PyExc_ValueError, "Expected a mesh name"); + return NULL; + } + mesh_pt = SCA_ILogicBrick::m_sCurrentLogicManager->GetMeshByName(STR_String(meshname)); + + if (mesh_pt==NULL) { + PyErr_SetString(PyExc_ValueError, "The mesh name given does not exist"); + return NULL; + } + scene->ReplaceMesh(this, (class RAS_MeshObject*)mesh_pt); + + Py_RETURN_NONE; } + +PyObject* KX_GameObject::PyEndObject(PyObject* self) +{ + + KX_Scene *scene = KX_GetActiveScene(); + scene->DelayedRemoveObject(this); + Py_RETURN_NONE; + +} -PyObject* KX_GameObject::PyGetPosition(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyGetPosition(PyObject* self) { return PyObjectFrom(NodeGetWorldPosition()); } @@ -729,7 +1112,7 @@ PyObject* KX_GameObject::_getattr(const STR_String& attr) parent->AddRef(); return parent; } - Py_Return; + Py_RETURN_NONE; } if (attr == "visible") @@ -746,27 +1129,53 @@ PyObject* KX_GameObject::_getattr(const STR_String& attr) if (attr == "name") return PyString_FromString(m_name.ReadPtr()); + if (attr == "timeOffset") { + if (m_pSGNode->GetSGParent()->IsSlowParent()) { + return PyFloat_FromDouble(static_cast<KX_SlowParentRelation *>(m_pSGNode->GetSGParent()->GetParentRelation())->GetTimeOffset()); + } else { + return PyFloat_FromDouble(0.0); + } + } + _getattr_up(SCA_IObject); } 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; } } + + if (PyFloat_Check(value)) + { + MT_Scalar val = PyFloat_AsDouble(value); + if (attr == "timeOffset") { + if (m_pSGNode->GetSGParent() && m_pSGNode->GetSGParent()->IsSlowParent()) { + static_cast<KX_SlowParentRelation *>(m_pSGNode->GetSGParent()->GetParentRelation())->SetTimeOffset(val); + return 0; + } else { + return 0; + } + } + } if (PySequence_Check(value)) { @@ -778,6 +1187,7 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr if (PyMatTo(value, rot)) { NodeSetLocalOrientation(rot); + NodeUpdateGS(0.f,true); return 0; } return 1; @@ -790,6 +1200,7 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr { rot.setRotation(qrot); NodeSetLocalOrientation(rot); + NodeUpdateGS(0.f,true); return 0; } return 1; @@ -802,11 +1213,12 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr { rot.setEuler(erot); NodeSetLocalOrientation(rot); + NodeUpdateGS(0.f,true); return 0; } return 1; } - + PyErr_SetString(PyExc_AttributeError, "could not set the orientation from a 3x3 matrix, quaternion or euler sequence"); return 1; } @@ -816,6 +1228,7 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr if (PyVecTo(value, pos)) { NodeSetLocalPosition(pos); + NodeUpdateGS(0.f,true); return 0; } return 1; @@ -827,6 +1240,7 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr if (PyVecTo(value, scale)) { NodeSetLocalScale(scale); + NodeUpdateGS(0.f,true); return 0; } return 1; @@ -842,44 +1256,117 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr } } + /* Need to have parent settable here too */ + return SCA_IObject::_setattr(attr, value); } -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... - return PyObjectFrom(GetLinearVelocity()); + int local = 0; + if (PyArg_ParseTuple(args,"|i",&local)) + { + return PyObjectFrom(GetLinearVelocity((local!=0))); + } + else + { + return NULL; + } } - - -PyObject* KX_GameObject::PySetVisible(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PySetLinearVelocity(PyObject* self, PyObject* args) { - int visible = 1; + int local = 0; + PyObject* pyvect; - if (PyArg_ParseTuple(args,"i",&visible)) + if (PyArg_ParseTuple(args,"O|i",&pyvect,&local)) { + MT_Vector3 velocity; + if (PyVecTo(pyvect, velocity)) { + setLinearVelocity(velocity, (local!=0)); + Py_RETURN_NONE; + } + } + return NULL; +} + +PyObject* KX_GameObject::PyGetAngularVelocity(PyObject* self, PyObject* args) +{ + // only can get the velocity if we have a physics object connected to us... + int local = 0; + if (PyArg_ParseTuple(args,"|i",&local)) { - MarkVisible(visible!=0); - m_bVisible = (visible!=0); + return PyObjectFrom(GetAngularVelocity((local!=0))); } else { - return NULL; + return NULL; } - Py_Return; +} + +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; + + SetVisible(visible ? true:false, recursive ? true:false); + UpdateBuckets(recursive ? true:false); + Py_RETURN_NONE; + +} + +PyObject* KX_GameObject::PyGetVisible(PyObject* self) +{ + return PyInt_FromLong(m_bVisible); +} + +PyObject* KX_GameObject::PyGetState(PyObject* self) +{ + int state = 0; + state |= GetState(); + return PyInt_FromLong(state); +} + +PyObject* KX_GameObject::PySetState(PyObject* self, PyObject* value) +{ + int state_i = PyInt_AsLong(value); + unsigned int state = 0; + + if (state_i == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "expected an int bit field"); + return NULL; + } + + state |= state_i; + if ((state & ((1<<30)-1)) == 0) { + PyErr_SetString(PyExc_AttributeError, "The state bitfield was not between 0 and 30 (1<<0 and 1<<29)"); + return NULL; + } + SetState(state); + + Py_RETURN_NONE; } -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); @@ -892,6 +1379,9 @@ PyObject* KX_GameObject::PyGetVelocity(PyObject* self, if (pypos) PyVecTo(pypos, point); } + else { + return NULL; + } if (m_pPhysicsController1) { @@ -903,26 +1393,14 @@ PyObject* KX_GameObject::PyGetVelocity(PyObject* self, -PyObject* KX_GameObject::PyGetMass(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyGetMass(PyObject* self) { - PyObject* pymass = NULL; - - float mass = GetPhysicsController()->GetMass(); - pymass = PyFloat_FromDouble(mass); - - if (pymass) - return pymass; - - Py_Return; + return PyFloat_FromDouble(GetPhysicsController()->GetMass()); } -PyObject* KX_GameObject::PyGetReactionForce(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyGetReactionForce(PyObject* self) { // only can get the velocity if we have a physics object connected to us... return PyObjectFrom(GetPhysicsController()->getReactionForce()); @@ -930,32 +1408,25 @@ PyObject* KX_GameObject::PyGetReactionForce(PyObject* self, -PyObject* KX_GameObject::PyEnableRigidBody(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyEnableRigidBody(PyObject* self) { - GetPhysicsController()->setRigidBody(true); - Py_Return; + Py_RETURN_NONE; } -PyObject* KX_GameObject::PyDisableRigidBody(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyDisableRigidBody(PyObject* self) { GetPhysicsController()->setRigidBody(false); - Py_Return; + Py_RETURN_NONE; } -PyObject* KX_GameObject::PyGetParent(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyGetParent(PyObject* self) { KX_GameObject* parent = this->GetParent(); if (parent) @@ -963,69 +1434,128 @@ PyObject* KX_GameObject::PyGetParent(PyObject* self, parent->AddRef(); return parent; } - Py_Return; + Py_RETURN_NONE; +} + +PyObject* KX_GameObject::PySetParent(PyObject* self, PyObject* value) +{ + if (!PyObject_TypeCheck(value, &KX_GameObject::Type)) { + PyErr_SetString(PyExc_TypeError, "expected a KX_GameObject type"); + return NULL; + } + + // The object we want to set as parent + CValue *m_ob = (CValue*)value; + KX_GameObject *obj = ((KX_GameObject*)m_ob); + KX_Scene *scene = KX_GetActiveScene(); + + this->SetParent(scene, obj); + + Py_RETURN_NONE; } +PyObject* KX_GameObject::PyRemoveParent(PyObject* self) +{ + KX_Scene *scene = KX_GetActiveScene(); + this->RemoveParent(scene); + Py_RETURN_NONE; +} -PyObject* KX_GameObject::PyGetMesh(PyObject* self, - PyObject* args, - PyObject* kwds) +static void walk_children(SG_Node* node, CListValue* list, bool recursive) { - int mesh = 0; + NodeList& children = node->GetSGChildren(); - if (PyArg_ParseTuple(args, "|i", &mesh)) + for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) { - if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0) + SG_Node* childnode = (*childit); + CValue* childobj = (CValue*)childnode->GetSGClientObject(); + if (childobj != NULL) // This is a GameObject { - KX_MeshProxy* meshproxy = new KX_MeshProxy(m_meshes[mesh]); - return meshproxy; + // add to the list + list->Add(childobj->AddRef()); + } + + // if the childobj is NULL then this may be an inverse parent link + // so a non recursive search should still look down this node. + if (recursive || childobj==NULL) { + walk_children(childnode, list, recursive); } } - Py_Return; } +PyObject* KX_GameObject::PyGetChildren(PyObject* self) +{ + CListValue* list = new CListValue(); + walk_children(m_pSGNode, list, 0); + return list; +} +PyObject* KX_GameObject::PyGetChildrenRecursive(PyObject* self) +{ + CListValue* list = new CListValue(); + walk_children(m_pSGNode, list, 1); + return list; +} - - -PyObject* KX_GameObject::PySetCollisionMargin(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyGetMesh(PyObject* self, PyObject* args) { - float collisionMargin; - if (PyArg_ParseTuple(args, "f", &collisionMargin)) + int mesh = 0; + + if (!PyArg_ParseTuple(args, "|i", &mesh)) + return NULL; // python sets a simple error + + if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0) { - if (m_pPhysicsController1) - { - m_pPhysicsController1->setMargin(collisionMargin); - Py_Return; - } + KX_MeshProxy* meshproxy = new KX_MeshProxy(m_meshes[mesh]); + return meshproxy; + } + + Py_RETURN_NONE; +} + + + + +PyObject* KX_GameObject::PySetCollisionMargin(PyObject* self, PyObject* value) +{ + float collisionMargin = PyFloat_AsDouble(value); + + if (collisionMargin==-1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "expected a float"); + return NULL; } + if (m_pPhysicsController1) + { + m_pPhysicsController1->setMargin(collisionMargin); + Py_RETURN_NONE; + } + PyErr_SetString(PyExc_RuntimeError, "This object has no physics controller"); return NULL; } -PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, PyObject* args) { PyObject* pyattach; PyObject* pyimpulse; + + if (!m_pPhysicsController1) { + PyErr_SetString(PyExc_RuntimeError, "This object has no physics controller"); + return NULL; + } + if (PyArg_ParseTuple(args, "OO", &pyattach, &pyimpulse)) { MT_Point3 attach; MT_Vector3 impulse; - if (m_pPhysicsController1) + if (PyVecTo(pyattach, attach) && PyVecTo(pyimpulse, impulse)) { - if (PyVecTo(pyattach, attach) && PyVecTo(pyimpulse, impulse)) - { - m_pPhysicsController1->applyImpulse(attach, impulse); - Py_Return; - } + m_pPhysicsController1->applyImpulse(attach, impulse); + Py_RETURN_NONE; } } @@ -1035,102 +1565,109 @@ PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, -PyObject* KX_GameObject::PySuspendDynamics(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PySuspendDynamics(PyObject* self) { - if (m_bSuspendDynamics) - { - Py_Return; - } - - if (m_pPhysicsController1) - { - m_pPhysicsController1->SuspendDynamics(); - } - m_bSuspendDynamics = true; - - Py_Return; + SuspendDynamics(); + Py_RETURN_NONE; } -PyObject* KX_GameObject::PyRestoreDynamics(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PyRestoreDynamics(PyObject* self) { - - if (!m_bSuspendDynamics) - { - Py_Return; - } - - if (m_pPhysicsController1) - { - m_pPhysicsController1->RestoreDynamics(); - } - m_bSuspendDynamics = false; - - Py_Return; + RestoreDynamics(); + Py_RETURN_NONE; } -PyObject* KX_GameObject::PyGetOrientation(PyObject* self, - PyObject* args, - PyObject* kwds) //keywords +PyObject* KX_GameObject::PyGetOrientation(PyObject* self) //keywords { return PyObjectFrom(NodeGetWorldOrientation()); } -PyObject* KX_GameObject::PySetOrientation(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PySetOrientation(PyObject* self, PyObject* value) { - PyObject* pylist; - - if (PyArg_ParseTuple(args,"O",&pylist)) + MT_Matrix3x3 matrix; + if (PyObject_IsMT_Matrix(value, 3) && PyMatTo(value, matrix)) { - MT_Matrix3x3 matrix; - if (PyObject_IsMT_Matrix(pylist, 3) && PyMatTo(pylist, matrix)) - { - NodeSetLocalOrientation(matrix); - Py_Return; - } + NodeSetLocalOrientation(matrix); + NodeUpdateGS(0.f,true); + Py_RETURN_NONE; + } + + MT_Quaternion quat; + if (PyVecTo(value, quat)) + { + matrix.setRotation(quat); + NodeSetLocalOrientation(matrix); + NodeUpdateGS(0.f,true); + Py_RETURN_NONE; + } + return NULL; +} + +PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* self, PyObject* args) +{ + PyObject* pyvect; + int axis = 2; //z axis is the default + float fac = 1.0; - MT_Quaternion quat; - if (PyVecTo(pylist, quat)) + if (PyArg_ParseTuple(args,"O|if",&pyvect,&axis, &fac)) + { + MT_Vector3 vect; + if (PyVecTo(pyvect, vect)) { - matrix.setRotation(quat); - NodeSetLocalOrientation(matrix); - Py_Return; + if (fac<=0.0) Py_RETURN_NONE; // Nothing to do. + if (fac> 1.0) fac= 1.0; + + AlignAxisToVect(vect,axis,fac); + NodeUpdateGS(0.f,true); + Py_RETURN_NONE; } } return NULL; } +PyObject* KX_GameObject::PyGetAxisVect(PyObject* self, PyObject* value) +{ + MT_Vector3 vect; + if (PyVecTo(value, vect)) + { + return PyObjectFrom(NodeGetWorldOrientation() * vect); + } + return NULL; +} - -PyObject* KX_GameObject::PySetPosition(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_GameObject::PySetPosition(PyObject* self, PyObject* value) { MT_Point3 pos; - if (PyVecArgTo(args, pos)) + if (PyVecTo(value, pos)) { NodeSetLocalPosition(pos); NodeUpdateGS(0.f,true); - Py_Return; + Py_RETURN_NONE; } - + return NULL; } -PyObject* KX_GameObject::PyGetPhysicsId(PyObject* self, - PyObject* args, - PyObject* kwds) +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(); uint_ptr physid=0; @@ -1141,6 +1678,11 @@ PyObject* KX_GameObject::PyGetPhysicsId(PyObject* self, return PyInt_FromLong((long)physid); } +PyObject* KX_GameObject::PyGetPropertyNames(PyObject* self) +{ + return ConvertKeysToPython(); +} + KX_PYMETHODDEF_DOC(KX_GameObject, getDistanceTo, "getDistanceTo(other): get distance to another point/KX_GameObject") { @@ -1152,20 +1694,356 @@ KX_PYMETHODDEF_DOC(KX_GameObject, getDistanceTo, PyErr_Clear(); PyObject *pyother; - if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &pyother)) + KX_GameObject *other; + if (PyArg_ParseTuple(args, "O", &pyother) && ConvertPythonToGameObject(pyother, &other, false)) { - KX_GameObject *other = static_cast<KX_GameObject*>(pyother); return PyFloat_FromDouble(NodeGetWorldPosition().distance(other->NodeGetWorldPosition())); } return NULL; } +KX_PYMETHODDEF_DOC(KX_GameObject, getVectTo, +"getVectTo(other): get vector and the distance to another point/KX_GameObject\n" +"Returns a 3-tuple with (distance,worldVector,localVector)\n") +{ + MT_Point3 toPoint, fromPoint; + MT_Vector3 toDir, locToDir; + MT_Scalar distance; + + PyObject *returnValue; + PyObject *pyother; + + if (!PyVecArgTo(args, toPoint)) + { + PyErr_Clear(); + + KX_GameObject *other; + if (PyArg_ParseTuple(args, "O", &pyother) && ConvertPythonToGameObject(pyother, &other, false)) + { + toPoint = other->NodeGetWorldPosition(); + } else + { + PyErr_SetString(PyExc_TypeError, "Expected a 3D Vector or GameObject type"); + return NULL; + } + } + + fromPoint = NodeGetWorldPosition(); + toDir = toPoint-fromPoint; + distance = toDir.length(); + + if (MT_fuzzyZero(distance)) + { + //cout << "getVectTo() Error: Null vector!\n"; + locToDir = toDir = MT_Vector3(0.0,0.0,0.0); + distance = 0.0; + } else { + toDir.normalize(); + locToDir = toDir * NodeGetWorldOrientation(); + } + + returnValue = PyTuple_New(3); + if (returnValue) { // very unlikely to fail, python sets a memory error here. + PyTuple_SET_ITEM(returnValue, 0, PyFloat_FromDouble(distance)); + PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(toDir)); + PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(locToDir)); + } + return returnValue; +} + +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) + { + // 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 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) + { + return true; + } + // skip the object + return false; +} + +KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, +"rayCastTo(other,dist,prop): look towards another point/KX_GameObject and return first object hit within dist that matches prop\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 other\n" +" other = 3-tuple or object reference") +{ + MT_Point3 toPoint; + PyObject* pyarg; + float dist = 0.0f; + char *propName = NULL; + + if (!PyArg_ParseTuple(args,"O|fs", &pyarg, &dist, &propName)) { + return NULL; // python sets simple error + } + + if (!PyVecTo(pyarg, toPoint)) + { + KX_GameObject *other; + PyErr_Clear(); + + if (ConvertPythonToGameObject(pyarg, &other, false)) + { + toPoint = other->NodeGetWorldPosition(); + } else + { + PyErr_SetString(PyExc_TypeError, "the first argument to rayCastTo must be a vector or a KX_GameObject"); + return NULL; + } + } + MT_Point3 fromPoint = NodeGetWorldPosition(); + if (dist != 0.0f) + { + MT_Vector3 toDir = toPoint-fromPoint; + toDir.normalize(); + toPoint = fromPoint + (dist) * toDir; + } + + PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment(); + KX_IPhysicsController *spc = GetPhysicsController(); + KX_GameObject *parent = GetParent(); + if (!spc && parent) + spc = parent->GetPhysicsController(); + if (parent) + parent->Release(); + + m_pHitObject = NULL; + if (propName) + m_testPropName = propName; + else + m_testPropName.SetLength(0); + KX_RayCast::Callback<KX_GameObject> callback(this,spc); + KX_RayCast::RayTest(pe, fromPoint, toPoint, callback); + + if (m_pHitObject) + { + m_pHitObject->AddRef(); + return m_pHitObject; + } + Py_RETURN_NONE; +} + +KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, + "rayCast(to,from,dist,prop,face,xray,poly): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) of contact point with object within dist that matches prop.\n" + " If no hit, return (None,None,None) or (None,None,None,None).\n" +" 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" +" 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; + PyObject* pyto; + PyObject* pyfrom = NULL; + float dist = 0.0f; + char *propName = NULL; + KX_GameObject *other; + int face=0, xray=0, poly=0; + + if (!PyArg_ParseTuple(args,"O|Ofsiii", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly)) { + return NULL; // Python sets a simple error + } + + if (!PyVecTo(pyto, toPoint)) + { + PyErr_Clear(); + + if (ConvertPythonToGameObject(pyto, &other, false)) + { + toPoint = other->NodeGetWorldPosition(); + } else + { + PyErr_SetString(PyExc_TypeError, "the first argument to rayCast must be a vector or a KX_GameObject"); + return NULL; + } + } + if (!pyfrom || pyfrom == Py_None) + { + fromPoint = NodeGetWorldPosition(); + } + else if (!PyVecTo(pyfrom, fromPoint)) + { + PyErr_Clear(); + + if (ConvertPythonToGameObject(pyfrom, &other, false)) + { + fromPoint = other->NodeGetWorldPosition(); + } else + { + PyErr_SetString(PyExc_TypeError, "the second optional argument to rayCast must be a vector or a KX_GameObject"); + return NULL; + } + } + + if (dist != 0.0f) { + MT_Vector3 toDir = toPoint-fromPoint; + if (MT_fuzzyZero(toDir.length2())) { + return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + } + toDir.normalize(); + toPoint = fromPoint + (dist) * toDir; + } else if (MT_fuzzyZero((toPoint-fromPoint).length2())) { + return Py_BuildValue("OOO", Py_None, Py_None, Py_None); + } + + PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment(); + KX_IPhysicsController *spc = GetPhysicsController(); + KX_GameObject *parent = GetParent(); + if (!spc && parent) + spc = parent->GetPhysicsController(); + if (parent) + parent->Release(); + + m_pHitObject = NULL; + if (propName) + m_testPropName = propName; + else + m_testPropName.SetLength(0); + 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) + { + 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(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; + } + // 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); +} + /* --------------------------------------------------------------------- * Some stuff taken from the header * --------------------------------------------------------------------- */ void KX_GameObject::Relink(GEN_Map<GEN_HashedPtr, void*> *map_parameter) { - /* intentionally empty ? */ + // we will relink the sensors and actuators that use object references + // if the object is part of the replicated hierarchy, use the new + // object reference instead + SCA_SensorList& sensorlist = GetSensors(); + SCA_SensorList::iterator sit; + for (sit=sensorlist.begin(); sit != sensorlist.end(); sit++) + { + (*sit)->Relink(map_parameter); + } + SCA_ActuatorList& actuatorlist = GetActuators(); + SCA_ActuatorList::iterator ait; + for (ait=actuatorlist.begin(); ait != actuatorlist.end(); ait++) + { + (*ait)->Relink(map_parameter); + } } +bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok) +{ + if (value==NULL) { + PyErr_SetString(PyExc_TypeError, "Error in ConvertPythonToGameObject, python pointer NULL, should never happen"); + *object = NULL; + return false; + } + + if (value==Py_None) { + *object = NULL; + + if (py_none_ok) { + return true; + } else { + PyErr_SetString(PyExc_TypeError, "Expected KX_GameObject or a string for a name of a KX_GameObject, None is invalid"); + return false; + } + return (py_none_ok ? true : false); + } + + if (PyString_Check(value)) { + *object = (KX_GameObject *)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String( PyString_AsString(value) )); + + if (*object) { + return true; + } else { + PyErr_SetString(PyExc_ValueError, "Requested name did not match any KX_GameObject"); + return false; + } + } + + if (PyObject_TypeCheck(value, &KX_GameObject::Type)) { + *object = static_cast<KX_GameObject*>(value); + return true; + } + + *object = NULL; + + if (py_none_ok) { + PyErr_SetString(PyExc_TypeError, "Expect a KX_GameObject, a string or None"); + } else { + PyErr_SetString(PyExc_TypeError, "Expect a KX_GameObject or a string"); + } + + return false; +} diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index c82ee9cfdab..20b15787d27 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -44,17 +44,21 @@ #include "MT_CmMatrix4x4.h" #include "GEN_Map.h" #include "GEN_HashedPtr.h" - -#define KX_FIXED_FRAME_PER_SEC 25.0f -#define KX_FIXED_SEC_PER_FRAME (1.0f / KX_FIXED_FRAME_PER_SEC) +#include "KX_Scene.h" +#include "KX_KetsjiEngine.h" /* for m_anim_framerate */ +#include "KX_IPhysicsController.h" /* for suspend/resume */ +#include "DNA_object_types.h" +#include "SCA_LogicManager.h" /* for ConvertPythonToGameObject to search object names */ #define KX_OB_DYNAMIC 1 //Forward declarations. struct KX_ClientObjectInfo; +class KX_RayCast; class RAS_MeshObject; class KX_IPhysicsController; - +class PHY_IPhysicsEnvironment; +struct Object; /** * KX_GameObject is the main class for dynamic objects. @@ -68,17 +72,28 @@ protected: KX_ClientObjectInfo* m_pClient_info; STR_String m_name; STR_String m_text; + 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; MT_CmMatrix4x4 m_OpenGL_4x4Matrix; @@ -125,6 +140,15 @@ public: GetParent( ); + /** + * Sets the parent of this object to a game object + */ + void SetParent(KX_Scene *scene, KX_GameObject *obj); + + /** + * Removes the parent of this object to a game object + */ + void RemoveParent(KX_Scene *scene); /** * Construct a game object. This class also inherits the @@ -235,8 +259,42 @@ public: /** * Return the linear velocity of the game object. */ - MT_Vector3 + MT_Vector3 GetLinearVelocity( + 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 + */ + MT_Scalar + GetMass(); + + /** + * Return the angular velocity of the game object. + */ + MT_Vector3 + GetAngularVelocity( + bool local=false + ); + + /** + * Align the object to a given normal. + */ + void + AlignAxisToVect( + const MT_Vector3& vect, + int axis = 2, + float fac = 1.0 ); /** @@ -259,6 +317,19 @@ public: /** + * @return a pointer to the physics environment in use during the game, for rayCasting + */ + PHY_IPhysicsEnvironment* GetPhysicsEnvironment() + { + return m_pPhysicsEnvironment; + } + + void SetPhysicsEnvironment(PHY_IPhysicsEnvironment* physicsEnvironment) + { + m_pPhysicsEnvironment = physicsEnvironment; + } + + /** * @return a pointer to the physics controller owned by this class. */ @@ -270,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 @@ -283,6 +362,9 @@ public: void NodeSetRelativeScale( const MT_Vector3& scale ); + // adapt local position so that world position is set to desired position + void NodeSetWorldPosition(const MT_Point3& trans); + void NodeUpdateGS( double time, @@ -320,6 +402,37 @@ public: } /** + * @section blender object accessor functions. + */ + + struct Object* GetBlenderObject( ) + { + return m_pBlenderObject; + } + + void SetBlenderObject( struct Object* obj) + { + m_pBlenderObject = obj; + } + + struct Object* GetBlenderGroupObject( ) + { + return m_pBlenderGroupObject; + } + + void SetBlenderGroupObject( struct Object* obj) + { + m_pBlenderGroupObject = obj; + } + + bool IsDupliGroup() + { + return (m_pBlenderObject && + (m_pBlenderObject->transflag & OB_DUPLIGROUP) && + m_pBlenderObject->dup_group != NULL) ? true : false; + } + + /** * Set the Scene graph node for this game object. * warning - it is your responsibility to make sure * all controllers look at this new node. You must @@ -337,7 +450,18 @@ public: { return m_bDyna; } - + + /** + * Check if this object has a vertex parent relationship + */ + bool IsVertexParent( ) + { + return (m_pSGNode && m_pSGNode->GetSGParent() && m_pSGNode->GetSGParent()->IsVertexParent()); + } + + bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); + bool NeedRayCast(KX_ClientObjectInfo* client); + /** * @section Physics accessors for this node. @@ -408,20 +532,29 @@ public: ); /** + * Function to set IPO option at start of IPO + */ + void + InitIPO( + bool ipo_as_force, + bool ipo_add, + bool ipo_local + ); + + /** * Odd function to update an ipo. ??? */ void UpdateIPO( float curframetime, - bool recurse, - bool ipo_as_force, - bool force_ipo_local + bool recurse ); /** * Updates Material Ipo data */ void UpdateMaterialData( + dword matname_hash, MT_Vector4 rgba, MT_Vector3 specrgb, MT_Scalar hard, @@ -434,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 ); /** @@ -506,42 +644,74 @@ 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 ); + /** + * Change the layer of the object (when it is added in another layer + * than the original layer) + */ + void + SetLayer( + int l + ); + + /** + * Get the object layer + */ + int + GetLayer( + void + ); /** + * Get the negative scaling state + */ + bool + IsNegativeScaling( + void + ) { return m_bIsNegativeScaling; } + + /** + * Is this a light? + */ + virtual bool + IsLight( + void + ) { return false; } + + /** * @section Logic bubbling methods. */ @@ -555,6 +725,32 @@ public: */ void Resume(void); + void SuspendDynamics(void) { + if (m_bSuspendDynamics) + { + return; + } + + if (m_pPhysicsController1) + { + m_pPhysicsController1->SuspendDynamics(); + } + m_bSuspendDynamics = true; + } + + void RestoreDynamics(void) { + if (!m_bSuspendDynamics) + { + return; + } + + if (m_pPhysicsController1) + { + m_pPhysicsController1->RestoreDynamics(); + } + m_bSuspendDynamics = false; + } + KX_ClientObjectInfo* getClientInfo() { return m_pClient_info; } /** * @section Python interface functions. @@ -573,39 +769,45 @@ public: PyObject *value ); // _setattr method - PyObject* - PySetPosition( - PyObject* self, - PyObject* args, - PyObject* kwds - ); - - static - PyObject* - sPySetPosition( - PyObject* self, - PyObject* args, - PyObject* kwds - ); - - KX_PYMETHOD(KX_GameObject,GetPosition); - KX_PYMETHOD(KX_GameObject,GetLinearVelocity); - KX_PYMETHOD(KX_GameObject,GetVelocity); - KX_PYMETHOD(KX_GameObject,GetMass); - KX_PYMETHOD(KX_GameObject,GetReactionForce); - KX_PYMETHOD(KX_GameObject,GetOrientation); - KX_PYMETHOD(KX_GameObject,SetOrientation); - KX_PYMETHOD(KX_GameObject,SetVisible); - KX_PYMETHOD(KX_GameObject,SuspendDynamics); - KX_PYMETHOD(KX_GameObject,RestoreDynamics); - KX_PYMETHOD(KX_GameObject,EnableRigidBody); - KX_PYMETHOD(KX_GameObject,DisableRigidBody); - KX_PYMETHOD(KX_GameObject,ApplyImpulse); - KX_PYMETHOD(KX_GameObject,SetCollisionMargin); - KX_PYMETHOD(KX_GameObject,GetMesh); - KX_PYMETHOD(KX_GameObject,GetParent); - KX_PYMETHOD(KX_GameObject,GetPhysicsId); + KX_PYMETHOD_NOARGS(KX_GameObject,GetPosition); + KX_PYMETHOD_O(KX_GameObject,SetPosition); + 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_VARARGS(KX_GameObject,SetVisible); + KX_PYMETHOD_NOARGS(KX_GameObject,GetState); + KX_PYMETHOD_O(KX_GameObject,SetState); + 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_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_VARARGS(KX_GameObject,GetMesh); + KX_PYMETHOD_NOARGS(KX_GameObject,GetPhysicsId); + KX_PYMETHOD_NOARGS(KX_GameObject,GetPropertyNames); + KX_PYMETHOD_O(KX_GameObject,ReplaceMesh); + KX_PYMETHOD_NOARGS(KX_GameObject,EndObject); + KX_PYMETHOD_DOC(KX_GameObject,rayCastTo); + KX_PYMETHOD_DOC(KX_GameObject,rayCast); KX_PYMETHOD_DOC(KX_GameObject,getDistanceTo); + KX_PYMETHOD_DOC(KX_GameObject,getVectTo); + private : /** @@ -623,5 +825,8 @@ private : }; +/* utility conversion function */ +bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok); + #endif //__KX_GAMEOBJECT diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.cpp b/source/gameengine/Ketsji/KX_IPO_SGController.cpp index bb4b75c6c4a..67d54cf0b0b 100644 --- a/source/gameengine/Ketsji/KX_IPO_SGController.cpp +++ b/source/gameengine/Ketsji/KX_IPO_SGController.cpp @@ -48,20 +48,24 @@ typedef unsigned long uint_ptr; #include "KX_ScalarInterpolator.h" #include "KX_GameObject.h" #include "KX_IPhysicsController.h" +#include "DNA_ipo_types.h" +#include "BLI_arithb.h" // All objects should start on frame 1! Will we ever need an object to // start on another frame, the 1.0 should change. KX_IpoSGController::KX_IpoSGController() -: m_modify_position(false), - m_modify_orientation(false), - m_modify_scaling(false), - m_ipo_as_force(false), - m_force_ipo_acts_local(false), +: m_ipo_as_force(false), + m_ipo_add(false), + m_ipo_local(false), m_modified(true), - m_ipotime(1.0) + m_ipo_start_initialized(false), + 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++) + m_ipo_channels_active[i] = false; } @@ -74,8 +78,23 @@ void KX_IpoSGController::SetOption( m_ipo_as_force = (value != 0); m_modified = true; break; - case SG_CONTR_IPO_FORCES_ACT_LOCAL: - m_force_ipo_acts_local = (value != 0); + case SG_CONTR_IPO_IPO_ADD: + m_ipo_add = (value != 0); + m_modified = true; + break; + case SG_CONTR_IPO_RESET: + if (m_ipo_start_initialized && value) { + m_ipo_start_initialized = false; + m_modified = true; + } + break; + case SG_CONTR_IPO_LOCAL: + if (value/* && ((SG_Node*)m_pObject)->GetSGParent() == NULL*/) { + // only accept local Ipo if the object has no parent + m_ipo_local = true; + } else { + m_ipo_local = false; + } m_modified = true; break; default: @@ -112,35 +131,200 @@ bool KX_IpoSGController::Update(double currentTime) } SG_Spatial* ob = (SG_Spatial*)m_pObject; - - if (m_modify_position) { - if (m_ipo_as_force) { - - if (m_game_object && ob) { - m_game_object->GetPhysicsController()->ApplyForce(m_force_ipo_acts_local ? + + //initialization on the first frame of the IPO + if (! m_ipo_start_initialized && currentTime > 0.0) { + m_ipo_start_point = ob->GetLocalPosition(); + 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? + if (m_ipo_channels_active[OB_LOC_X] || m_ipo_channels_active[OB_LOC_Y] || m_ipo_channels_active[OB_LOC_Z] || m_ipo_channels_active[OB_DLOC_X] || m_ipo_channels_active[OB_DLOC_Y] || m_ipo_channels_active[OB_DLOC_Z]) + { + if (m_ipo_as_force == true) + { + if (m_game_object && ob && m_game_object->GetPhysicsController()) + { + m_game_object->GetPhysicsController()->ApplyForce(m_ipo_local ? ob->GetWorldOrientation() * m_ipo_xform.GetPosition() : m_ipo_xform.GetPosition(), false); } - - } else { - ob->SetLocalPosition(m_ipo_xform.GetPosition()); + } + else + { + // Local ipo should be defined with the object position at (0,0,0) + // Local transform is applied to the object based on initial position + MT_Point3 newPosition(0.0,0.0,0.0); + + if (!m_ipo_add) + newPosition = ob->GetLocalPosition(); + //apply separate IPO channels if there is any data in them + //Loc and dLoc act by themselves or are additive + //LocX and dLocX + if (m_ipo_channels_active[OB_LOC_X]) { + newPosition[0] = (m_ipo_channels_active[OB_DLOC_X] ? m_ipo_xform.GetPosition()[0] + m_ipo_xform.GetDeltaPosition()[0] : m_ipo_xform.GetPosition()[0]); + } + else if (m_ipo_channels_active[OB_DLOC_X] && m_ipo_start_initialized) { + newPosition[0] = (((!m_ipo_add)?m_ipo_start_point[0]:0.0) + m_ipo_xform.GetDeltaPosition()[0]); + } + //LocY and dLocY + if (m_ipo_channels_active[OB_LOC_Y]) { + newPosition[1] = (m_ipo_channels_active[OB_DLOC_Y] ? m_ipo_xform.GetPosition()[1] + m_ipo_xform.GetDeltaPosition()[1] : m_ipo_xform.GetPosition()[1]); + } + else if (m_ipo_channels_active[OB_DLOC_Y] && m_ipo_start_initialized) { + newPosition[1] = (((!m_ipo_add)?m_ipo_start_point[1]:0.0) + m_ipo_xform.GetDeltaPosition()[1]); + } + //LocZ and dLocZ + if (m_ipo_channels_active[OB_LOC_Z]) { + newPosition[2] = (m_ipo_channels_active[OB_DLOC_Z] ? m_ipo_xform.GetPosition()[2] + m_ipo_xform.GetDeltaPosition()[2] : m_ipo_xform.GetPosition()[2]); + } + else if (m_ipo_channels_active[OB_DLOC_Z] && m_ipo_start_initialized) { + newPosition[2] = (((!m_ipo_add)?m_ipo_start_point[2]:0.0) + m_ipo_xform.GetDeltaPosition()[2]); + } + if (m_ipo_add) { + if (m_ipo_local) + newPosition = m_ipo_start_point + m_ipo_start_scale*(m_ipo_start_orient*newPosition); + else + newPosition = m_ipo_start_point + newPosition; + } + ob->SetLocalPosition(newPosition); } } - if (m_modify_orientation) { + //modifies orientation? + if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z] || m_ipo_channels_active[OB_DROT_X] || m_ipo_channels_active[OB_DROT_Y] || m_ipo_channels_active[OB_DROT_Z]) { if (m_ipo_as_force) { if (m_game_object && ob) { - m_game_object->ApplyTorque(m_force_ipo_acts_local ? + m_game_object->ApplyTorque(m_ipo_local ? ob->GetWorldOrientation() * m_ipo_xform.GetEulerAngles() : m_ipo_xform.GetEulerAngles(), false); } + } else if (m_ipo_add) { + if (m_ipo_start_initialized) { + double yaw=0, pitch=0, roll=0; //delta Euler angles - } else { - ob->SetLocalOrientation(MT_Matrix3x3(m_ipo_xform.GetEulerAngles())); + //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]; + + 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 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? + if (m_ipo_channels_active[OB_SIZE_X] || m_ipo_channels_active[OB_SIZE_Y] || m_ipo_channels_active[OB_SIZE_Z] || m_ipo_channels_active[OB_DSIZE_X] || m_ipo_channels_active[OB_DSIZE_Y] || m_ipo_channels_active[OB_DSIZE_Z]) { + //default is no scale change + MT_Vector3 newScale(1.0,1.0,1.0); + if (!m_ipo_add) + newScale = ob->GetLocalScale(); + + if (m_ipo_channels_active[OB_SIZE_X]) { + newScale[0] = (m_ipo_channels_active[OB_DSIZE_X] ? (m_ipo_xform.GetScaling()[0] + m_ipo_xform.GetDeltaScaling()[0]) : m_ipo_xform.GetScaling()[0]); + } + else if (m_ipo_channels_active[OB_DSIZE_X] && m_ipo_start_initialized) { + newScale[0] = (m_ipo_xform.GetDeltaScaling()[0] + ((!m_ipo_add)?m_ipo_start_scale[0]:0.0)); + } + + //RotY dRotY + if (m_ipo_channels_active[OB_SIZE_Y]) { + newScale[1] = (m_ipo_channels_active[OB_DSIZE_Y] ? (m_ipo_xform.GetScaling()[1] + m_ipo_xform.GetDeltaScaling()[1]): m_ipo_xform.GetScaling()[1]); + } + else if (m_ipo_channels_active[OB_DSIZE_Y] && m_ipo_start_initialized) { + newScale[1] = (m_ipo_xform.GetDeltaScaling()[1] + ((!m_ipo_add)?m_ipo_start_scale[1]:0.0)); } + + //RotZ and dRotZ + if (m_ipo_channels_active[OB_SIZE_Z]) { + newScale[2] = (m_ipo_channels_active[OB_DSIZE_Z] ? (m_ipo_xform.GetScaling()[2] + m_ipo_xform.GetDeltaScaling()[2]) : m_ipo_xform.GetScaling()[2]); + } + else if (m_ipo_channels_active[OB_DSIZE_Z] && m_ipo_start_initialized) { + newScale[2] = (m_ipo_xform.GetDeltaScaling()[2] + ((!m_ipo_add)?m_ipo_start_scale[2]:1.0)); + } + + if (m_ipo_add) { + newScale = m_ipo_start_scale * newScale; + } + + ob->SetLocalScale(newScale); } - if (m_modify_scaling) - ob->SetLocalScale(m_ipo_xform.GetScaling()); m_modified=false; } diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.h b/source/gameengine/Ketsji/KX_IPO_SGController.h index a010e8e3e6c..031b74294ce 100644 --- a/source/gameengine/Ketsji/KX_IPO_SGController.h +++ b/source/gameengine/Ketsji/KX_IPO_SGController.h @@ -35,27 +35,49 @@ #include "KX_IPOTransform.h" #include "KX_IInterpolator.h" +#define KX_MAX_IPO_CHANNELS 19 //note- [0] is not used + class KX_IpoSGController : public SG_Controller { KX_IPOTransform m_ipo_xform; T_InterpolatorList m_interpolators; - /* Why not bools? */ - short m_modify_position : 1; - short m_modify_orientation : 1; - short m_modify_scaling : 1; + + /** Flag for each IPO channel that can be applied to a game object */ + bool m_ipo_channels_active[KX_MAX_IPO_CHANNELS]; /** Interpret the ipo as a force rather than a displacement? */ bool m_ipo_as_force; - /** Ipo-as-force acts in local rather than in global coordinates? */ - bool m_force_ipo_acts_local; + /** Add Ipo curve to current loc/rot/scale */ + bool m_ipo_add; + /** Ipo must be applied in local coordinate rather than in global coordinates (used for force and Add mode)*/ + bool m_ipo_local; + /** Were settings altered since the last update? */ bool m_modified; /** Local time of this ipo.*/ double m_ipotime; + /** Location of the object when the IPO is first fired (for local transformations) */ + class MT_Point3 m_ipo_start_point; + + /** Orientation of the object when the IPO is first fired (for local transformations) */ + class MT_Matrix3x3 m_ipo_start_orient; + + /** Scale of the object when the IPO is first fired (for local transformations) */ + class MT_Vector3 m_ipo_start_scale; + + /** 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; @@ -77,16 +99,12 @@ public: /** Set reference to the corresponding game object. */ void SetGameObject(class KX_GameObject*); - void SetModifyPosition(bool modifypos) { - m_modify_position=modifypos; - } - void SetModifyOrientation(bool modifyorient) { - m_modify_orientation=modifyorient; - } - void SetModifyScaling(bool modifyscale) { - m_modify_scaling=modifyscale; + void SetIPOChannelActive(int index, bool value) { + //indexes found in makesdna\DNA_ipo_types.h + m_ipo_channels_active[index] = value; } + KX_IPOTransform& GetIPOTransform() { return m_ipo_xform; @@ -102,3 +120,4 @@ public: #endif //__IPO_SGCONTROLLER_H + diff --git a/source/gameengine/Ketsji/KX_IPhysicsController.h b/source/gameengine/Ketsji/KX_IPhysicsController.h index 009db40d3e8..4ea283e9f98 100644 --- a/source/gameengine/Ketsji/KX_IPhysicsController.h +++ b/source/gameengine/Ketsji/KX_IPhysicsController.h @@ -64,20 +64,22 @@ public: virtual void ApplyTorque(const MT_Vector3& torque,bool local)=0; virtual void ApplyForce(const MT_Vector3& force,bool local)=0; virtual MT_Vector3 GetLinearVelocity()=0; + virtual MT_Vector3 GetAngularVelocity()=0; virtual MT_Vector3 GetVelocity(const MT_Point3& pos)=0; virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local)=0; virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local)=0; virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) = 0; virtual void getOrientation(MT_Quaternion& orn)=0; - virtual void setOrientation(const MT_Quaternion& orn)=0; + virtual void setOrientation(const MT_Matrix3x3& orn)=0; + //virtual void setOrientation(const MT_Quaternion& orn)=0; virtual void setPosition(const MT_Point3& pos)=0; virtual void setScaling(const MT_Vector3& scaling)=0; virtual MT_Scalar GetMass()=0; virtual MT_Vector3 getReactionForce()=0; virtual void setRigidBody(bool rigid)=0; - virtual void SuspendDynamics()=0; + virtual void SuspendDynamics(bool ghost=false)=0; virtual void RestoreDynamics()=0; virtual SG_Controller* GetReplica(class SG_Node* destnode)=0; @@ -86,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 cb749801827..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 { @@ -52,6 +54,8 @@ public: class RAS_IRenderTools* rendertools, class RAS_ICanvas* canvas)=0; + virtual void RemoveScene(class KX_Scene *scene)=0; + virtual void SetAlwaysUseExpandFraming(bool to_what) = 0; virtual void SetNewFileName(const STR_String& filename) = 0; @@ -72,6 +76,11 @@ public: virtual void SetMaterials(bool val) =0; virtual bool GetMaterials()=0; + // 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 3af1316ba5d..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> @@ -59,49 +60,17 @@ STR_String KX_IpoActuator::S_KX_ACT_IPO_FROM_PROP_STRING = "FromProp"; /* ------------------------------------------------------------------------- */ /* Native functions */ /* ------------------------------------------------------------------------- */ -/** Another poltergeist? This seems to be a very transient class... */ -class CIpoAction : public CAction -{ - float m_curtime; - bool m_recurse; - KX_GameObject* m_gameobj; - bool m_ipo_as_force; - bool m_force_ipo_local; - -public: - CIpoAction(KX_GameObject* gameobj, - float curtime, - bool recurse, - bool ipo_as_force, - bool force_ipo_local) : - m_curtime(curtime) , - m_recurse(recurse), - m_gameobj(gameobj), - m_ipo_as_force(ipo_as_force), - m_force_ipo_local(force_ipo_local) - { - /* intentionally empty */ - }; - - virtual void Execute() const - { - m_gameobj->UpdateIPO( - m_curtime, - m_recurse, - m_ipo_as_force, - m_force_ipo_local); - }; - -}; KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj, const STR_String& propname, + const STR_String& framePropname, float starttime, float endtime, bool recurse, int acttype, bool ipo_as_force, - bool force_ipo_local, + bool ipo_add, + bool ipo_local, PyTypeObject* T) : SCA_IActuator(gameobj,T), m_bNegativeEvent(false), @@ -111,8 +80,10 @@ 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_force_ipo_local(force_ipo_local), + m_ipo_add(ipo_add), + m_ipo_local(ipo_local), m_type((IpoActType)acttype) { m_starttime = -2.0*fabs(m_endframe - m_startframe) - 1.0; @@ -160,18 +131,17 @@ bool KX_IpoActuator::ClampLocalTime() void KX_IpoActuator::SetStartTime(float curtime) { - float direction = m_startframe < m_endframe ? 1.0 : -1.0; + 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_FIXED_FRAME_PER_SEC; + m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate(); else - m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_FIXED_FRAME_PER_SEC; + m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate(); } void KX_IpoActuator::SetLocalTime(float curtime) { - float delta_time = ((curtime - m_starttime) - KX_KetsjiEngine::GetSuspendedDelta())*KX_FIXED_FRAME_PER_SEC; + 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 @@ -195,36 +165,28 @@ bool KX_IpoActuator::Update(double curtime, bool frame) // maybe there are events for us in the queue ! bool bNegativeEvent = false; int numevents = 0; + bool bIpoStart = false; + + curtime -= KX_KetsjiEngine::GetSuspendedDelta(); if (frame) { numevents = m_events.size(); - for (vector<CValue*>::iterator i=m_events.end(); !(i==m_events.begin());) - { - --i; - if ((*i)->GetNumber() == 0.0f) - bNegativeEvent = true; - - (*i)->Release(); - } - m_events.clear(); - - if (m_type != KX_ACT_IPO_PLAY) - { - if (bNegativeEvent) - RemoveAllEvents(); - } + bNegativeEvent = IsNegativeEvent(); + RemoveAllEvents(); } - double start_smaller_then_end = ( m_startframe < m_endframe ? 1.0 : -1.0); + float start_smaller_then_end = ( m_startframe < m_endframe ? 1.0f : -1.0f); bool result=true; if (!bNegativeEvent) { - if (m_starttime < -2.0*start_smaller_then_end*(m_endframe - m_startframe)) + if (m_starttime < -2.0f*start_smaller_then_end*(m_endframe - m_startframe)) { - m_starttime = curtime - KX_KetsjiEngine::GetSuspendedDelta(); + // start for all Ipo, initial start for LOOP_STOP + m_starttime = curtime; m_bIpoPlaying = true; + bIpoStart = true; } } @@ -235,17 +197,10 @@ bool KX_IpoActuator::Update(double curtime, bool frame) { // Check if playing forwards. result = ! finished - if (!bNegativeEvent) - { - if (start_smaller_then_end > 0.0) - result = (m_localtime < m_endframe && !(m_localtime == m_startframe && bNegativeEvent)); - else - result = (m_localtime > m_endframe && !(m_localtime == m_startframe && bNegativeEvent)); - } + if (start_smaller_then_end > 0.f) + result = (m_localtime < m_endframe && m_bIpoPlaying); else - { - result = (m_bIpoPlaying && (m_localtime < m_endframe)); - } + result = (m_localtime > m_endframe && m_bIpoPlaying); if (result) { @@ -253,18 +208,13 @@ bool KX_IpoActuator::Update(double curtime, bool frame) /* Perform clamping */ ClampLocalTime(); - - CIpoAction ipoaction( - (KX_GameObject*)GetParent(), - m_localtime, - m_recurse, - m_ipo_as_force, - m_force_ipo_local); - GetParent()->Execute(ipoaction); + + if (bIpoStart) + ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); + ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); } else { m_localtime=m_startframe; - SetStartTime(curtime); m_direction=1; } break; @@ -272,7 +222,7 @@ bool KX_IpoActuator::Update(double curtime, bool frame) case KX_ACT_IPO_PINGPONG: { result = true; - if (bNegativeEvent && ((m_localtime == m_startframe )|| (m_localtime == m_endframe))) + if (bNegativeEvent && !m_bIpoPlaying) result = false; else SetLocalTime(curtime); @@ -283,39 +233,35 @@ bool KX_IpoActuator::Update(double curtime, bool frame) m_direction = -m_direction; } - CIpoAction ipoaction( - (KX_GameObject*) GetParent(), - m_localtime, - m_recurse, - m_ipo_as_force, - m_force_ipo_local); - GetParent()->Execute(ipoaction); + if (bIpoStart && m_direction > 0) + ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); + ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); break; } case KX_ACT_IPO_FLIPPER: { - result = !(bNegativeEvent && (m_localtime == m_startframe)); + if (bNegativeEvent && !m_bIpoPlaying) + result = false; if (numevents) { + float oldDirection = m_direction; if (bNegativeEvent) m_direction = -1; else m_direction = 1; - SetStartTime(curtime); + if (m_direction != oldDirection) + // changing direction, reset start time + SetStartTime(curtime); } SetLocalTime(curtime); if (ClampLocalTime() && m_localtime == m_startframe) result = false; - - CIpoAction ipoaction( - (KX_GameObject*) GetParent(), - m_localtime, - m_recurse, - m_ipo_as_force, - m_force_ipo_local); - GetParent()->Execute(ipoaction); + + if (bIpoStart) + ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); + ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); break; } @@ -329,18 +275,26 @@ bool KX_IpoActuator::Update(double curtime, bool frame) m_bNegativeEvent = false; numevents = 0; } - SetStartTime(curtime); + if (!m_bIpoPlaying) + { + // Ipo was stopped, make sure we will restart from where it stopped + SetStartTime(curtime); + if (!bNegativeEvent) + // positive signal will restart the Ipo + m_bIpoPlaying = true; + } + } // fall through to loopend, and quit the ipo animation immediatly } case KX_ACT_IPO_LOOPEND: { if (numevents){ - if (bNegativeEvent){ + if (bNegativeEvent && m_bIpoPlaying){ m_bNegativeEvent = true; } } - if (bNegativeEvent && m_localtime == m_startframe){ + if (bNegativeEvent && !m_bIpoPlaying){ result = false; } else @@ -353,8 +307,12 @@ bool KX_IpoActuator::Update(double curtime, bool frame) if (!m_bNegativeEvent){ /* Perform wraparound */ SetLocalTime(curtime); - m_localtime = m_startframe + fmod(m_localtime, m_startframe - m_endframe); + if (start_smaller_then_end > 0.f) + m_localtime = m_startframe + fmod(m_localtime - m_startframe, m_endframe - m_startframe); + else + m_localtime = m_startframe - fmod(m_startframe - m_localtime, m_startframe - m_endframe); SetStartTime(curtime); + bIpoStart = true; } else { @@ -366,13 +324,9 @@ bool KX_IpoActuator::Update(double curtime, bool frame) } } - CIpoAction ipoaction( - (KX_GameObject*) GetParent(), - m_localtime, - m_recurse, - m_ipo_as_force, - m_force_ipo_local); - GetParent()->Execute(ipoaction); + if (m_bIpoPlaying && bIpoStart) + ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); + ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); break; } @@ -392,14 +346,9 @@ bool KX_IpoActuator::Update(double curtime, bool frame) { m_localtime = propval->GetNumber(); - CIpoAction ipoaction( - (KX_GameObject*) GetParent(), - m_localtime, - m_recurse, - m_ipo_as_force, - m_force_ipo_local); - GetParent()->Execute(ipoaction); - + if (bIpoStart) + ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); + ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); } else { result = false; @@ -410,9 +359,26 @@ bool KX_IpoActuator::Update(double curtime, bool frame) default: result = false; } - - if (!result && m_type != KX_ACT_IPO_LOOPSTOP) - m_starttime = -2.0*start_smaller_then_end*(m_endframe - m_startframe) - 1.0; + + /* 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) + m_starttime = -2.0*start_smaller_then_end*(m_endframe - m_startframe) - 1.0; + m_bIpoPlaying = false; + } return result; } @@ -474,30 +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_VARARGS, GetStart_doc}, - {"setEnd", (PyCFunction) KX_IpoActuator::sPySetEnd, - METH_VARARGS, SetEnd_doc}, - {"getEnd", (PyCFunction) KX_IpoActuator::sPyGetEnd, - METH_VARARGS, GetEnd_doc}, - {"setIpoAsForce", (PyCFunction) KX_IpoActuator::sPySetIpoAsForce, - METH_VARARGS, SetIpoAsForce_doc}, - {"getIpoAsForce", (PyCFunction) KX_IpoActuator::sPyGetIpoAsForce, - METH_VARARGS, GetIpoAsForce_doc}, - {"setType", (PyCFunction) KX_IpoActuator::sPySetType, - METH_VARARGS, SetType_doc}, - {"getType", (PyCFunction) KX_IpoActuator::sPyGetType, - METH_VARARGS, GetType_doc}, - {"setForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPySetForceIpoActsLocal, - METH_VARARGS, SetForceIpoActsLocal_doc}, - {"getForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPyGetForceIpoActsLocal, - METH_VARARGS, 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 }; @@ -508,12 +464,12 @@ PyObject* KX_IpoActuator::_getattr(const STR_String& attr) { /* set --------------------------------------------------------------------- */ -char KX_IpoActuator::Set_doc[] = -"set(mode, startframe, endframe, force?)\n" -"\t - mode: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n" +const char KX_IpoActuator::Set_doc[] = +"set(type, startframe, endframe, mode?)\n" +"\t - type: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n" "\t - startframe: first frame to use (int)\n" "\t - endframe : last frame to use (int)\n" -"\t - force? : interpret this ipo as a force? (KX_TRUE, KX_FALSE)" +"\t - mode? : special mode (0=normal, 1=interpret location as force, 2=additive)" "\tSet the properties of the actuator.\n"; PyObject* KX_IpoActuator::PySet(PyObject* self, PyObject* args, @@ -540,7 +496,8 @@ PyObject* KX_IpoActuator::PySet(PyObject* self, m_type = modenum; m_startframe = startFrame; m_endframe = stopFrame; - m_ipo_as_force = PyArgToBool(forceToggle); + m_ipo_as_force = forceToggle == 1; + m_ipo_add = forceToggle == 2; break; default: ; /* error */ @@ -550,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"; @@ -570,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"; @@ -587,17 +544,15 @@ 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, - PyObject* args, - PyObject* kwds) { +PyObject* KX_IpoActuator::PyGetStart(PyObject* self) { return PyFloat_FromDouble(m_startframe); } /* 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"; @@ -614,17 +569,15 @@ 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, - PyObject* args, - PyObject* kwds) { +PyObject* KX_IpoActuator::PyGetEnd(PyObject* self) { return PyFloat_FromDouble(m_endframe); } /* 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"; @@ -638,21 +591,49 @@ PyObject* KX_IpoActuator::PySetIpoAsForce(PyObject* self, } m_ipo_as_force = PyArgToBool(boolArg); + if (m_ipo_as_force) + m_ipo_add = false; 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, - PyObject* args, - PyObject* kwds) { +PyObject* KX_IpoActuator::PyGetIpoAsForce(PyObject* self) { return BoolToPyArg(m_ipo_as_force); } +/* 6. setIpoAsForce: */ +const char KX_IpoActuator::SetIpoAdd_doc[] = +"setIpoAdd(add?)\n" +"\t - add? : add flag (KX_TRUE, KX_FALSE)\n" +"\tSet whether to interpret the ipo as additive rather than absolute.\n"; +PyObject* KX_IpoActuator::PySetIpoAdd(PyObject* self, + PyObject* args, + PyObject* kwds) { + int boolArg; + + if (!PyArg_ParseTuple(args, "i", &boolArg)) { + return NULL; + } + + m_ipo_add = PyArgToBool(boolArg); + if (m_ipo_add) + m_ipo_as_force = false; + + Py_Return; +} +/* 7. getIpoAsForce: */ +const char KX_IpoActuator::GetIpoAdd_doc[] = +"getIpoAsAdd()\n" +"\tReturns whether to interpret the ipo as additive rather than absolute.\n"; +PyObject* KX_IpoActuator::PyGetIpoAdd(PyObject* self) { + return BoolToPyArg(m_ipo_add); +} + /* 8. setType: */ -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"; @@ -673,17 +654,15 @@ 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, - PyObject* args, - PyObject* kwds) { +PyObject* KX_IpoActuator::PyGetType(PyObject* self) { return PyInt_FromLong(m_type); } /* 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" @@ -698,19 +677,17 @@ PyObject* KX_IpoActuator::PySetForceIpoActsLocal(PyObject* self, return NULL; } - m_force_ipo_local = PyArgToBool(boolArg); + m_ipo_local = PyArgToBool(boolArg); 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"; -PyObject* KX_IpoActuator::PyGetForceIpoActsLocal(PyObject* self, - PyObject* args, - PyObject* kwds) { - return BoolToPyArg(m_force_ipo_local); +PyObject* KX_IpoActuator::PyGetForceIpoActsLocal(PyObject* self) { + return BoolToPyArg(m_ipo_local); } diff --git a/source/gameengine/Ketsji/KX_IpoActuator.h b/source/gameengine/Ketsji/KX_IpoActuator.h index 79e8daa3f87..8e5baed0530 100644 --- a/source/gameengine/Ketsji/KX_IpoActuator.h +++ b/source/gameengine/Ketsji/KX_IpoActuator.h @@ -72,11 +72,17 @@ 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; - /** Apply a force-ipo locally? */ - bool m_force_ipo_local; + /** Add Ipo curve to current loc/rot/scale */ + bool m_ipo_add; + + /** The Ipo curve is applied in local coordinates */ + bool m_ipo_local; bool m_bIpoPlaying; @@ -108,12 +114,14 @@ public: KX_IpoActuator(SCA_IObject* gameobj, const STR_String& propname, + const STR_String& framePropname, float starttime, float endtime, bool recurse, int acttype, bool ipo_as_force, - bool force_ipo_local, + bool ipo_add, + bool ipo_local, PyTypeObject* T=&Type); virtual ~KX_IpoActuator() {}; @@ -139,15 +147,17 @@ public: KX_PYMETHOD_DOC(KX_IpoActuator,SetProperty); /* KX_PYMETHOD_DOC(KX_IpoActuator,SetKey2Key); */ KX_PYMETHOD_DOC(KX_IpoActuator,SetStart); - KX_PYMETHOD_DOC(KX_IpoActuator,GetStart); + KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetStart); KX_PYMETHOD_DOC(KX_IpoActuator,SetEnd); - KX_PYMETHOD_DOC(KX_IpoActuator,GetEnd); + KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetEnd); KX_PYMETHOD_DOC(KX_IpoActuator,SetIpoAsForce); - KX_PYMETHOD_DOC(KX_IpoActuator,GetIpoAsForce); + KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetIpoAsForce); + KX_PYMETHOD_DOC(KX_IpoActuator,SetIpoAdd); + KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetIpoAdd); KX_PYMETHOD_DOC(KX_IpoActuator,SetType); - KX_PYMETHOD_DOC(KX_IpoActuator,GetType); + KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetType); KX_PYMETHOD_DOC(KX_IpoActuator,SetForceIpoActsLocal); - KX_PYMETHOD_DOC(KX_IpoActuator,GetForceIpoActsLocal); + KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetForceIpoActsLocal); }; diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 64bfa90d4d6..8bcda4479e1 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -55,6 +55,7 @@ #include "KX_Scene.h" #include "MT_CmMatrix4x4.h" #include "KX_Camera.h" +#include "KX_Light.h" #include "KX_PythonInit.h" #include "KX_PyConstraintBinding.h" #include "PHY_IPhysicsEnvironment.h" @@ -71,6 +72,7 @@ #include "KX_TimeCategoryLogger.h" #include "RAS_FramingManager.h" +#include "stdio.h" // If define: little test for Nzc: guarded drawing. If the canvas is // not valid, skip rendering this frame. @@ -91,9 +93,10 @@ const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = { }; 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; /** @@ -116,7 +119,6 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_bInitialized(false), m_activecam(0), m_bFixedTime(false), - m_game2ipo(false), m_firstframe(true), @@ -133,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), @@ -146,6 +150,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_showBackground(false), m_show_debug_properties(false), + m_game2ipo(false), + // Default behavior is to hide the cursor every frame. m_hideCursor(false), @@ -229,7 +235,10 @@ void KX_KetsjiEngine::SetRasterizer(RAS_IRasterizer* rasterizer) } - +/* + * At the moment the GameLogic module is imported into 'pythondictionary' after this function is called. + * if this function ever changes to assign a copy, make sure the game logic module is imported into this dictionary before hand. + */ void KX_KetsjiEngine::SetPythonDictionary(PyObject* pythondictionary) { MT_assert(pythondictionary); @@ -269,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_rasterizer->BeginFrame(m_drawingmode , m_kxsystem->GetTimeInSeconds()); + m_rendertools->BeginFrame(m_rasterizer); - 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); + return true; } - return result; + return false; } @@ -304,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()); @@ -315,8 +373,6 @@ void KX_KetsjiEngine::EndFrame() m_canvas->EndDraw(); - - } //#include "PIL_time.h" @@ -414,7 +470,7 @@ else m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); // set Python hooks for each scene PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); - PHY_SetActiveScene(scene); + KX_SetActiveScene(scene); scene->GetPhysicsEnvironment()->endFrame(); @@ -512,7 +568,7 @@ else // set Python hooks for each scene PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); - PHY_SetActiveScene(scene); + KX_SetActiveScene(scene); m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); scene->UpdateParents(m_clockTime); @@ -595,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); @@ -613,25 +669,25 @@ void KX_KetsjiEngine::Render() // pass the scene's worldsettings to the rasterizer SetWorldSettings(scene->GetWorldInfo()); + // shadow buffers + RenderShadowBuffers(scene); + // Avoid drawing the scene with the active camera twice when it's viewport is enabled - if(!cam->GetViewport()) + if(cam && !cam->GetViewport()) { if (scene->IsClearingZBuffer()) m_rasterizer->ClearDepthBuffer(); m_rendertools->SetAuxilaryClientInfo(scene); - //Initialize scene viewport. - SetupRenderFrame(scene, cam); - // do the rendering RenderFrame(scene, cam); } - set<class KX_Camera*>* cameras = scene->GetCameras(); + list<class KX_Camera*>* cameras = scene->GetCameras(); // Draw the scene once for each camera with an enabled viewport - set<KX_Camera*>::iterator it = cameras->begin(); + list<KX_Camera*>::iterator it = cameras->begin(); while(it != cameras->end()) { if((*it)->GetViewport()) @@ -641,9 +697,6 @@ void KX_KetsjiEngine::Render() m_rendertools->SetAuxilaryClientInfo(scene); - //Initialize scene viewport. - SetupRenderFrame(scene, (*it)); - // do the rendering RenderFrame(scene, (*it)); } @@ -676,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); @@ -839,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 @@ -848,14 +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->GetViewport()) { - viewport.SetLeft(cam->GetViewportLeft()); - viewport.SetBottom(cam->GetViewportBottom()); - viewport.SetRight(cam->GetViewportRight()); - viewport.SetTop(cam->GetViewportTop()); + // 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); + + RAS_FramingManager::ComputeViewport( + scene->GetFramingType(), + userviewport, + viewport + ); + + area = userviewport; } else if ( m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho ) { RAS_FramingManager::ComputeViewport( @@ -863,42 +929,95 @@ 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())); + + area = m_canvas->GetDisplayArea(); } - // store the computed viewport in the scene +} - scene->SetSceneViewport(viewport); +void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) +{ + CListValue *objectlist = scene->GetObjectList(); + int i, drawmode; - // set the viewport for this frame and scene - m_canvas->SetViewPort( - viewport.GetLeft(), - viewport.GetBottom(), - viewport.GetRight(), - viewport.GetTop() - ); + 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(); + + if(m_drawingmode == RAS_IRasterizer::KX_TEXTURED && light->HasShadowBuffer()) { + /* make temporary camera */ + RAS_CameraData camdata = RAS_CameraData(); + KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, false); + cam->SetName("__shadow__cam__"); + + MT_Transform camtrans; + + /* switch drawmode for speed */ + drawmode = m_rasterizer->GetDrawingMode(); + m_rasterizer->SetDrawingMode(RAS_IRasterizer::KX_SHADOW); + + /* binds framebuffer object, sets up camera .. */ + light->BindShadowBuffer(m_rasterizer, cam, camtrans); + /* update scene */ + scene->UpdateMeshTransformations(); + scene->CalculateVisibleMeshes(m_rasterizer, cam, light->GetShadowLayer()); + + /* render */ + m_rasterizer->ClearDepthBuffer(); + scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools); + + /* unbind framebuffer object, restore drawmode, free camera */ + light->UnbindShadowBuffer(m_rasterizer); + m_rasterizer->SetDrawingMode(drawmode); + cam->Release(); + } + } +} // update graphics void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) { - float left, right, bottom, top, nearfrust, farfrust; + 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() ) @@ -908,11 +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; @@ -920,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, @@ -936,8 +1061,8 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) farfrust = frustum.camfar; MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix( - left, right, bottom, top, nearfrust, farfrust); - + left, right, bottom, top, nearfrust, farfrust, focallength); + cam->SetProjectionMatrix(projmat); // Otherwise the projection matrix for each eye will be the same... @@ -963,13 +1088,18 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) scene->CalculateVisibleMeshes(m_rasterizer,cam); scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools); + + PostRenderFrame(); +} +void KX_KetsjiEngine::PostRenderFrame() +{ + m_rendertools->PushMatrix(); + m_rendertools->Render2DFilters(m_canvas); m_rendertools->MotionBlur(m_rasterizer); - + m_rendertools->PopMatrix(); } - - void KX_KetsjiEngine::StopEngine() { if (m_bInitialized) @@ -985,7 +1115,7 @@ void KX_KetsjiEngine::StopEngine() for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++) { KX_Scene* scene = *sceneit; - delete scene; + m_sceneconverter->RemoveScene(scene); } m_scenes.clear(); @@ -1039,6 +1169,8 @@ void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene) scene->SetActiveCamera(activecam); scene->GetObjectList()->Add(activecam->AddRef()); scene->GetRootParentList()->Add(activecam->AddRef()); + //done with activecam + activecam->Release(); } scene->UpdateParents(0.0); @@ -1111,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; + } + } } } } @@ -1207,7 +1369,7 @@ void KX_KetsjiEngine::RemoveScheduledScenes() KX_Scene* scene = *sceneit; if (scene->GetName()==scenename) { - delete scene; + m_sceneconverter->RemoveScene(scene); m_scenes.erase(sceneit); break; } @@ -1221,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, @@ -1305,7 +1468,7 @@ void KX_KetsjiEngine::ReplaceScheduledScenes() KX_Scene* scene = *sceneit; if (scene->GetName() == oldscenename) { - delete scene; + m_sceneconverter->RemoveScene(scene); KX_Scene* tmpscene = CreateScene(newscenename); m_scenes[i]=tmpscene; PostProcessScene(tmpscene); @@ -1372,6 +1535,26 @@ void KX_KetsjiEngine::SetTicRate(double ticrate) m_ticrate = ticrate; } +double KX_KetsjiEngine::GetAnimFrameRate() +{ + return m_anim_framerate; +} + +double KX_KetsjiEngine::GetClockTime(void) const +{ + return m_clockTime; +} + +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; @@ -1464,3 +1647,4 @@ void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const } + diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index e727452423b..4184202c518 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -103,6 +103,7 @@ private: double m_remainingTime; static double m_ticrate; + static double m_anim_framerate; /* for animation playback only - ipo and action */ static double m_suspendedtime; static double m_suspendeddelta; @@ -123,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; @@ -148,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? */ @@ -174,9 +179,10 @@ 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(); + void RenderShadowBuffers(KX_Scene *scene); void SetBackGround(KX_WorldInfo* worldinfo); void SetWorldSettings(KX_WorldInfo* worldinfo); void DoSound(KX_Scene* scene); @@ -198,6 +204,8 @@ public: void SetSceneConverter(KX_ISceneConverter* sceneconverter); void SetGame2IpoMode(bool game2ipo,int startFrame); + RAS_IRasterizer* GetRasterizer(){return m_rasterizer;}; + ///returns true if an update happened to indicate -> Render bool NextFrame(); void Render(); @@ -221,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); @@ -229,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. @@ -243,6 +254,11 @@ public: bool GetUseFixedTime(void) const; /** + * Returns current render frame clock time + */ + double GetClockTime(void) const; + + /** * Returns the difference between the local time of the scene (when it * was running and not suspended) and the "curtime" */ @@ -258,6 +274,20 @@ public: static void SetTicRate(double ticrate); /** + * Gets the framerate for playing animations. (actions and ipos) + */ + static double GetAnimFrameRate(); + /** + * Sets the framerate for playing animations. (actions and ipos) + */ + 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. @@ -334,8 +364,10 @@ protected: KX_Scene* CreateScene(const STR_String& scenename); bool BeginFrame(); + void ClearFrame(); void EndFrame(); }; #endif //__KX_KETSJI_ENGINE + diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp index 3ae09c01270..e0f171e78e0 100644 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ b/source/gameengine/Ketsji/KX_Light.cpp @@ -36,14 +36,19 @@ #endif #include "KX_Light.h" +#include "KX_Camera.h" +#include "RAS_IRasterizer.h" #include "RAS_IRenderTools.h" #include "KX_PyMath.h" +#include "DNA_object_types.h" +#include "GPU_material.h" KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks, class RAS_IRenderTools* rendertools, const RAS_LightObject& lightobj, + bool glsl, PyTypeObject* T ) : @@ -53,11 +58,19 @@ KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks, m_lightobj = lightobj; m_lightobj.m_worldmatrix = GetOpenGLMatrixPtr(); m_rendertools->AddLight(&m_lightobj); + 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); } @@ -67,7 +80,7 @@ CValue* KX_LightObject::GetReplica() { KX_LightObject* replica = new KX_LightObject(*this); - + // this will copy properties and so on... CValue::AddDataToReplica(replica); @@ -75,9 +88,90 @@ 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() +{ + GPULamp *lamp; + + if((lamp = GetGPULamp())) { + float obmat[4][4]; + double *dobmat = GetOpenGLMatrixPtr()->getPointer(); + + for(int i=0; i<4; i++) + for(int j=0; j<4; j++, dobmat++) + obmat[i][j] = (float)*dobmat; + + GPU_lamp_update(lamp, m_lightobj.m_layer, obmat); + } +} + +bool KX_LightObject::HasShadowBuffer() +{ + GPULamp *lamp; + + if((lamp = GetGPULamp())) + return GPU_lamp_has_shadow_buffer(lamp); + else + return false; +} + +int KX_LightObject::GetShadowLayer() +{ + GPULamp *lamp; + + if((lamp = GetGPULamp())) + return GPU_lamp_shadow_layer(lamp); + else + return 0; +} + +void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_Transform& camtrans) +{ + GPULamp *lamp; + float viewmat[4][4], winmat[4][4]; + int winsize; + + /* bind framebuffer */ + lamp = GetGPULamp(); + GPU_lamp_shadow_buffer_bind(lamp, viewmat, &winsize, winmat); + + /* setup camera transformation */ + MT_Matrix4x4 modelviewmat((float*)viewmat); + MT_Matrix4x4 projectionmat((float*)winmat); + + MT_Transform trans = MT_Transform((float*)viewmat); + camtrans.invert(trans); + + cam->SetModelviewMatrix(modelviewmat); + cam->SetProjectionMatrix(projectionmat); + + cam->NodeSetLocalPosition(camtrans.getOrigin()); + cam->NodeSetLocalOrientation(camtrans.getBasis()); + cam->NodeUpdateGS(0,true); + + /* setup rasterizer transformations */ + ras->SetProjectionMatrix(projectionmat); + ras->SetViewMatrix(modelviewmat, cam->NodeGetWorldPosition(), + cam->GetCameraLocation(), cam->GetCameraOrientation()); +} + +void KX_LightObject::UnbindShadowBuffer(RAS_IRasterizer *ras) +{ + GPULamp *lamp = GetGPULamp(); + GPU_lamp_shadow_buffer_unbind(lamp); +} + PyObject* KX_LightObject::_getattr(const STR_String& attr) { if (attr == "layer") @@ -223,7 +317,7 @@ char KX_LightObject::doc[] = "Module KX_LightObject\n\n" "\t\tThe effect radius of the light.\n" "\tcolour -> list [r, g, b].\n" "\tcolor -> list [r, g, b].\n" -"\t\tThe colour of the light.\n" +"\t\tThe color of the light.\n" "\tlin_attenuation -> float.\n" "\t\tThe attenuation factor for the light.\n" "\tspotsize -> float.\n" diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h index 236d3e4e12e..e5dbf0b7f4a 100644 --- a/source/gameengine/Ketsji/KX_Light.h +++ b/source/gameengine/Ketsji/KX_Light.h @@ -32,22 +32,41 @@ #include "RAS_LightObject.h" #include "KX_GameObject.h" +struct GPULamp; +struct Scene; +class KX_Camera; +class RAS_IRasterizer; +class RAS_IRenderTools; +class MT_Transform; + class KX_LightObject : public KX_GameObject { Py_Header; protected: RAS_LightObject m_lightobj; class RAS_IRenderTools* m_rendertools; //needed for registering and replication of lightobj - 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, 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); + void UnbindShadowBuffer(class RAS_IRasterizer *ras); + void Update(); virtual PyObject* _getattr(const STR_String& attr); /* lens, near, far, projection_matrix */ virtual int _setattr(const STR_String& attr, PyObject *pyvalue); + + 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 c0757a32b9c..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 @@ -37,6 +39,7 @@ bool KX_MaterialIpoController::Update(double currentTime) //kxgameobj->SetObjectColor(m_rgba); kxgameobj->UpdateMaterialData( + m_matname_hash, m_rgba, m_specrgb, m_hard, @@ -75,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_MaterialIpoController.h b/source/gameengine/Ketsji/KX_MaterialIpoController.h index e76ddeefb04..4d2e258bf94 100644 --- a/source/gameengine/Ketsji/KX_MaterialIpoController.h +++ b/source/gameengine/Ketsji/KX_MaterialIpoController.h @@ -7,6 +7,8 @@ #include "SG_Spatial.h" #include "KX_IInterpolator.h" +#include "STR_String.h" //typedef dword + class KX_MaterialIpoController : public SG_Controller { public: @@ -23,10 +25,12 @@ private: bool m_modified; double m_ipotime; + dword m_matname_hash; public: - KX_MaterialIpoController() : + KX_MaterialIpoController(dword matname_hash) : m_modified(true), - m_ipotime(0.0) + m_ipotime(0.0), + m_matname_hash(matname_hash) {} virtual ~KX_MaterialIpoController(); virtual SG_Controller* GetReplica(class SG_Node* destnode); diff --git a/source/gameengine/Ketsji/KX_MeshProxy.cpp b/source/gameengine/Ketsji/KX_MeshProxy.cpp index 5c8fef1fca0..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) @@ -157,6 +169,9 @@ PyObject* KX_MeshProxy::PyGetMaterialName(PyObject* self, { matname = m_meshobj->GetMaterialName(matid); } + else { + return NULL; + } return PyString_FromString(matname.Ptr()); @@ -174,6 +189,9 @@ PyObject* KX_MeshProxy::PyGetTextureName(PyObject* self, { matname = m_meshobj->GetTextureName(matid); } + else { + return NULL; + } return PyString_FromString(matname.Ptr()); @@ -189,11 +207,14 @@ 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; } return PyInt_FromLong(length); @@ -217,14 +238,39 @@ PyObject* KX_MeshProxy::PyGetVertex(PyObject* self, vertexob = new KX_VertexProxy(this, vertex); } } + else { + return NULL; + } return vertexob; } +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.") { //this needs to be reviewed, it is dependend on Sumo/Solid. Who is using this ? - return Py_None;//Py_Success(KX_ReInstanceShapeFromMesh(m_meshobj)); + Py_RETURN_NONE;//(KX_ReInstanceShapeFromMesh(m_meshobj)) ? Py_RETURN_TRUE : Py_RETURN_FALSE; } 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 60b90138abe..28279b9a6b8 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -62,43 +62,54 @@ 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(); +} - m_mouse_over_in_previous_frame = false; +void KX_MouseFocusSensor::Init() +{ + m_mouse_over_in_previous_frame = (m_invert)?true:false; m_positive_event = false; m_hitObject = 0; - + m_reset = true; } bool KX_MouseFocusSensor::Evaluate(CValue* event) { bool result = false; bool obHasFocus = false; + bool reset = m_reset && m_level; // cout << "evaluate focus mouse sensor "<<endl; - + m_reset = false; if (m_focusmode) { /* Focus behaviour required. Test mouse-on. The rest is * equivalent to handling a key. */ obHasFocus = ParentObjectHasFocus(); if (!obHasFocus) { + m_positive_event = false; if (m_mouse_over_in_previous_frame) { - m_positive_event = false; - result = true; + result = true; } } else { + m_positive_event = true; if (!m_mouse_over_in_previous_frame) { - m_positive_event = true; result = true; } } + if (reset) { + // force an event + result = true; + } } else { /* No focus behaviour required: revert to the basic mode. This * mode is never used, because the converter never makes this @@ -113,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 @@ -133,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; } @@ -149,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 @@ -192,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(); + + /* 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 */ - const RAS_Rect & viewport = m_kxscene->GetSceneViewport(); + 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); @@ -204,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; @@ -271,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); @@ -313,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 @@ -331,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, @@ -346,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, @@ -366,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, @@ -387,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, @@ -408,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."; @@ -425,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 86f32fbf4be..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 ); @@ -68,6 +71,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor * @attention Overrides default evaluate. */ virtual bool Evaluate(CValue* event); + virtual void Init(); virtual bool IsPositiveTrigger() { bool result = m_positive_event; @@ -75,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; } + /* --------------------------------------------------------------------- */ @@ -138,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; @@ -153,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 d893990735f..bae87c28123 100644 --- a/source/gameengine/Ketsji/KX_NearSensor.cpp +++ b/source/gameengine/Ketsji/KX_NearSensor.cpp @@ -75,6 +75,21 @@ KX_NearSensor::KX_NearSensor(SCA_EventManager* eventmgr, SynchronizeTransform(); } +void KX_NearSensor::SynchronizeTransform() +{ + // The near and radar sensors are using a different physical object which is + // not linked to the parent object, must synchronize it. + if (m_physCtrl) + { + KX_GameObject* parent = ((KX_GameObject*)GetParent()); + MT_Vector3 pos = parent->NodeGetWorldPosition(); + MT_Quaternion orn = parent->NodeGetWorldOrientation().getRotation(); + m_physCtrl->setPosition(pos.x(),pos.y(),pos.z()); + m_physCtrl->setOrientation(orn.x(),orn.y(),orn.z(),orn.w()); + m_physCtrl->calcXform(); + } +} + void KX_NearSensor::RegisterSumo(KX_TouchEventManager *touchman) { if (m_physCtrl) @@ -83,14 +98,19 @@ void KX_NearSensor::RegisterSumo(KX_TouchEventManager *touchman) } } +void KX_NearSensor::UnregisterSumo(KX_TouchEventManager* touchman) +{ + if (m_physCtrl) + { + touchman->GetPhysicsEnvironment()->removeSensor(m_physCtrl); + } +} + CValue* KX_NearSensor::GetReplica() { KX_NearSensor* replica = new KX_NearSensor(*this); replica->m_colliders = new CListValue(); - replica->m_bCollision = false; - replica->m_bTriggered= false; - replica->m_hitObject = NULL; - replica->m_bLastTriggered = false; + replica->Init(); // this will copy properties and so on... CValue::AddDataToReplica(replica); @@ -123,9 +143,6 @@ CValue* KX_NearSensor::GetReplica() void KX_NearSensor::ReParent(SCA_IObject* parent) { - - SCA_ISensor::ReParent(parent); - m_client_info->m_gameobject = static_cast<KX_GameObject*>(parent); m_client_info->m_sensors.push_back(this); @@ -139,6 +156,7 @@ void KX_NearSensor::ReParent(SCA_IObject* parent) */ ((KX_GameObject*)GetParent())->GetSGNode()->ComputeWorldTransforms(NULL); SynchronizeTransform(); + SCA_ISensor::ReParent(parent); } @@ -172,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); } } @@ -188,7 +206,36 @@ bool KX_NearSensor::Evaluate(CValue* event) return result; } +// this function is called at broad phase stage to check if the two controller +// need to interact at all. It is used for Near/Radar sensor that don't need to +// check collision with object not included in filter +bool KX_NearSensor::BroadPhaseFilterCollision(void*obj1,void*obj2) +{ + KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent()); + + // need the mapping from PHY_IPhysicsController to gameobjects now + assert(obj1==m_physCtrl && obj2); + KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>((static_cast<PHY_IPhysicsController*>(obj2))->getNewClientInfo()); + KX_GameObject* gameobj = ( client_info ? + client_info->m_gameobject : + NULL); + + if (gameobj && (gameobj != parent)) + { + // only take valid colliders + if (client_info->m_type == KX_ClientObjectInfo::ACTOR) + { + if ((m_touchedpropname.Length() == 0) || + (gameobj->GetProperty(m_touchedpropname))) + { + return true; + } + } + } + + return false; +} bool KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData * coll_data) { @@ -205,20 +252,24 @@ bool KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData client_info->m_gameobject : NULL); - if (gameobj && (gameobj != parent)) + // Add the same check as in SCA_ISensor::Activate(), + // we don't want to record collision when the sensor is not active. + if (m_links && !m_suspended && + gameobj /* done in BroadPhaseFilterCollision() && (gameobj != parent)*/) { if (!m_colliders->SearchValue(gameobj)) m_colliders->Add(gameobj->AddRef()); // only take valid colliders - if (client_info->m_type == KX_ClientObjectInfo::ACTOR) - { - if ((m_touchedpropname.Length() == 0) || - (gameobj->GetProperty(m_touchedpropname))) - { + // These checks are done already in BroadPhaseFilterCollision() + //if (client_info->m_type == KX_ClientObjectInfo::ACTOR) + //{ + // if ((m_touchedpropname.Length() == 0) || + // (gameobj->GetProperty(m_touchedpropname))) + // { m_bTriggered = true; m_hitObject = gameobj; - } - } + // } + //} } return DT_CONTINUE; @@ -260,14 +311,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_NearSensor.h b/source/gameengine/Ketsji/KX_NearSensor.h index 096822f99ed..3f7078ef9fd 100644 --- a/source/gameengine/Ketsji/KX_NearSensor.h +++ b/source/gameengine/Ketsji/KX_NearSensor.h @@ -68,13 +68,16 @@ public: PyTypeObject* T=&Type); */ virtual ~KX_NearSensor(); + virtual void SynchronizeTransform(); virtual CValue* GetReplica(); virtual bool Evaluate(CValue* event); virtual void ReParent(SCA_IObject* parent); virtual bool NewHandleCollision(void* obj1,void* obj2, const PHY_CollData * coll_data); + virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2); virtual void RegisterSumo(KX_TouchEventManager *touchman); + virtual void UnregisterSumo(KX_TouchEventManager* touchman); virtual PyObject* _getattr(const STR_String& attr); diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp index 22a406792f9..98e73d4f0d7 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp @@ -50,6 +50,7 @@ KX_ObjectActuator( const MT_Vector3& drot, const MT_Vector3& linV, const MT_Vector3& angV, + const short damping, const KX_LocalFlags& flag, PyTypeObject* T ) : @@ -60,9 +61,23 @@ KX_ObjectActuator( m_drot(drot), m_linear_velocity(linV), m_angular_velocity(angV), + m_linear_length2(0.0), + m_current_linear_factor(0.0), + m_current_angular_factor(0.0), + m_damping(damping), m_bitLocalFlag (flag), - m_active_combined_velocity (false) + m_active_combined_velocity (false), + m_linear_damping_active(false), + m_angular_damping_active(false), + m_error_accumulator(0.0,0.0,0.0), + m_previous_error(0.0,0.0,0.0) { + if (m_bitLocalFlag.ServoControl) + { + // in servo motion, the force is local if the target velocity is local + m_bitLocalFlag.Force = m_bitLocalFlag.LinearVelocity; + } + UpdateFuzzyFlags(); } bool KX_ObjectActuator::Update() @@ -79,51 +94,153 @@ bool KX_ObjectActuator::Update() // it should reconcile the externally set velocity with it's // own velocity. if (m_active_combined_velocity) { - parent->ResolveCombinedVelocities( - m_linear_velocity, - m_angular_velocity, - (m_bitLocalFlag.LinearVelocity) != 0, - (m_bitLocalFlag.AngularVelocity) != 0 - ); + if (parent) + parent->ResolveCombinedVelocities( + m_linear_velocity, + m_angular_velocity, + (m_bitLocalFlag.LinearVelocity) != 0, + (m_bitLocalFlag.AngularVelocity) != 0 + ); m_active_combined_velocity = false; } + m_linear_damping_active = false; + m_angular_damping_active = false; + m_error_accumulator.setValue(0.0,0.0,0.0); + m_previous_error.setValue(0.0,0.0,0.0); return false; - } else - if (parent) + } else if (parent) { - /* Probably better to use some flags, so these MT_zero tests can be */ - /* skipped. */ - if (!MT_fuzzyZero(m_force)) - { - parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0); - } - if (!MT_fuzzyZero(m_torque)) - { - parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0); - } - if (!MT_fuzzyZero(m_dloc)) + if (m_bitLocalFlag.ServoControl) { - parent->ApplyMovement(m_dloc,(m_bitLocalFlag.DLoc) != 0); - } - if (!MT_fuzzyZero(m_drot)) - { - parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0); - } - if (!MT_fuzzyZero(m_linear_velocity)) + // In this mode, we try to reach a target speed using force + // As we don't know the friction, we must implement a generic + // servo control to achieve the speed in a configurable + // v = current velocity + // V = target velocity + // e = V-v = speed error + // dt = time interval since previous update + // I = sum(e(t)*dt) + // dv = e(t) - e(t-1) + // KP, KD, KI : coefficient + // F = KP*e+KI*I+KD*dv + MT_Scalar mass = parent->GetMass(); + if (mass < MT_EPSILON) + return false; + MT_Vector3 v = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity); + MT_Vector3 e = m_linear_velocity - v; + MT_Vector3 dv = e - m_previous_error; + MT_Vector3 I = m_error_accumulator + e; + + m_force = m_torque.x()*e+m_torque.y()*I+m_torque.z()*dv; + // to automatically adapt the PID coefficient to mass; + m_force *= mass; + if (m_bitLocalFlag.Torque) + { + if (m_force[0] > m_dloc[0]) + { + m_force[0] = m_dloc[0]; + I[0] = m_error_accumulator[0]; + } else if (m_force[0] < m_drot[0]) + { + m_force[0] = m_drot[0]; + I[0] = m_error_accumulator[0]; + } + } + if (m_bitLocalFlag.DLoc) + { + if (m_force[1] > m_dloc[1]) + { + m_force[1] = m_dloc[1]; + I[1] = m_error_accumulator[1]; + } else if (m_force[1] < m_drot[1]) + { + m_force[1] = m_drot[1]; + I[1] = m_error_accumulator[1]; + } + } + if (m_bitLocalFlag.DRot) + { + if (m_force[2] > m_dloc[2]) + { + m_force[2] = m_dloc[2]; + I[2] = m_error_accumulator[2]; + } else if (m_force[2] < m_drot[2]) + { + m_force[2] = m_drot[2]; + I[2] = m_error_accumulator[2]; + } + } + m_previous_error = e; + m_error_accumulator = I; + parent->ApplyForce(m_force,(m_bitLocalFlag.LinearVelocity) != 0); + } else { - if (m_bitLocalFlag.AddOrSetLinV) { - parent->addLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0); - } else { + if (!m_bitLocalFlag.ZeroForce) + { + parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0); + } + if (!m_bitLocalFlag.ZeroTorque) + { + parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0); + } + if (!m_bitLocalFlag.ZeroDLoc) + { + parent->ApplyMovement(m_dloc,(m_bitLocalFlag.DLoc) != 0); + } + if (!m_bitLocalFlag.ZeroDRot) + { + parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0); + } + if (!m_bitLocalFlag.ZeroLinearVelocity) + { + if (m_bitLocalFlag.AddOrSetLinV) { + parent->addLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0); + } else { + m_active_combined_velocity = true; + if (m_damping > 0) { + MT_Vector3 linV; + if (!m_linear_damping_active) { + // delta and the start speed (depends on the existing speed in that direction) + linV = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity); + // keep only the projection along the desired direction + m_current_linear_factor = linV.dot(m_linear_velocity)/m_linear_length2; + m_linear_damping_active = true; + } + if (m_current_linear_factor < 1.0) + m_current_linear_factor += 1.0/m_damping; + if (m_current_linear_factor > 1.0) + m_current_linear_factor = 1.0; + linV = m_current_linear_factor * m_linear_velocity; + parent->setLinearVelocity(linV,(m_bitLocalFlag.LinearVelocity) != 0); + } else { + parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0); + } + } + } + if (!m_bitLocalFlag.ZeroAngularVelocity) + { m_active_combined_velocity = true; - parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0); + if (m_damping > 0) { + MT_Vector3 angV; + if (!m_angular_damping_active) { + // delta and the start speed (depends on the existing speed in that direction) + angV = parent->GetAngularVelocity(m_bitLocalFlag.AngularVelocity); + // keep only the projection along the desired direction + m_current_angular_factor = angV.dot(m_angular_velocity)/m_angular_length2; + m_angular_damping_active = true; + } + if (m_current_angular_factor < 1.0) + m_current_angular_factor += 1.0/m_damping; + if (m_current_angular_factor > 1.0) + m_current_angular_factor = 1.0; + angV = m_current_angular_factor * m_angular_velocity; + parent->setAngularVelocity(angV,(m_bitLocalFlag.AngularVelocity) != 0); + } else { + parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0); + } } } - if (!MT_fuzzyZero(m_angular_velocity)) - { - parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0); - m_active_combined_velocity = true; - } } return true; @@ -187,18 +304,29 @@ PyParentObject KX_ObjectActuator::Parents[] = { }; PyMethodDef KX_ObjectActuator::Methods[] = { - {"getForce", (PyCFunction) KX_ObjectActuator::sPyGetForce, METH_VARARGS}, + {"getForce", (PyCFunction) KX_ObjectActuator::sPyGetForce, METH_NOARGS}, {"setForce", (PyCFunction) KX_ObjectActuator::sPySetForce, METH_VARARGS}, - {"getTorque", (PyCFunction) KX_ObjectActuator::sPyGetTorque, METH_VARARGS}, + {"getTorque", (PyCFunction) KX_ObjectActuator::sPyGetTorque, METH_NOARGS}, {"setTorque", (PyCFunction) KX_ObjectActuator::sPySetTorque, METH_VARARGS}, - {"getDLoc", (PyCFunction) KX_ObjectActuator::sPyGetDLoc, METH_VARARGS}, + {"getDLoc", (PyCFunction) KX_ObjectActuator::sPyGetDLoc, METH_NOARGS}, {"setDLoc", (PyCFunction) KX_ObjectActuator::sPySetDLoc, METH_VARARGS}, - {"getDRot", (PyCFunction) KX_ObjectActuator::sPyGetDRot, METH_VARARGS}, + {"getDRot", (PyCFunction) KX_ObjectActuator::sPyGetDRot, METH_NOARGS}, {"setDRot", (PyCFunction) KX_ObjectActuator::sPySetDRot, METH_VARARGS}, - {"getLinearVelocity", (PyCFunction) KX_ObjectActuator::sPyGetLinearVelocity, METH_VARARGS}, + {"getLinearVelocity", (PyCFunction) KX_ObjectActuator::sPyGetLinearVelocity, METH_NOARGS}, {"setLinearVelocity", (PyCFunction) KX_ObjectActuator::sPySetLinearVelocity, METH_VARARGS}, - {"getAngularVelocity", (PyCFunction) KX_ObjectActuator::sPyGetAngularVelocity, METH_VARARGS}, + {"getAngularVelocity", (PyCFunction) KX_ObjectActuator::sPyGetAngularVelocity, METH_NOARGS}, {"setAngularVelocity", (PyCFunction) KX_ObjectActuator::sPySetAngularVelocity, METH_VARARGS}, + {"setDamping", (PyCFunction) KX_ObjectActuator::sPySetDamping, METH_VARARGS}, + {"getDamping", (PyCFunction) KX_ObjectActuator::sPyGetDamping, METH_NOARGS}, + {"setForceLimitX", (PyCFunction) KX_ObjectActuator::sPySetForceLimitX, METH_VARARGS}, + {"getForceLimitX", (PyCFunction) KX_ObjectActuator::sPyGetForceLimitX, METH_NOARGS}, + {"setForceLimitY", (PyCFunction) KX_ObjectActuator::sPySetForceLimitY, METH_VARARGS}, + {"getForceLimitY", (PyCFunction) KX_ObjectActuator::sPyGetForceLimitY, METH_NOARGS}, + {"setForceLimitZ", (PyCFunction) KX_ObjectActuator::sPySetForceLimitZ, METH_VARARGS}, + {"getForceLimitZ", (PyCFunction) KX_ObjectActuator::sPyGetForceLimitZ, METH_NOARGS}, + {"setPID", (PyCFunction) KX_ObjectActuator::sPyGetPID, METH_NOARGS}, + {"getPID", (PyCFunction) KX_ObjectActuator::sPySetPID, METH_VARARGS}, + {NULL,NULL} //Sentinel @@ -212,9 +340,7 @@ PyObject* KX_ObjectActuator::_getattr(const STR_String& attr) { /* Removed! */ /* 2. getForce */ -PyObject* KX_ObjectActuator::PyGetForce(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_ObjectActuator::PyGetForce(PyObject* self) { PyObject *retVal = PyList_New(4); @@ -238,13 +364,12 @@ PyObject* KX_ObjectActuator::PySetForce(PyObject* self, } m_force.setValue(vecArg); m_bitLocalFlag.Force = PyArgToBool(bToggle); + UpdateFuzzyFlags(); Py_Return; } /* 4. getTorque */ -PyObject* KX_ObjectActuator::PyGetTorque(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_ObjectActuator::PyGetTorque(PyObject* self) { PyObject *retVal = PyList_New(4); @@ -268,13 +393,12 @@ PyObject* KX_ObjectActuator::PySetTorque(PyObject* self, } m_torque.setValue(vecArg); m_bitLocalFlag.Torque = PyArgToBool(bToggle); + UpdateFuzzyFlags(); Py_Return; } /* 6. getDLoc */ -PyObject* KX_ObjectActuator::PyGetDLoc(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_ObjectActuator::PyGetDLoc(PyObject* self) { PyObject *retVal = PyList_New(4); @@ -298,13 +422,12 @@ PyObject* KX_ObjectActuator::PySetDLoc(PyObject* self, } m_dloc.setValue(vecArg); m_bitLocalFlag.DLoc = PyArgToBool(bToggle); + UpdateFuzzyFlags(); Py_Return; } /* 8. getDRot */ -PyObject* KX_ObjectActuator::PyGetDRot(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_ObjectActuator::PyGetDRot(PyObject* self) { PyObject *retVal = PyList_New(4); @@ -328,13 +451,12 @@ PyObject* KX_ObjectActuator::PySetDRot(PyObject* self, } m_drot.setValue(vecArg); m_bitLocalFlag.DRot = PyArgToBool(bToggle); + UpdateFuzzyFlags(); Py_Return; } /* 10. getLinearVelocity */ -PyObject* KX_ObjectActuator::PyGetLinearVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) { +PyObject* KX_ObjectActuator::PyGetLinearVelocity(PyObject* self) { PyObject *retVal = PyList_New(4); PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0])); @@ -357,14 +479,13 @@ PyObject* KX_ObjectActuator::PySetLinearVelocity(PyObject* self, } m_linear_velocity.setValue(vecArg); m_bitLocalFlag.LinearVelocity = PyArgToBool(bToggle); + UpdateFuzzyFlags(); Py_Return; } /* 12. getAngularVelocity */ -PyObject* KX_ObjectActuator::PyGetAngularVelocity(PyObject* self, - PyObject* args, - PyObject* kwds) { +PyObject* KX_ObjectActuator::PyGetAngularVelocity(PyObject* self) { PyObject *retVal = PyList_New(4); PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_angular_velocity[0])); @@ -386,10 +507,133 @@ PyObject* KX_ObjectActuator::PySetAngularVelocity(PyObject* self, } m_angular_velocity.setValue(vecArg); m_bitLocalFlag.AngularVelocity = PyArgToBool(bToggle); + UpdateFuzzyFlags(); + Py_Return; +} + +/* 13. setDamping */ +PyObject* KX_ObjectActuator::PySetDamping(PyObject* self, + PyObject* args, + PyObject* kwds) { + int damping = 0; + if (!PyArg_ParseTuple(args, "i", &damping) || damping < 0 || damping > 1000) { + return NULL; + } + m_damping = damping; + Py_Return; +} + +/* 13. getVelocityDamping */ +PyObject* KX_ObjectActuator::PyGetDamping(PyObject* self) { + return Py_BuildValue("i",m_damping); +} +/* 6. getForceLimitX */ +PyObject* KX_ObjectActuator::PyGetForceLimitX(PyObject* self) +{ + PyObject *retVal = PyList_New(3); + + PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[0])); + PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[0])); + PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.Torque)); + + return retVal; +} +/* 7. setForceLimitX */ +PyObject* KX_ObjectActuator::PySetForceLimitX(PyObject* self, + PyObject* args, + PyObject* kwds) +{ + float vecArg[2]; + int bToggle = 0; + if(!PyArg_ParseTuple(args, "ffi", &vecArg[0], &vecArg[1], &bToggle)) { + return NULL; + } + m_drot[0] = vecArg[0]; + m_dloc[0] = vecArg[1]; + m_bitLocalFlag.Torque = PyArgToBool(bToggle); + Py_Return; +} + +/* 6. getForceLimitY */ +PyObject* KX_ObjectActuator::PyGetForceLimitY(PyObject* self) +{ + PyObject *retVal = PyList_New(3); + + PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[1])); + PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[1])); + PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.DLoc)); + + return retVal; +} +/* 7. setForceLimitY */ +PyObject* KX_ObjectActuator::PySetForceLimitY(PyObject* self, + PyObject* args, + PyObject* kwds) +{ + float vecArg[2]; + int bToggle = 0; + if(!PyArg_ParseTuple(args, "ffi", &vecArg[0], &vecArg[1], &bToggle)) { + return NULL; + } + m_drot[1] = vecArg[0]; + m_dloc[1] = vecArg[1]; + m_bitLocalFlag.DLoc = PyArgToBool(bToggle); + Py_Return; +} + +/* 6. getForceLimitZ */ +PyObject* KX_ObjectActuator::PyGetForceLimitZ(PyObject* self) +{ + PyObject *retVal = PyList_New(3); + + PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[2])); + PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[2])); + PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.DRot)); + + return retVal; +} +/* 7. setForceLimitZ */ +PyObject* KX_ObjectActuator::PySetForceLimitZ(PyObject* self, + PyObject* args, + PyObject* kwds) +{ + float vecArg[2]; + int bToggle = 0; + if(!PyArg_ParseTuple(args, "ffi", &vecArg[0], &vecArg[1], &bToggle)) { + return NULL; + } + m_drot[2] = vecArg[0]; + m_dloc[2] = vecArg[1]; + m_bitLocalFlag.DRot = PyArgToBool(bToggle); + Py_Return; +} + +/* 4. getPID */ +PyObject* KX_ObjectActuator::PyGetPID(PyObject* self) +{ + PyObject *retVal = PyList_New(3); + + PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_torque[0])); + PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_torque[1])); + PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_torque[2])); + + return retVal; +} +/* 5. setPID */ +PyObject* KX_ObjectActuator::PySetPID(PyObject* self, + PyObject* args, + PyObject* kwds) +{ + float vecArg[3]; + if (!PyArg_ParseTuple(args, "fff", &vecArg[0], &vecArg[1], &vecArg[2])) { + return NULL; + } + m_torque.setValue(vecArg); Py_Return; } + /* eof */ diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.h b/source/gameengine/Ketsji/KX_ObjectActuator.h index edbae154b8b..aa686f41233 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.h +++ b/source/gameengine/Ketsji/KX_ObjectActuator.h @@ -46,7 +46,12 @@ struct KX_LocalFlags { DLoc(false), LinearVelocity(false), AngularVelocity(false), - AddOrSetLinV(false) + AddOrSetLinV(false), + ZeroForce(false), + ZeroDRot(false), + ZeroDLoc(false), + ZeroLinearVelocity(false), + ZeroAngularVelocity(false) { } @@ -57,6 +62,13 @@ struct KX_LocalFlags { unsigned short LinearVelocity : 1; unsigned short AngularVelocity : 1; unsigned short AddOrSetLinV : 1; + unsigned short ServoControl : 1; + unsigned short ZeroForce : 1; + unsigned short ZeroTorque : 1; + unsigned short ZeroDRot : 1; + unsigned short ZeroDLoc : 1; + unsigned short ZeroLinearVelocity : 1; + unsigned short ZeroAngularVelocity : 1; }; class KX_ObjectActuator : public SCA_IActuator @@ -69,6 +81,15 @@ class KX_ObjectActuator : public SCA_IActuator MT_Vector3 m_drot; MT_Vector3 m_linear_velocity; MT_Vector3 m_angular_velocity; + MT_Scalar m_linear_length2; + MT_Scalar m_angular_length2; + // used in damping + MT_Scalar m_current_linear_factor; + MT_Scalar m_current_angular_factor; + short m_damping; + // used in servo control + MT_Vector3 m_previous_error; + MT_Vector3 m_error_accumulator; KX_LocalFlags m_bitLocalFlag; // A hack bool -- oh no sorry everyone @@ -77,6 +98,8 @@ class KX_ObjectActuator : public SCA_IActuator // setting linear velocity. bool m_active_combined_velocity; + bool m_linear_damping_active; + bool m_angular_damping_active; public: enum KX_OBJECT_ACT_VEC_TYPE { @@ -103,6 +126,7 @@ public: const MT_Vector3& drot, const MT_Vector3& linV, const MT_Vector3& angV, + const short damping, const KX_LocalFlags& flag, PyTypeObject* T=&Type ); @@ -110,6 +134,17 @@ public: CValue* GetReplica(); void SetForceLoc(const double force[3]) { /*m_force=force;*/ } + void UpdateFuzzyFlags() + { + m_bitLocalFlag.ZeroForce = MT_fuzzyZero(m_force); + m_bitLocalFlag.ZeroTorque = MT_fuzzyZero(m_torque); + m_bitLocalFlag.ZeroDLoc = MT_fuzzyZero(m_dloc); + m_bitLocalFlag.ZeroDRot = MT_fuzzyZero(m_drot); + m_bitLocalFlag.ZeroLinearVelocity = MT_fuzzyZero(m_linear_velocity); + m_linear_length2 = (m_bitLocalFlag.ZeroLinearVelocity) ? 0.0 : m_linear_velocity.length2(); + m_bitLocalFlag.ZeroAngularVelocity = MT_fuzzyZero(m_angular_velocity); + m_angular_length2 = (m_bitLocalFlag.ZeroAngularVelocity) ? 0.0 : m_angular_velocity.length2(); + } virtual bool Update(); @@ -120,18 +155,28 @@ public: virtual PyObject* _getattr(const STR_String& attr); - KX_PYMETHOD(KX_ObjectActuator,GetForce); + KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForce); KX_PYMETHOD(KX_ObjectActuator,SetForce); - KX_PYMETHOD(KX_ObjectActuator,GetTorque); + KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetTorque); KX_PYMETHOD(KX_ObjectActuator,SetTorque); - KX_PYMETHOD(KX_ObjectActuator,GetDLoc); + KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetDLoc); KX_PYMETHOD(KX_ObjectActuator,SetDLoc); - KX_PYMETHOD(KX_ObjectActuator,GetDRot); + KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetDRot); KX_PYMETHOD(KX_ObjectActuator,SetDRot); - KX_PYMETHOD(KX_ObjectActuator,GetLinearVelocity); + KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetLinearVelocity); KX_PYMETHOD(KX_ObjectActuator,SetLinearVelocity); - KX_PYMETHOD(KX_ObjectActuator,GetAngularVelocity); + KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetAngularVelocity); KX_PYMETHOD(KX_ObjectActuator,SetAngularVelocity); + KX_PYMETHOD(KX_ObjectActuator,SetDamping); + KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetDamping); + KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForceLimitX); + KX_PYMETHOD(KX_ObjectActuator,SetForceLimitX); + KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForceLimitY); + KX_PYMETHOD(KX_ObjectActuator,SetForceLimitY); + KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForceLimitZ); + KX_PYMETHOD(KX_ObjectActuator,SetForceLimitZ); + KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetPID); + KX_PYMETHOD(KX_ObjectActuator,SetPID); }; #endif //__KX_OBJECTACTUATOR diff --git a/source/gameengine/Ketsji/KX_OdePhysicsController.cpp b/source/gameengine/Ketsji/KX_OdePhysicsController.cpp index 4e45ce484e3..6a701a5f25b 100644 --- a/source/gameengine/Ketsji/KX_OdePhysicsController.cpp +++ b/source/gameengine/Ketsji/KX_OdePhysicsController.cpp @@ -133,8 +133,9 @@ void KX_OdePhysicsController::SetLinearVelocity(const MT_Vector3& lin_vel,bool l ODEPhysicsController::SetLinearVelocity(lin_vel[0],lin_vel[1],lin_vel[2],local); } -void KX_OdePhysicsController::setOrientation(const MT_Quaternion& orn) +void KX_OdePhysicsController::setOrientation(const MT_Matrix3x3& rot) { + MT_Quaternion orn = rot.getRotation(); ODEPhysicsController::setOrientation(orn[0],orn[1],orn[2],orn[3]); } @@ -168,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); @@ -177,7 +183,7 @@ void KX_OdePhysicsController::setRigidBody(bool rigid) } -void KX_OdePhysicsController::SuspendDynamics() +void KX_OdePhysicsController::SuspendDynamics(bool) { ODEPhysicsController::SuspendDynamics(); } diff --git a/source/gameengine/Ketsji/KX_OdePhysicsController.h b/source/gameengine/Ketsji/KX_OdePhysicsController.h index 07a0bee9775..53050f6ce3e 100644 --- a/source/gameengine/Ketsji/KX_OdePhysicsController.h +++ b/source/gameengine/Ketsji/KX_OdePhysicsController.h @@ -67,16 +67,16 @@ public: virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local); virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ); virtual void getOrientation(MT_Quaternion& orn); - virtual void setOrientation(const MT_Quaternion& orn); + virtual void setOrientation(const MT_Matrix3x3& orn); virtual void setPosition(const MT_Point3& pos); virtual void setScaling(const MT_Vector3& scaling); virtual MT_Scalar GetMass(); virtual MT_Vector3 getReactionForce(); virtual void setRigidBody(bool rigid); - virtual void SuspendDynamics(); + 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 new file mode 100644 index 00000000000..89549ca6b57 --- /dev/null +++ b/source/gameengine/Ketsji/KX_ParentActuator.cpp @@ -0,0 +1,221 @@ +/** + * Set or remove an objects parent + * + * $Id: SCA_ParentActuator.cpp 13932 2008-03-01 19:05:41Z ben2610 $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "KX_ParentActuator.h" +#include "KX_GameObject.h" +#include "KX_PythonInit.h" + +#include "PyObjectPlus.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +/* ------------------------------------------------------------------------- */ +/* Native functions */ +/* ------------------------------------------------------------------------- */ + +KX_ParentActuator::KX_ParentActuator(SCA_IObject *gameobj, + int mode, + SCA_IObject *ob, + PyTypeObject* T) + : SCA_IActuator(gameobj, T), + m_mode(mode), + m_ob(ob) +{ + if (m_ob) + m_ob->RegisterActuator(this); +} + + + +KX_ParentActuator::~KX_ParentActuator() +{ + if (m_ob) + m_ob->UnregisterActuator(this); +} + + + +CValue* KX_ParentActuator::GetReplica() +{ + KX_ParentActuator* replica = new KX_ParentActuator(*this); + // replication just copy the m_base pointer => common random generator + replica->ProcessReplica(); + CValue::AddDataToReplica(replica); + + return replica; +} + +void KX_ParentActuator::ProcessReplica() +{ + if (m_ob) + m_ob->RegisterActuator(this); + SCA_IActuator::ProcessReplica(); +} + + +bool KX_ParentActuator::UnlinkObject(SCA_IObject* clientobj) +{ + if (clientobj == m_ob) + { + // this object is being deleted, we cannot continue to track it. + m_ob = NULL; + return true; + } + return false; +} + +void KX_ParentActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + void **h_obj = (*obj_map)[m_ob]; + if (h_obj) { + if (m_ob) + m_ob->UnregisterActuator(this); + m_ob = (SCA_IObject*)(*h_obj); + m_ob->RegisterActuator(this); + } +} + + + +bool KX_ParentActuator::Update() +{ + bool bNegativeEvent = IsNegativeEvent(); + RemoveAllEvents(); + + if (bNegativeEvent) + return false; // do nothing on negative events + + KX_GameObject *obj = (KX_GameObject*) GetParent(); + KX_Scene *scene = KX_GetActiveScene(); + switch (m_mode) { + case KX_PARENT_SET: + if (m_ob) + obj->SetParent(scene, (KX_GameObject*)m_ob); + break; + case KX_PARENT_REMOVE: + obj->RemoveParent(scene); + break; + }; + + return false; +} + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ + +/* Integration hooks ------------------------------------------------------- */ +PyTypeObject KX_ParentActuator::Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "KX_ParentActuator", + sizeof(KX_ParentActuator), + 0, + PyDestructor, + 0, + __getattr, + __setattr, + 0, //&MyPyCompare, + __repr, + 0, //&cvalue_as_number, + 0, + 0, + 0, + 0 +}; + +PyParentObject KX_ParentActuator::Parents[] = { + &KX_ParentActuator::Type, + &SCA_IActuator::Type, + &SCA_ILogicBrick::Type, + &CValue::Type, + NULL +}; + +PyMethodDef KX_ParentActuator::Methods[] = { + {"setObject", (PyCFunction) KX_ParentActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc}, + {"getObject", (PyCFunction) KX_ParentActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc}, + {NULL,NULL} //Sentinel +}; + +PyObject* KX_ParentActuator::_getattr(const STR_String& attr) { + _getattr_up(SCA_IActuator); +} + +/* 1. setObject */ +const char KX_ParentActuator::SetObject_doc[] = +"setObject(object)\n" +"\t- object: KX_GameObject, string or None\n" +"\tSet the object to set as parent.\n"; +PyObject* KX_ParentActuator::PySetObject(PyObject* self, PyObject* value) { + KX_GameObject *gameobj; + + if (!ConvertPythonToGameObject(value, &gameobj, true)) + return NULL; // ConvertPythonToGameObject sets the error + + if (m_ob != NULL) + m_ob->UnregisterActuator(this); + + m_ob = (SCA_IObject*)gameobj; + if (m_ob) + m_ob->RegisterActuator(this); + + Py_RETURN_NONE; +} + +/* 2. getObject */ + +/* get obj ---------------------------------------------------------- */ +const char KX_ParentActuator::GetObject_doc[] = +"getObject(name_only = 1)\n" +"name_only - optional arg, when true will return the KX_GameObject rather then its name\n" +"\tReturns the object that is set to.\n"; +PyObject* KX_ParentActuator::PyGetObject(PyObject* self, PyObject* args) +{ + int ret_name_only = 1; + if (!PyArg_ParseTuple(args, "|i", &ret_name_only)) + return NULL; + + if (!m_ob) + Py_RETURN_NONE; + + if (ret_name_only) + return PyString_FromString(m_ob->GetName()); + else + return m_ob->AddRef(); +} + +/* eof */ diff --git a/source/gameengine/Ketsji/KX_ParentActuator.h b/source/gameengine/Ketsji/KX_ParentActuator.h new file mode 100644 index 00000000000..e2b30ba2d0f --- /dev/null +++ b/source/gameengine/Ketsji/KX_ParentActuator.h @@ -0,0 +1,89 @@ +/** + * Set or remove an objects parent + * + * + * $Id: KX_ParentActuator.h 3271 2004-10-16 11:41:50Z kester $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 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_PARENTACTUATOR +#define __KX_PARENTACTUATOR + +#include "SCA_IActuator.h" +#include "SCA_LogicManager.h" + +class KX_ParentActuator : public SCA_IActuator +{ + Py_Header; + + /** Mode */ + int m_mode; + + /** Object to set as parent */ + SCA_IObject *m_ob; + + + + public: + enum KX_PARENTACT_MODE + { + KX_PARENT_NODEF = 0, + KX_PARENT_SET, + KX_PARENT_REMOVE, + + }; + + KX_ParentActuator(class SCA_IObject* gameobj, + int mode, + SCA_IObject *ob, + PyTypeObject* T=&Type); + virtual ~KX_ParentActuator(); + virtual bool Update(); + + virtual CValue* GetReplica(); + virtual void ProcessReplica(); + virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map); + virtual bool UnlinkObject(SCA_IObject* clientobj); + + /* --------------------------------------------------------------------- */ + /* Python interface ---------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + + virtual PyObject* _getattr(const STR_String& attr); + + /* 1. setObject */ + KX_PYMETHOD_DOC_O(KX_ParentActuator,SetObject); + /* 2. getObject */ + KX_PYMETHOD_DOC_VARARGS(KX_ParentActuator,GetObject); + +}; /* end of class KX_ParentActuator : public SCA_PropertyActuator */ + +#endif + diff --git a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp index 27cfaefc076..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" @@ -58,7 +60,10 @@ PyObject* KX_PhysicsObjectWrapper::PySetPosition(PyObject* self, { m_ctrl->setPosition(x,y,z); } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } @@ -72,7 +77,10 @@ PyObject* KX_PhysicsObjectWrapper::PySetLinearVelocity(PyObject* self, { m_ctrl->SetLinearVelocity(x,y,z,local != 0); } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } PyObject* KX_PhysicsObjectWrapper::PySetAngularVelocity(PyObject* self, @@ -85,7 +93,10 @@ PyObject* KX_PhysicsObjectWrapper::PySetAngularVelocity(PyObject* self, { m_ctrl->SetAngularVelocity(x,y,z,local != 0); } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } PyObject* KX_PhysicsObjectWrapper::PySetActive(PyObject* self, @@ -97,7 +108,10 @@ PyObject* KX_PhysicsObjectWrapper::PySetActive(PyObject* self, { m_ctrl->SetActive(active!=0); } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } 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 70333b33d2c..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" { -//XXX #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" @@ -59,11 +57,10 @@ KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname, int tilexrep, int tileyrep, int mode, - bool transparant, + int transp, + bool alpha, bool zsort, int lightlayer, - bool bIsTriangle, - void* clientobject, struct MTFace* tface, unsigned int* mcol, PyTypeObject *T) @@ -74,11 +71,10 @@ KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname, tilexrep, tileyrep, mode, - transparant, + transp, + alpha, zsort, - lightlayer, - bIsTriangle, - clientobject), + lightlayer), m_tface(tface), m_mcol(mcol), m_material(material), @@ -138,38 +134,29 @@ void KX_PolygonMaterial::DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& c if (GetCachingInfo() != cachingInfo) { if (!cachingInfo) - { - //XXX 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()); - //XXX 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 - { - //XXX 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); @@ -245,13 +232,14 @@ PyObject* KX_PolygonMaterial::_getattr(const STR_String& attr) if (attr == "drawingmode") return PyInt_FromLong(m_drawingmode); if (attr == "transparent") - return PyInt_FromLong(m_transparant); + return PyInt_FromLong(m_alpha); if (attr == "zsort") return PyInt_FromLong(m_zsort); 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); @@ -312,7 +300,7 @@ int KX_PolygonMaterial::_setattr(const STR_String &attr, PyObject *pyvalue) if (attr == "transparent") { - m_transparant = value; + m_alpha = value; return 0; } @@ -331,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; } } @@ -384,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; } @@ -397,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); - //XXX 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 19015494e06..fe116f757db 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.h +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.h @@ -64,11 +64,10 @@ public: int tilexrep, int tileyrep, int mode, - bool transparant, + int transp, + 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 172882ff18d..fb37eded450 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 @@ -82,13 +84,16 @@ static PyObject* gPySetGravity(PyObject* self, PyObject* kwds) { float x,y,z; - int len = PyTuple_Size(args); - if ((len == 3) && PyArg_ParseTuple(args,"fff",&x,&y,&z)) + if (PyArg_ParseTuple(args,"fff",&x,&y,&z)) { if (PHY_GetActiveEnvironment()) PHY_GetActiveEnvironment()->setGravity(x,y,z); } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + + Py_RETURN_NONE; } static PyObject* gPySetDebugMode(PyObject* self, @@ -105,7 +110,11 @@ static PyObject* gPySetDebugMode(PyObject* self, } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + + Py_RETURN_NONE; } @@ -122,7 +131,10 @@ static PyObject* gPySetNumTimeSubSteps(PyObject* self, PHY_GetActiveEnvironment()->setNumTimeSubSteps(substep); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } @@ -138,7 +150,10 @@ static PyObject* gPySetNumIterations(PyObject* self, PHY_GetActiveEnvironment()->setNumIterations(iter); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } @@ -155,7 +170,10 @@ static PyObject* gPySetDeactivationTime(PyObject* self, PHY_GetActiveEnvironment()->setDeactivationTime(deactive_time); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } @@ -171,7 +189,10 @@ static PyObject* gPySetDeactivationLinearTreshold(PyObject* self, PHY_GetActiveEnvironment()->setDeactivationLinearTreshold( linearDeactivationTreshold); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } @@ -187,7 +208,10 @@ static PyObject* gPySetDeactivationAngularTreshold(PyObject* self, PHY_GetActiveEnvironment()->setDeactivationAngularTreshold( angularDeactivationTreshold); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } static PyObject* gPySetContactBreakingTreshold(PyObject* self, @@ -202,7 +226,10 @@ static PyObject* gPySetContactBreakingTreshold(PyObject* self, PHY_GetActiveEnvironment()->setContactBreakingTreshold( contactBreakingTreshold); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } @@ -218,7 +245,10 @@ static PyObject* gPySetCcdMode(PyObject* self, PHY_GetActiveEnvironment()->setCcdMode( ccdMode); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } static PyObject* gPySetSorConstant(PyObject* self, @@ -233,7 +263,10 @@ static PyObject* gPySetSorConstant(PyObject* self, PHY_GetActiveEnvironment()->setSolverSorConstant( sor); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } static PyObject* gPySetSolverTau(PyObject* self, @@ -248,7 +281,10 @@ static PyObject* gPySetSolverTau(PyObject* self, PHY_GetActiveEnvironment()->setSolverTau( tau); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } @@ -264,7 +300,10 @@ static PyObject* gPySetSolverDamping(PyObject* self, PHY_GetActiveEnvironment()->setSolverDamping( damping); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } static PyObject* gPySetLinearAirDamping(PyObject* self, @@ -279,7 +318,10 @@ static PyObject* gPySetLinearAirDamping(PyObject* self, PHY_GetActiveEnvironment()->setLinearAirDamping( damping); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } @@ -295,7 +337,10 @@ static PyObject* gPySetUseEpa(PyObject* self, PHY_GetActiveEnvironment()->setUseEpa(epa); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } static PyObject* gPySetSolverType(PyObject* self, PyObject* args, @@ -309,7 +354,10 @@ static PyObject* gPySetSolverType(PyObject* self, PHY_GetActiveEnvironment()->setSolverType(solverType); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } @@ -338,8 +386,11 @@ static PyObject* gPyGetVehicleConstraint(PyObject* self, } } + else { + return NULL; + } - Py_INCREF(Py_None); return Py_None; + Py_RETURN_NONE; } @@ -384,7 +435,7 @@ static PyObject* gPyCreateConstraint(PyObject* self, PHY_IPhysicsController* physctrl2 = (PHY_IPhysicsController*) physicsid2; if (physctrl) //TODO:check for existance of this pointer! { - int constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,pivotX,pivotY,pivotZ,axisX,axisY,axisZ); + int constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,pivotX,pivotY,pivotZ,axisX,axisY,axisZ,0); KX_ConstraintWrapper* wrap = new KX_ConstraintWrapper((enum PHY_ConstraintType)constrainttype,constraintid,PHY_GetActiveEnvironment()); @@ -395,8 +446,11 @@ static PyObject* gPyCreateConstraint(PyObject* self, } } + else { + return NULL; + } - Py_INCREF(Py_None); return Py_None; + Py_RETURN_NONE; } @@ -421,6 +475,9 @@ static PyObject* gPyGetAppliedImpulse(PyObject* self, appliedImpulse = PHY_GetActiveEnvironment()->getAppliedImpulse(constraintid); } } + else { + return NULL; + } return PyFloat_FromDouble(appliedImpulse); } @@ -443,60 +500,64 @@ static PyObject* gPyRemoveConstraint(PyObject* self, PHY_GetActiveEnvironment()->removeConstraint(constraintid); } } - Py_INCREF(Py_None); return Py_None; + else { + return NULL; + } + + Py_RETURN_NONE; } 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_PyMath.h b/source/gameengine/Ketsji/KX_PyMath.h index e1715c9275f..4e383e9b3d4 100644 --- a/source/gameengine/Ketsji/KX_PyMath.h +++ b/source/gameengine/Ketsji/KX_PyMath.h @@ -84,7 +84,10 @@ bool PyMatTo(PyObject* pymat, T& mat) } } else noerror = false; - + + if (noerror==false) + PyErr_SetString(PyExc_TypeError, "could not be converted to a matrix (sequence of sequences)"); + return noerror; } @@ -97,9 +100,13 @@ bool PyVecTo(PyObject* pyval, T& vec) if (PySequence_Check(pyval)) { unsigned int numitems = PySequence_Size(pyval); - if (numitems != Size(vec)) + if (numitems != Size(vec)) { + char err[128]; + sprintf(err, "error setting vector, %d args, should be %d", numitems, Size(vec)); + PyErr_SetString(PyExc_AttributeError, err); return false; - + } + for (unsigned int x = 0; x < numitems; x++) { PyObject *item = PySequence_GetItem(pyval, x); /* new ref */ @@ -107,7 +114,17 @@ bool PyVecTo(PyObject* pyval, T& vec) Py_DECREF(item); } + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_AttributeError, "one or more of the items in the sequence was not a float"); + return false; + } + return true; + } else + { + char err[128]; + sprintf(err, "not a sequence type, expected a sequence of numbers size %d", Size(vec)); + PyErr_SetString(PyExc_AttributeError, err); } return false; diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 681548fcc06..7ac817488fe 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -28,24 +28,14 @@ * Initialize Python thingies. */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif +#include "GL/glew.h" -#ifdef WIN32 -#include <windows.h> -#endif // WIN32 -#ifdef __APPLE__ -#define GL_GLEXT_LEGACY 1 -#include <OpenGL/gl.h> -#include <OpenGL/glu.h> -#else -#include <GL/gl.h> -#if defined(__sun__) && !defined(__sparc__) -#include <mesa/glu.h> +// directory header for py function getBlendFileList +#include <stdlib.h> +#ifndef WIN32 + #include <dirent.h> #else -#include <GL/glu.h> -#endif + #include "BLI_winstuff.h" #endif #ifdef WIN32 @@ -67,17 +57,28 @@ #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" + +//XXX +#if 0 +extern "C" { + #include "Mathutils.h" // Blender.Mathutils module copied here so the blenderlayer can use. +} +#endif + +#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. @@ -86,13 +87,20 @@ //#include "BPY_extern.h" #endif +#include "BKE_utildefines.h" +#include "BKE_global.h" +#include "BLI_blenlib.h" +#include "GPU_material.h" + 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; +static char gp_GamePythonPath[FILE_MAXDIR + FILE_MAXFILE] = ""; void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color) { @@ -115,36 +123,51 @@ void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,cons static PyObject* ErrorObject; STR_String gPyGetRandomFloat_doc="getRandomFloat returns a random floating point value in the range [0..1)"; -static PyObject* gPyGetRandomFloat(PyObject*, - PyObject*, - PyObject*) +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[] = +"(path) - Converts a blender internal path into a proper file system path.\n\ +path - the string path to convert.\n\n\ +Use / as directory separator in path\n\ +You can use '//' at the start of the string to define a relative path;\n\ +Blender replaces that string by the directory of the startup .blend or runtime\n\ +file to make a full path name (doesn't change during the game, even if you load\n\ +other .blend).\n\ +The function also converts the directory separator to the local file system format."; + +static PyObject* gPyExpandPath(PyObject*, PyObject* args) +{ + char expanded[FILE_MAXDIR + FILE_MAXFILE]; + char* filename; + + if (!PyArg_ParseTuple(args,"s",&filename)) + return NULL; + + BLI_strncpy(expanded, filename, FILE_MAXDIR + FILE_MAXFILE); + BLI_convertstringcode(expanded, gp_GamePythonPath); + return PyString_FromString(expanded); } static bool usedsp = false; // this gets a pointer to an array filled with floats -static PyObject* gPyGetSpectrum(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyGetSpectrum(PyObject*) { SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance(); @@ -165,111 +188,145 @@ 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*, PyObject*, PyObject*) +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; } -static PyObject* gPyGetPhysicsTicRate(PyObject*, PyObject*, PyObject*) +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(gp_GamePythonPath)]; + 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, gp_GamePythonPath); + } else { + /* Get the dir only */ + BLI_split_dirfile_basic(gp_GamePythonPath, 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"; -static PyObject* gPyGetCurrentScene(PyObject* self, - PyObject* args, - PyObject* kwds) +static PyObject* gPyGetCurrentScene(PyObject* self) { Py_INCREF(gp_KetsjiScene); return (PyObject*) gp_KetsjiScene; @@ -278,17 +335,13 @@ static PyObject* gPyGetCurrentScene(PyObject* self, static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *) { #define pprint(x) std::cout << x << std::endl; - bgl::BL_EXTInfo ext = bgl::RAS_EXT_support; bool count=0; bool support=0; pprint("Supported Extensions..."); -#ifdef GL_ARB_shader_objects - pprint(" GL_ARB_shader_objects supported? "<< (ext._ARB_shader_objects?"yes.":"no.")); + pprint(" GL_ARB_shader_objects supported? "<< (GLEW_ARB_shader_objects?"yes.":"no.")); count = 1; -#endif -#ifdef GL_ARB_vertex_shader - support= ext._ARB_vertex_shader; + support= GLEW_ARB_vertex_shader; pprint(" GL_ARB_vertex_shader supported? "<< (support?"yes.":"no.")); count = 1; if(support){ @@ -307,9 +360,8 @@ static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *) pprint(" Max combined texture units." << max); pprint(""); } -#endif -#ifdef GL_ARB_fragment_shader - support=ext._ARB_fragment_shader; + + support=GLEW_ARB_fragment_shader; pprint(" GL_ARB_fragment_shader supported? "<< (support?"yes.":"no.")); count = 1; if(support){ @@ -319,9 +371,8 @@ static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *) pprint(" Max uniform components." << max); pprint(""); } -#endif -#ifdef GL_ARB_texture_cube_map - support = ext._ARB_texture_cube_map; + + support = GLEW_ARB_texture_cube_map; pprint(" GL_ARB_texture_cube_map supported? "<< (support?"yes.":"no.")); count = 1; if(support){ @@ -331,9 +382,8 @@ static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *) pprint(" Max cubemap size." << size); pprint(""); } -#endif -#ifdef GL_ARB_multitexture - support = ext._ARB_multitexture; + + support = GLEW_ARB_multitexture; count = 1; pprint(" GL_ARB_multitexture supported? "<< (support?"yes.":"no.")); if(support){ @@ -343,63 +393,52 @@ static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *) pprint(" Max texture units available. " << units); pprint(""); } -#endif -#ifdef GL_ARB_texture_env_combine - pprint(" GL_ARB_texture_env_combine supported? "<< (ext._ARB_texture_env_combine?"yes.":"no.")); + + pprint(" GL_ARB_texture_env_combine supported? "<< (GLEW_ARB_texture_env_combine?"yes.":"no.")); count = 1; -#endif + if(!count) pprint("No extenstions are used in this build"); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } static struct PyMethodDef game_methods[] = { + {"expandPath", (PyCFunction)gPyExpandPath, METH_VARARGS, (PY_METHODCHAR)gPyExpandPath_doc}, {"getCurrentController", (PyCFunction) SCA_PythonController::sPyGetCurrentController, - METH_VARARGS, SCA_PythonController::sPyGetCurrentController__doc__}, + METH_NOARGS, (PY_METHODCHAR)SCA_PythonController::sPyGetCurrentController__doc__}, {"getCurrentScene", (PyCFunction) gPyGetCurrentScene, - METH_VARARGS, 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_VARARGS,gPyGetRandomFloat_doc.Ptr()}, - {"setGravity",(PyCFunction) gPySetGravity, METH_VARARGS,"set Gravitation"}, - {"getSpectrum",(PyCFunction) gPyGetSpectrum, METH_VARARGS,"get audio spectrum"}, - {"stopDSP",(PyCFunction) gPyStopDSP, METH_VARARGS,"stop using the audio dsp (for performance reasons)"}, - {"getLogicTicRate", (PyCFunction) gPyGetLogicTicRate, METH_VARARGS, "Gets the logic tic rate"}, - {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, "Sets the logic tic rate"}, - {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_VARARGS, "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)); } @@ -407,264 +446,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 - { - Py_Return; - } - Py_Return; + if (!PyArg_ParseTuple(args,"i",&visible)) + return NULL; + + 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 (!PyArg_ParseTuple(args,"i",&visible)) + return NULL; + + if (visible) { - if (visible) - { - if (gp_Canvas) - gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); - } else - { - if (gp_Canvas) - gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); - } + 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); - } + 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); - } + 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); - } + 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); } - Py_Return; + + Py_RETURN_NONE; } -static PyObject* gPyEnableMotionBlur(PyObject*, - PyObject* args, - PyObject*) +static PyObject* gPyEnableMotionBlur(PyObject*, PyObject* args) { float motionblurvalue; - if (PyArg_ParseTuple(args,"f",&motionblurvalue)) - { - if(gp_Rasterizer) - { - gp_Rasterizer->EnableMotionBlur(motionblurvalue); + if (!PyArg_ParseTuple(args,"f",&motionblurvalue)) + return NULL; + + if (!gp_Rasterizer) { + PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available"); + return NULL; + } + + gp_Rasterizer->EnableMotionBlur(motionblurvalue); + + Py_RETURN_NONE; +} + +static PyObject* gPyDisableMotionBlur(PyObject*, PyObject* args) +{ + 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(); + } + + 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; } -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* 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); +} + +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)"}, @@ -678,11 +856,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[] = @@ -695,11 +881,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; @@ -711,10 +898,14 @@ 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); - + // XXXX Add constants here /* To use logic bricks, we need some sort of constants. Here, we associate */ /* constants and sumbolic names. Add them to dictionary d. */ @@ -737,6 +928,15 @@ PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ROTX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTX); KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ROTY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTY); KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ROTZ, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTZ); + KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_DIRPX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPX); + KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_DIRPY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPY); + KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_DIRPY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPY); + KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_DIRNX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNX); + KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_DIRNY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNY); + KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_DIRNY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNY); + KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ORIX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIX); + KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ORIY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIY); + KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ORIZ, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIZ); /* 4. Ipo actuator, simple part */ KX_MACRO_addTypesToDict(d, KX_IPOACT_PLAY, KX_IpoActuator::KX_ACT_IPO_PLAY); @@ -803,37 +1003,75 @@ 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()) { Py_FatalError("can't initialize module GameLogic"); } - return d; -} - -void dictionaryClearByHand(PyObject *dict) -{ - // Clears the dictionary by hand: - // This prevents, extra references to global variables - // inside the GameLogic dictionary when the python interpreter is finalized. - // which allows the scene to safely delete them :) - // see: (space.c)->start_game - if(dict) PyDict_Clear(dict); + return m; } - // Python Sandbox code // 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) { @@ -843,9 +1081,17 @@ PyObject *KXpy_import(PyObject *self, PyObject *args) PyObject *fromlist = NULL; PyObject *l, *m, *n; +#if (PY_VERSION_HEX >= 0x02060000) + int dummy_val; /* what does this do?*/ + + if (!PyArg_ParseTuple(args, "s|OOOi:m_import", + &name, &globals, &locals, &fromlist, &dummy_val)) + return NULL; +#else if (!PyArg_ParseTuple(args, "s|OOO:m_import", &name, &globals, &locals, &fromlist)) return NULL; +#endif /* check for builtin modules */ m = PyImport_AddModule("sys"); @@ -859,7 +1105,7 @@ PyObject *KXpy_import(PyObject *self, PyObject *args) /* quick hack for GamePython modules TODO: register builtin modules properly by ExtendInittab */ if (!strcmp(name, "GameLogic") || !strcmp(name, "GameKeys") || !strcmp(name, "PhysicsConstraints") || - !strcmp(name, "Rasterizer")) { + !strcmp(name, "Rasterizer") || !strcmp(name, "Mathutils")) { return PyImport_ImportModuleEx(name, globals, locals, fromlist); } @@ -869,40 +1115,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; /* @@ -985,6 +1258,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 @@ -1006,9 +1284,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 } }; @@ -1152,7 +1459,111 @@ PyObject* initGameKeys() return d; } -void PHY_SetActiveScene(class KX_Scene* scene) +PyObject* initMathutils() +{ + return NULL; //XXX Mathutils_Init("Mathutils"); // Use as a top level module in BGE +} + +void KX_SetActiveScene(class KX_Scene* scene) { gp_KetsjiScene = scene; } + +class KX_Scene* KX_GetActiveScene() +{ + return gp_KetsjiScene; +} + +class KX_KetsjiEngine* KX_GetActiveEngine() +{ + return gp_KetsjiEngine; +} + +// utility function for loading and saving the globalDict +int saveGamePythonConfig( char **marshal_buffer) +{ + 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 { + PyErr_Clear(); + 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) { + PyObject* pyGlobalDict_orig = PyDict_GetItemString(PyModule_GetDict(gameLogic), "globalDict"); // Same as importing the module. + if (pyGlobalDict_orig) { + PyDict_Clear(pyGlobalDict_orig); + PyDict_Update(pyGlobalDict_orig, pyGlobalDict); + } else { + /* this should not happen, but cant find the original globalDict, just assign it then */ + PyDict_SetItemString(PyModule_GetDict(gameLogic), "globalDict", pyGlobalDict); // Same as importing the module. + } + Py_DECREF(gameLogic); + Py_DECREF(pyGlobalDict); + return 1; + } else { + Py_DECREF(gameLogic); + PyErr_Clear(); + printf("Error could not marshall string\n"); + } + } else { + PyErr_Clear(); + printf("Error, GameLogic failed to import GameLogic.globalDict will be lost\n"); + } + } + return 0; +} + +void pathGamePythonConfig( char *path ) +{ + int len = strlen(gp_GamePythonPath); + + BLI_strncpy(path, gp_GamePythonPath, sizeof(gp_GamePythonPath)); + + /* replace extension */ + if (BLI_testextensie(path, ".blend")) { + strcpy(path+(len-6), ".bgeconf"); + } else { + strcpy(path+len, ".bgeconf"); + } +} + +void setGamePythonPath(char *path) +{ + BLI_strncpy(gp_GamePythonPath, path, sizeof(gp_GamePythonPath)); +} + diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h index b2b66e70f5b..57ee0be9400 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.h +++ b/source/gameengine/Ketsji/KX_PythonInit.h @@ -40,16 +40,27 @@ 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); +PyObject* initMathutils(); +PyObject* initVideoTexture(void); void exitGamePlayerPythonScripting(); PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level); void exitGamePythonScripting(); -void dictionaryClearByHand(PyObject *dict); -void PHY_SetActiveScene(class KX_Scene* scene); +void setGamePythonPath(char *path); +void pathGamePythonConfig( char *path ); +int saveGamePythonConfig( char **marshal_buffer); +int loadGamePythonConfig(char *marshal_buffer, int marshal_length); + +class KX_KetsjiEngine; +class KX_Scene; + +void KX_SetActiveScene(class KX_Scene* scene); +class KX_Scene* KX_GetActiveScene(); +class KX_KetsjiEngine* KX_GetActiveEngine(); #include "MT_Vector3.h" void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color); diff --git a/source/gameengine/Ketsji/KX_RadarSensor.cpp b/source/gameengine/Ketsji/KX_RadarSensor.cpp index 66ff1e1e7ca..244e9b75d8e 100644 --- a/source/gameengine/Ketsji/KX_RadarSensor.cpp +++ b/source/gameengine/Ketsji/KX_RadarSensor.cpp @@ -71,7 +71,6 @@ KX_RadarSensor::KX_RadarSensor(SCA_EventManager* eventmgr, //sumoObj->setClientObject(&m_client_info); } - KX_RadarSensor::~KX_RadarSensor() { @@ -81,10 +80,7 @@ CValue* KX_RadarSensor::GetReplica() { KX_RadarSensor* replica = new KX_RadarSensor(*this); replica->m_colliders = new CListValue(); - replica->m_bCollision = false; - replica->m_bTriggered= false; - replica->m_hitObject = NULL; - replica->m_bLastTriggered = false; + replica->Init(); // this will copy properties and so on... CValue::AddDataToReplica(replica); @@ -93,6 +89,10 @@ CValue* KX_RadarSensor::GetReplica() if (replica->m_physCtrl) { replica->m_physCtrl = replica->m_physCtrl->GetReplica(); + if (replica->m_physCtrl) + { + replica->m_physCtrl->setNewClientInfo(replica->m_client_info); + } } //todo: make sure replication works fine! @@ -124,27 +124,48 @@ void KX_RadarSensor::SynchronizeTransform() // depends on the radar 'axis' switch (m_axis) { - case 0: // X Axis + case 0: // +X Axis { MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(90)); trans.rotate(rotquatje); trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0)); break; }; - case 1: // Y Axis + case 1: // +Y Axis { MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-180)); trans.rotate(rotquatje); trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0)); break; }; - case 2: // Z Axis + case 2: // +Z Axis { MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-90)); trans.rotate(rotquatje); trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0)); break; }; + case 3: // -X Axis + { + MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(-90)); + trans.rotate(rotquatje); + trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0)); + break; + }; + case 4: // -Y Axis + { + //MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-180)); + //trans.rotate(rotquatje); + trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0)); + break; + }; + case 5: // -Z Axis + { + MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(90)); + trans.rotate(rotquatje); + trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0)); + break; + }; default: { } @@ -155,8 +176,10 @@ void KX_RadarSensor::SynchronizeTransform() if (m_physCtrl) { - m_physCtrl->setPosition(trans.getOrigin().x(),trans.getOrigin().y(),trans.getOrigin().z()); - m_physCtrl->setOrientation(trans.getRotation().x(),trans.getRotation().y(),trans.getRotation().z(),trans.getRotation().w()); + MT_Quaternion orn = trans.getRotation(); + MT_Point3 pos = trans.getOrigin(); + m_physCtrl->setPosition(pos[0],pos[1],pos[2]); + m_physCtrl->setOrientation(orn[0],orn[1],orn[2],orn[3]); m_physCtrl->calcXform(); } @@ -198,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 }; @@ -211,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."; @@ -228,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, @@ -244,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 288a936e1b1..974d4b992a6 100644 --- a/source/gameengine/Ketsji/KX_RayCast.cpp +++ b/source/gameengine/Ketsji/KX_RayCast.cpp @@ -29,6 +29,7 @@ */ #include <stdlib.h> +#include <stdio.h> #include "KX_RayCast.h" @@ -39,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. @@ -48,51 +63,52 @@ 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).normalized() ); + 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; - - - // 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_RayEventManager.cpp b/source/gameengine/Ketsji/KX_RayEventManager.cpp index 4101c6b547e..1af29151adf 100644 --- a/source/gameengine/Ketsji/KX_RayEventManager.cpp +++ b/source/gameengine/Ketsji/KX_RayEventManager.cpp @@ -44,14 +44,9 @@ using namespace std; void KX_RayEventManager::NextFrame() { - for (vector<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++) + for (set<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++) { - SCA_ISensor *sensor = *i; - sensor->Activate(m_logicmgr, NULL); + (*i)->Activate(m_logicmgr, NULL); } } -void KX_RayEventManager::RegisterSensor(SCA_ISensor* sensor) -{ - m_sensors.push_back(sensor); -}; diff --git a/source/gameengine/Ketsji/KX_RayEventManager.h b/source/gameengine/Ketsji/KX_RayEventManager.h index 3630f9682b9..b816d4d5250 100644 --- a/source/gameengine/Ketsji/KX_RayEventManager.h +++ b/source/gameengine/Ketsji/KX_RayEventManager.h @@ -45,7 +45,6 @@ public: m_logicmgr(logicmgr) {} virtual void NextFrame(); - virtual void RegisterSensor(SCA_ISensor* sensor); }; #endif //__KX_RAYEVENTMGR diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp index 4ccb02d34ec..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,19 +59,23 @@ 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_bTriggered(false), - m_axis(axis), - m_rayHit(false), - m_hitObject(NULL) + m_axis(axis) { - + Init(); } - +void KX_RaySensor::Init() +{ + m_bTriggered = (m_invert)?true:false; + m_rayHit = false; + m_hitObject = NULL; + m_reset = true; +} KX_RaySensor::~KX_RaySensor() { @@ -81,9 +86,10 @@ KX_RaySensor::~KX_RaySensor() CValue* KX_RaySensor::GetReplica() { - CValue* replica = new KX_RaySensor(*this); + KX_RaySensor* replica = new KX_RaySensor(*this); // this will copy properties and so on... CValue::AddDataToReplica(replica); + replica->Init(); return replica; } @@ -100,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) @@ -135,20 +135,48 @@ 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; } - + // 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) { bool result = false; + bool reset = m_reset && m_level; m_rayHit = false; m_hitObject = NULL; m_hitPosition = MT_Vector3(0,0,0); @@ -160,6 +188,7 @@ bool KX_RaySensor::Evaluate(CValue* event) MT_Matrix3x3 invmat = matje.inverse(); MT_Vector3 todir; + m_reset = false; switch (m_axis) { case 1: // X @@ -209,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) @@ -232,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 */ @@ -259,9 +287,15 @@ bool KX_RaySensor::Evaluate(CValue* event) // notify logicsystem that ray JUST left the Object result = true; } + else + { + result = false; + } } - + if (reset) + // force an event + result = true; return result; } @@ -301,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, @@ -323,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, @@ -343,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, @@ -363,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 8a317ffaa07..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, @@ -66,8 +69,10 @@ public: virtual bool Evaluate(CValue* event); 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 b31fe16d05d..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 @@ -48,19 +50,28 @@ /* ------------------------------------------------------------------------- */ KX_SCA_AddObjectActuator::KX_SCA_AddObjectActuator(SCA_IObject *gameobj, - CValue* original, + SCA_IObject *original, 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); + m_lastCreatedObject = NULL; m_timeProp = time; } @@ -69,6 +80,8 @@ KX_SCA_AddObjectActuator::KX_SCA_AddObjectActuator(SCA_IObject *gameobj, KX_SCA_AddObjectActuator::~KX_SCA_AddObjectActuator() { + if (m_OriginalObject) + m_OriginalObject->UnregisterActuator(this); if (m_lastCreatedObject) m_lastCreatedObject->Release(); } @@ -108,12 +121,40 @@ CValue* KX_SCA_AddObjectActuator::GetReplica() // this will copy properties and so on... replica->ProcessReplica(); - replica->m_lastCreatedObject=NULL; CValue::AddDataToReplica(replica); return replica; } +void KX_SCA_AddObjectActuator::ProcessReplica() +{ + if (m_OriginalObject) + m_OriginalObject->RegisterActuator(this); + m_lastCreatedObject=NULL; + SCA_IActuator::ProcessReplica(); +} + +bool KX_SCA_AddObjectActuator::UnlinkObject(SCA_IObject* clientobj) +{ + if (clientobj == m_OriginalObject) + { + // this object is being deleted, we cannot continue to track it. + m_OriginalObject = NULL; + return true; + } + return false; +} + +void KX_SCA_AddObjectActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + void **h_obj = (*obj_map)[m_OriginalObject]; + if (h_obj) { + if (m_OriginalObject) + m_OriginalObject->UnregisterActuator(this); + m_OriginalObject = (SCA_IObject*)(*h_obj); + m_OriginalObject->RegisterActuator(this); + } +} /* ------------------------------------------------------------------------- */ @@ -147,14 +188,16 @@ PyParentObject KX_SCA_AddObjectActuator::Parents[] = { NULL }; PyMethodDef KX_SCA_AddObjectActuator::Methods[] = { - {"setObject", (PyCFunction) KX_SCA_AddObjectActuator::sPySetObject, METH_VARARGS, 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 }; @@ -166,114 +209,101 @@ PyObject* KX_SCA_AddObjectActuator::_getattr(const STR_String& attr) } /* 1. setObject */ -char KX_SCA_AddObjectActuator::SetObject_doc[] = -"setObject(name)\n" -"\t- name: string\n" +const char KX_SCA_AddObjectActuator::SetObject_doc[] = +"setObject(object)\n" +"\t- object: KX_GameObject, string or None\n" "\tSets the object that will be added. There has to be an object\n" "\tof this name. If not, this function does nothing.\n"; - - - -PyObject* KX_SCA_AddObjectActuator::PySetObject(PyObject* self, - PyObject* args, - PyObject* kwds) -{ - PyObject* gameobj; - if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj)) - { - m_OriginalObject = (CValue*)gameobj; - Py_Return; - } - PyErr_Clear(); +PyObject* KX_SCA_AddObjectActuator::PySetObject(PyObject* self, PyObject* value) +{ + KX_GameObject *gameobj; - char* objectname; - if (PyArg_ParseTuple(args, "s", &objectname)) - { - m_OriginalObject= (CValue*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname));; - - Py_Return; - } + if (!ConvertPythonToGameObject(value, &gameobj, true)) + return NULL; // ConvertPythonToGameObject sets the error + + if (m_OriginalObject != NULL) + m_OriginalObject->UnregisterActuator(this); + + m_OriginalObject = (SCA_IObject*)gameobj; + if (m_OriginalObject) + m_OriginalObject->RegisterActuator(this); - return NULL; + Py_RETURN_NONE; } /* 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[] = -"getObject()\n" +const char KX_SCA_AddObjectActuator::GetObject_doc[] = +"getObject(name_only = 1)\n" +"name_only - optional arg, when true will return the KX_GameObject rather then its name\n" "\tReturns the name of the object that will be added.\n"; - - - -PyObject* KX_SCA_AddObjectActuator::PyGetObject(PyObject* self, - PyObject* args, - PyObject* kwds) +PyObject* KX_SCA_AddObjectActuator::PyGetObject(PyObject* self, PyObject* args) { + int ret_name_only = 1; + if (!PyArg_ParseTuple(args, "|i", &ret_name_only)) + return NULL; + if (!m_OriginalObject) - Py_Return; - - return PyString_FromString(m_OriginalObject->GetName()); + Py_RETURN_NONE; + + if (ret_name_only) + return PyString_FromString(m_OriginalObject->GetName()); + else + return m_OriginalObject->AddRef(); } /* 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; } @@ -281,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]; @@ -299,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() @@ -310,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) @@ -323,36 +391,37 @@ void KX_SCA_AddObjectActuator::InstantAddObject() m_lastCreatedObject = replica; m_lastCreatedObject->AddRef(); + // finished using replica? then release it + replica->Release(); } } -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 2126a646303..278d4180284 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h @@ -53,16 +53,20 @@ class KX_SCA_AddObjectActuator : public SCA_IActuator int m_timeProp; /// Original object reference (object to replicate) - CValue* m_OriginalObject; + SCA_IObject* m_OriginalObject; /// Object will be added to the following scene SCA_IScene* m_scene; /// 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; @@ -75,11 +79,13 @@ public: KX_SCA_AddObjectActuator( SCA_IObject *gameobj, - CValue* original, + SCA_IObject *original, int time, SCA_IScene* scene, const MT_Vector3& linvel, - bool local, + bool linv_local, + const MT_Vector3& angvel, + bool angv_local, PyTypeObject* T=&Type ); @@ -89,6 +95,15 @@ public: GetReplica( ) ; + virtual void + ProcessReplica(); + + virtual bool + UnlinkObject(SCA_IObject* clientobj); + + virtual void + Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map); + virtual bool Update(); @@ -104,21 +119,25 @@ public: void InstantAddObject(); /* 1. setObject */ - KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,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(KX_SCA_AddObjectActuator,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_DynamicActuator.cpp b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp new file mode 100644 index 00000000000..d44ab477749 --- /dev/null +++ b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp @@ -0,0 +1,206 @@ +// +// Adjust dynamics settins for this object +// +// $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 ***** + +// +// Previously existed as: + +// \source\gameengine\GameLogic\SCA_DynamicActuator.cpp + +// Please look here for revision history. + +#include "KX_SCA_DynamicActuator.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ + +/* Integration hooks ------------------------------------------------------- */ + + PyTypeObject + +KX_SCA_DynamicActuator:: + +Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "KX_SCA_DynamicActuator", + sizeof(KX_SCA_DynamicActuator), + 0, + PyDestructor, + 0, + __getattr, + __setattr, + 0, + __repr, + 0, + 0, + 0, + 0, + 0 +}; + +PyParentObject KX_SCA_DynamicActuator::Parents[] = { + &KX_SCA_DynamicActuator::Type, + &SCA_IActuator::Type, + &SCA_ILogicBrick::Type, + &CValue::Type, + NULL +}; + + +PyMethodDef KX_SCA_DynamicActuator::Methods[] = { + KX_PYMETHODTABLE(KX_SCA_DynamicActuator, setOperation), + KX_PYMETHODTABLE(KX_SCA_DynamicActuator, getOperation), + {NULL,NULL} //Sentinel +}; + + + +PyObject* KX_SCA_DynamicActuator::_getattr(const STR_String& attr) +{ + _getattr_up(SCA_IActuator); +} + + + +/* 1. setOperation */ +KX_PYMETHODDEF_DOC(KX_SCA_DynamicActuator, setOperation, +"setOperation(operation?)\n" +"\t - operation? : type of dynamic operation\n" +"\t 0 = restore dynamics\n" +"\t 1 = disable dynamics\n" +"\t 2 = enable rigid body\n" +"\t 3 = disable rigid body\n" +"Change the dynamic status of the parent object.\n") +{ + int dyn_operation; + + if (!PyArg_ParseTuple(args, "i", &dyn_operation)) + { + return NULL; + } + if (dyn_operation <0 || dyn_operation>3) { + PyErr_SetString(PyExc_IndexError, "Dynamic Actuator's setOperation() range must be between 0 and 3"); + return NULL; + } + m_dyn_operation= dyn_operation; + Py_Return; +} + +KX_PYMETHODDEF_DOC(KX_SCA_DynamicActuator, getOperation, +"getOperation() -> integer\n" +"Returns the operation type of this actuator.\n" +) +{ + return PyInt_FromLong((long)m_dyn_operation); +} + + +/* ------------------------------------------------------------------------- */ +/* Native functions */ +/* ------------------------------------------------------------------------- */ + +KX_SCA_DynamicActuator::KX_SCA_DynamicActuator(SCA_IObject *gameobj, + short dyn_operation, + PyTypeObject* T) : + + SCA_IActuator(gameobj, T), + m_dyn_operation(dyn_operation) +{ +} /* End of constructor */ + + +KX_SCA_DynamicActuator::~KX_SCA_DynamicActuator() +{ + // there's nothing to be done here, really.... +} /* end of destructor */ + + + +bool KX_SCA_DynamicActuator::Update() +{ + // bool result = false; /*unused*/ + KX_GameObject *obj = (KX_GameObject*) GetParent(); + bool bNegativeEvent = IsNegativeEvent(); + KX_IPhysicsController* controller; + RemoveAllEvents(); + + if (bNegativeEvent) + return false; // do nothing on negative events + + if (!obj) + return false; // object not accessible, shouldnt happen + controller = obj->GetPhysicsController(); + if (!controller) + return false; // no physic object + + switch (m_dyn_operation) + { + case 0: + obj->RestoreDynamics(); + break; + case 1: + obj->SuspendDynamics(); + break; + case 2: + controller->setRigidBody(true); + break; + case 3: + controller->setRigidBody(false); + break; + } + + return false; +} + + + +CValue* KX_SCA_DynamicActuator::GetReplica() +{ + KX_SCA_DynamicActuator* replica = + new KX_SCA_DynamicActuator(*this); + + if (replica == NULL) + return NULL; + + replica->ProcessReplica(); + + // this will copy properties and so on... + CValue::AddDataToReplica(replica); + + return replica; +}; + + +/* eof */ diff --git a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h new file mode 100644 index 00000000000..b47c3a511d9 --- /dev/null +++ b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h @@ -0,0 +1,76 @@ +// +// Add object to the game world on action of this actuator +// +// $Id$ +// +// ***** BEGIN GPL LICENSE BLOCK ***** +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +// All rights reserved. +// +// The Original Code is: all of this file. +// +// Contributor(s): Campbell Barton +// +// ***** END GPL LICENSE BLOCK ***** +// + +#ifndef __KX_SCA_DYNAMICACTUATOR +#define __KX_SCA_DYNAMICACTUATOR + +#include "SCA_IActuator.h" +#include "SCA_PropertyActuator.h" +#include "SCA_LogicManager.h" + +#include "KX_GameObject.h" +#include "KX_IPhysicsController.h" + +class KX_SCA_DynamicActuator : public SCA_IActuator +{ + Py_Header; + + // dynamics operation to apply to the game object + short m_dyn_operation; + public: + KX_SCA_DynamicActuator( + SCA_IObject* gameobj, + short dyn_operation, + PyTypeObject* T=&Type + ); + + ~KX_SCA_DynamicActuator( + ); + + CValue* + GetReplica( + ); + + virtual bool + Update(); + + virtual PyObject* + _getattr( + const STR_String& attr + ); + + /* 1. setOperation */ + KX_PYMETHOD_DOC(KX_SCA_DynamicActuator,setOperation); + KX_PYMETHOD_DOC(KX_SCA_DynamicActuator,getOperation); + +}; + +#endif 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_SG_NodeRelationships.h b/source/gameengine/Ketsji/KX_SG_NodeRelationships.h index d83fb79ee25..faa650106c8 100644 --- a/source/gameengine/Ketsji/KX_SG_NodeRelationships.h +++ b/source/gameengine/Ketsji/KX_SG_NodeRelationships.h @@ -129,6 +129,12 @@ public : ~KX_VertexParentRelation( ); + bool + IsVertexRelation( + ) { + return true; + } + private : KX_VertexParentRelation( @@ -171,8 +177,23 @@ public : NewCopy( ); + MT_Scalar + GetTimeOffset( + ) { return m_relax; } + + void + SetTimeOffset( + MT_Scalar relaxation + ) { m_relax = relaxation; } + ~KX_SlowParentRelation( ); + + bool + IsSlowRelation( + ) { + return true; + } private : diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 7f7558b0ab7..caa71441b1d 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -32,10 +32,12 @@ #pragma warning (disable : 4786) #endif //WIN32 + #include "KX_Scene.h" #include "MT_assert.h" #include "KX_KetsjiEngine.h" +#include "KX_BlenderMaterial.h" #include "RAS_IPolygonMaterial.h" #include "ListValue.h" #include "SCA_LogicManager.h" @@ -47,6 +49,7 @@ #include "SCA_KeyboardManager.h" #include "SCA_MouseManager.h" #include "SCA_PropertyEventManager.h" +#include "SCA_ActuatorEventManager.h" #include "KX_Camera.h" #include "SCA_JoystickManager.h" @@ -64,6 +67,9 @@ #include "SG_Controller.h" #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" @@ -71,15 +77,26 @@ #include "NG_NetworkScene.h" #include "PHY_IPhysicsEnvironment.h" #include "KX_IPhysicsController.h" +#include "KX_BlenderSceneConverter.h" -#include "BL_SkinDeformer.h" +#include "BL_ShapeDeformer.h" #include "BL_DeformableGameObject.h" +// to get USE_BULLET! +#include "KX_ConvertPhysicsObject.h" + +#ifdef USE_BULLET +#include "CcdPhysicsEnvironment.h" +#include "CcdPhysicsController.h" +#endif void* KX_SceneReplicationFunc(SG_IObject* node,void* gameobj,void* scene) { KX_GameObject* replica = ((KX_Scene*)scene)->AddNodeReplicaObject(node,(KX_GameObject*)gameobj); + if(replica) + replica->Release(); + return (void*)replica; } @@ -100,16 +117,19 @@ 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), + m_sceneConverter(NULL), m_physicsEnvironment(0), m_sceneName(sceneName), 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; @@ -121,6 +141,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_objectlist = new CListValue(); m_parentlist = new CListValue(); m_lightlist= new CListValue(); + m_inactivelist = new CListValue(); m_euthanasyobjects = new CListValue(); m_delayReleaseObjects = new CListValue(); @@ -132,22 +153,32 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, SCA_AlwaysEventManager* alwaysmgr = new SCA_AlwaysEventManager(m_logicmgr); SCA_PropertyEventManager* propmgr = new SCA_PropertyEventManager(m_logicmgr); + SCA_ActuatorEventManager* actmgr = new SCA_ActuatorEventManager(m_logicmgr); SCA_RandomEventManager* rndmgr = new SCA_RandomEventManager(m_logicmgr); KX_RayEventManager* raymgr = new KX_RayEventManager(m_logicmgr); 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); + m_logicmgr->RegisterEventManager(actmgr); m_logicmgr->RegisterEventManager(m_keyboardmgr); m_logicmgr->RegisterEventManager(m_mousemgr); m_logicmgr->RegisterEventManager(m_timemgr); 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); @@ -167,13 +198,14 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, KX_Scene::~KX_Scene() { - -// int numobj = m_objectlist->GetCount(); + // The release of debug properties used to be in SCA_IScene::~SCA_IScene + // It's still there but we remove all properties here otherwise some + // reference might be hanging and causing late release of objects + RemoveAllDebugProperties(); - //int numrootobjects = GetRootParentList()->GetCount(); - for (int i = 0; i < GetRootParentList()->GetCount(); i++) + while (GetRootParentList()->GetCount() > 0) { - KX_GameObject* parentobj = (KX_GameObject*) GetRootParentList()->GetValue(i); + KX_GameObject* parentobj = (KX_GameObject*) GetRootParentList()->GetValue(0); this->RemoveObject(parentobj); } @@ -183,6 +215,9 @@ KX_Scene::~KX_Scene() if (m_parentlist) m_parentlist->Release(); + if (m_inactivelist) + m_inactivelist->Release(); + if (m_lightlist) m_lightlist->Release(); @@ -210,13 +245,9 @@ KX_Scene::~KX_Scene() { delete m_bucketmanager; } - //Py_DECREF(m_attrlist); } - - - void KX_Scene::SetProjectionMatrix(MT_CmMatrix4x4& pmat) { m_projectionmat = pmat; @@ -243,6 +274,11 @@ CListValue* KX_Scene::GetRootParentList() return m_parentlist; } +CListValue* KX_Scene::GetInactiveList() +{ + return m_inactivelist; +} + CListValue* KX_Scene::GetLightList() @@ -263,7 +299,7 @@ SCA_TimeEventManager* KX_Scene::GetTimeEventManager() -set<class KX_Camera*>* KX_Scene::GetCameras() +list<class KX_Camera*>* KX_Scene::GetCameras() { return &m_cameras; } @@ -364,14 +400,26 @@ void KX_Scene::EnableZBufferClearing(bool isclearingZbuffer) void KX_Scene::RemoveNodeDestructObject(class SG_IObject* node,class CValue* gameobj) { KX_GameObject* orgobj = (KX_GameObject*)gameobj; - NewRemoveObject(orgobj); - + if (NewRemoveObject(orgobj) != 0) + { + // object is not yet deleted (this can happen when it hangs in an add object actuator + // last object created reference. It's a bad situation, don't know how to fix it exactly + // The least I can do, is remove the reference to the node in the object as the node + // will in any case be deleted. This ensures that the object will not try to use the node + // when it is finally deleted (see KX_GameObject destructor) + orgobj->SetSGNode(NULL); + } if (node) delete node; } KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CValue* gameobj) { + // for group duplication, limit the duplication of the hierarchy to the + // objects that are part of the group. + if (!IsObjectInGroup(gameobj)) + return NULL; + KX_GameObject* orgobj = (KX_GameObject*)gameobj; KX_GameObject* newobj = (KX_GameObject*)orgobj->GetReplica(); m_map_gameobject_to_replica.insert(orgobj, newobj); @@ -415,8 +463,8 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal replicanode->SetSGClientObject(newobj); // this is the list of object that are send to the graphics pipeline - m_objectlist->Add(newobj); - newobj->Bucketize(); + m_objectlist->Add(newobj->AddRef()); + newobj->AddMeshUser(); // logic cannot be replicated, until the whole hierarchy is replicated. m_logicHierarchicalGameObjects.push_back(newobj); @@ -449,6 +497,11 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal // hierarchy that's because first ALL bricks must exist in the new // replica of the hierarchy in order to make cross-links work properly // ! +// It is VERY important that the order of sensors and actuators in +// the replicated object is preserved: it is is used to reconnect the logic. +// This method is more robust then using the bricks name in case of complex +// group replication. The replication of logic bricks is done in +// SCA_IObject::ReParentLogic(), make sure it preserves the order of the bricks. void KX_Scene::ReplicateLogic(KX_GameObject* newobj) { // also relink the controller to sensors/actuators @@ -471,37 +524,38 @@ void KX_Scene::ReplicateLogic(KX_GameObject* newobj) for (vector<SCA_ISensor*>::iterator its = linkedsensors.begin();!(its==linkedsensors.end());its++) { SCA_ISensor* oldsensor = (*its); - STR_String name = oldsensor->GetName(); - //find this name in the list - SCA_ISensor* newsensor = newobj->FindSensor(name); + SCA_IObject* oldsensorobj = oldsensor->GetParent(); + SCA_IObject* newsensorobj = NULL; - if (newsensor) + // the original owner of the sensor has been replicated? + void **h_obj = m_map_gameobject_to_replica[oldsensorobj]; + if (h_obj) + newsensorobj = (SCA_IObject*)(*h_obj); + if (!newsensorobj) { - // relink this newsensor to the controller - m_logicmgr->RegisterToSensor(cont,newsensor); + // no, then the sensor points outside the hierachy, keep it the same + if (m_objectlist->SearchValue(oldsensorobj)) + // only replicate links that points to active objects + m_logicmgr->RegisterToSensor(cont,oldsensor); } else { - // it can be linked somewhere in the hierarchy or... - for (vector<KX_GameObject*>::iterator git = m_logicHierarchicalGameObjects.begin(); - !(git==m_logicHierarchicalGameObjects.end());++git) - { - newsensor = (*git)->FindSensor(name); - if (newsensor) - break; - } + // yes, then the new sensor has the same position + SCA_SensorList& sensorlist = oldsensorobj->GetSensors(); + SCA_SensorList::iterator sit; + SCA_ISensor* newsensor = NULL; + int sensorpos; - if (newsensor) - { - // relink this newsensor to the controller somewhere else within this - // hierarchy - m_logicmgr->RegisterToSensor(cont,newsensor); - } - else + for (sensorpos=0, sit=sensorlist.begin(); sit!=sensorlist.end(); sit++, sensorpos++) { - // must be an external sensor, so... - m_logicmgr->RegisterToSensor(cont,oldsensor); + if ((*sit) == oldsensor) + { + newsensor = newsensorobj->GetSensors().at(sensorpos); + break; + } } + assert(newsensor != NULL); + m_logicmgr->RegisterToSensor(cont,newsensor); } } @@ -509,43 +563,189 @@ void KX_Scene::ReplicateLogic(KX_GameObject* newobj) for (vector<SCA_IActuator*>::iterator ita = linkedactuators.begin();!(ita==linkedactuators.end());ita++) { SCA_IActuator* oldactuator = (*ita); - STR_String name = oldactuator->GetName(); - //find this name in the list - SCA_IActuator* newactuator = newobj->FindActuator(name); - if (newactuator) + SCA_IObject* oldactuatorobj = oldactuator->GetParent(); + SCA_IObject* newactuatorobj = NULL; + + // the original owner of the sensor has been replicated? + void **h_obj = m_map_gameobject_to_replica[oldactuatorobj]; + if (h_obj) + newactuatorobj = (SCA_IObject*)(*h_obj); + + if (!newactuatorobj) { - // relink this newsensor to the controller - m_logicmgr->RegisterToActuator(cont,newactuator); - newactuator->SetUeberExecutePriority(m_ueberExecutionPriority); + // no, then the sensor points outside the hierachy, keep it the same + if (m_objectlist->SearchValue(oldactuatorobj)) + // only replicate links that points to active objects + m_logicmgr->RegisterToActuator(cont,oldactuator); } else { - // it can be linked somewhere in the hierarchy or... - for (vector<KX_GameObject*>::iterator git = m_logicHierarchicalGameObjects.begin(); - !(git==m_logicHierarchicalGameObjects.end());++git) - { - newactuator= (*git)->FindActuator(name); - if (newactuator) - break; - } + // yes, then the new sensor has the same position + SCA_ActuatorList& actuatorlist = oldactuatorobj->GetActuators(); + SCA_ActuatorList::iterator ait; + SCA_IActuator* newactuator = NULL; + int actuatorpos; - if (newactuator) + for (actuatorpos=0, ait=actuatorlist.begin(); ait!=actuatorlist.end(); ait++, actuatorpos++) { - // relink this actuator to the controller somewhere else within this - // hierarchy - m_logicmgr->RegisterToActuator(cont,newactuator); - newactuator->SetUeberExecutePriority(m_ueberExecutionPriority); - } - else - { - // must be an external actuator, so... - m_logicmgr->RegisterToActuator(cont,oldactuator); + if ((*ait) == oldactuator) + { + newactuator = newactuatorobj->GetActuators().at(actuatorpos); + break; + } } + assert(newactuator != NULL); + m_logicmgr->RegisterToActuator(cont,newactuator); + newactuator->SetUeberExecutePriority(m_ueberExecutionPriority); } } } + // ready to set initial state + newobj->ResetState(); } +void KX_Scene::DupliGroupRecurse(CValue* obj, int level) +{ + KX_GameObject* groupobj = (KX_GameObject*) obj; + KX_GameObject* replica; + KX_GameObject* gameobj; + Object* blgroupobj = groupobj->GetBlenderObject(); + Group* group; + GroupObject *go; + vector<KX_GameObject*> duplilist; + + if (!groupobj->GetSGNode() || + !groupobj->IsDupliGroup() || + level>MAX_DUPLI_RECUR) + return; + + // we will add one group at a time + m_logicHierarchicalGameObjects.clear(); + m_map_gameobject_to_replica.clear(); + m_ueberExecutionPriority++; + // for groups will do something special: + // we will force the creation of objects to those in the group only + // Again, this is match what Blender is doing (it doesn't care of parent relationship) + m_groupGameObjects.clear(); + + group = blgroupobj->dup_group; + for(go=(GroupObject*)group->gobject.first; go; go=(GroupObject*)go->next) + { + Object* blenderobj = go->ob; + if (blgroupobj == blenderobj) + // this check is also in group_duplilist() + continue; + + gameobj = (KX_GameObject*)m_logicmgr->FindGameObjByBlendObj(blenderobj); + if (gameobj == NULL) + { + // this object has not been converted!!! + // 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 + continue; + } + m_groupGameObjects.insert(gameobj); + } + + set<CValue*>::iterator oit; + for (oit=m_groupGameObjects.begin(); oit != m_groupGameObjects.end(); oit++) + { + gameobj = (KX_GameObject*)(*oit); + + KX_GameObject *parent = gameobj->GetParent(); + if (parent != NULL) + { + parent->Release(); // GetParent() increased the refcount + + // this object is not a top parent. Either it is the child of another + // object in the group and it will be added automatically when the parent + // is added. Or it is the child of an object outside the group and the group + // is inconsistent, skip it anyway + continue; + } + replica = (KX_GameObject*) AddNodeReplicaObject(NULL,gameobj); + // add to 'rootparent' list (this is the list of top hierarchy objects, updated each frame) + m_parentlist->Add(replica->AddRef()); + + // recurse replication into children nodes + NodeList& children = gameobj->GetSGNode()->GetSGChildren(); + + replica->GetSGNode()->ClearSGChildren(); + for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) + { + SG_Node* orgnode = (*childit); + SG_Node* childreplicanode = orgnode->GetSGReplica(); + if (childreplicanode) + replica->GetSGNode()->AddChild(childreplicanode); + } + // don't replicate logic now: we assume that the objects in the group can have + // logic relationship, even outside parent relationship + // In order to match 3D view, the position of groupobj is used as a + // transformation matrix instead of the new position. This means that + // the group reference point is 0,0,0 + + // get the rootnode's scale + MT_Vector3 newscale = groupobj->NodeGetWorldScaling(); + // set the replica's relative scale with the rootnode's scale + replica->NodeSetRelativeScale(newscale); + + MT_Matrix3x3 newori = groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldOrientation(); + replica->NodeSetLocalOrientation(newori); + + MT_Point3 newpos = groupobj->NodeGetWorldPosition() + + newscale*(groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldPosition()); + replica->NodeSetLocalPosition(newpos); + + replica->GetSGNode()->UpdateWorldData(0); + replica->GetSGNode()->SetBBox(gameobj->GetSGNode()->BBox()); + replica->GetSGNode()->SetRadius(gameobj->GetSGNode()->Radius()); + // done with replica + replica->Release(); + } + + // the logic must be replicated first because we need + // the new logic bricks before relinking + vector<KX_GameObject*>::iterator git; + for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) + { + (*git)->ReParentLogic(); + } + + // relink any pointers as necessary, sort of a temporary solution + for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) + { + // this will also relink the actuator to objects within the hierarchy + (*git)->Relink(&m_map_gameobject_to_replica); + // add the object in the layer of the parent + (*git)->SetLayer(groupobj->GetLayer()); + } + + // replicate crosslinks etc. between logic bricks + for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) + { + ReplicateLogic((*git)); + } + + // now look if object in the hierarchy have dupli group and recurse + for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) + { + if ((*git) != groupobj && (*git)->IsDupliGroup()) + // can't instantiate group immediately as it destroys m_logicHierarchicalGameObjects + duplilist.push_back((*git)); + } + + for (git = duplilist.begin(); !(git == duplilist.end()); ++git) + { + DupliGroupRecurse((*git), level+1); + } +} SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, @@ -555,6 +755,7 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, m_logicHierarchicalGameObjects.clear(); m_map_gameobject_to_replica.clear(); + m_groupGameObjects.clear(); // todo: place a timebomb in the object, for temporarily objects :) // lifespan of zero means 'this object lives forever' @@ -571,7 +772,9 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, // add a timebomb to this object // for now, convert between so called frames and realtime m_tempObjectList->Add(replica->AddRef()); - replica->SetProperty("::timebomb",new CFloatValue(lifespan*0.02)); + CValue *fval = new CFloatValue(lifespan*0.02); + replica->SetProperty("::timebomb",fval); + fval->Release(); } // add to 'rootparent' list (this is the list of top hierarchy objects, updated each frame) @@ -586,22 +789,26 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, { SG_Node* orgnode = (*childit); SG_Node* childreplicanode = orgnode->GetSGReplica(); - replica->GetSGNode()->AddChild(childreplicanode); + if (childreplicanode) + replica->GetSGNode()->AddChild(childreplicanode); } - // relink any pointers as necessary, sort of a temporary solution + // now replicate logic vector<KX_GameObject*>::iterator git; for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) { - (*git)->Relink(&m_map_gameobject_to_replica); + (*git)->ReParentLogic(); } - - // now replicate logic + + // relink any pointers as necessary, sort of a temporary solution for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) { - (*git)->ReParentLogic(); + // this will also relink the actuators in the hierarchy + (*git)->Relink(&m_map_gameobject_to_replica); + // add the object in the layer of the parent + (*git)->SetLayer(parentobj->GetLayer()); } - + // replicate crosslinks etc. between logic bricks for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) { @@ -620,21 +827,24 @@ 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()) - { - 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()); - + // check if there are objects with dupligroup in the hierarchy + vector<KX_GameObject*> duplilist; + for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) + { + if ((*git)->IsDupliGroup()) + { + // separate list as m_logicHierarchicalGameObjects is also used by DupliGroupRecurse() + duplilist.push_back(*git); + } + } + for (git = duplilist.begin();!(git==duplilist.end());++git) + { + DupliGroupRecurse(*git, 0); + } + // don't release replica here because we are returning it, not done with it... return replica; } @@ -654,7 +864,8 @@ void KX_Scene::RemoveObject(class CValue* gameobj) // recursively destruct node->Destruct(); } - newobj->SetSGNode(0); + //no need to do that: the object is destroyed and memory released + //newobj->SetSGNode(0); } void KX_Scene::DelayedReleaseObject(CValue* gameobj) @@ -674,10 +885,17 @@ void KX_Scene::DelayedRemoveObject(class CValue* gameobj) -void KX_Scene::NewRemoveObject(class CValue* gameobj) +int KX_Scene::NewRemoveObject(class CValue* gameobj) { + int ret; KX_GameObject* newobj = (KX_GameObject*) gameobj; + // keep the blender->game object association up to date + // note that all the replicas of an object will have the same + // blender object, that's why we need to check the game object + // as only the deletion of the original object must be recorded + m_logicmgr->UnregisterGameObj(newobj->GetBlenderObject(), gameobj); + //todo: look at this //GetPhysicsEnvironment()->RemovePhysicsController(gameobj->getPhysicsController()); @@ -694,8 +912,7 @@ void KX_Scene::NewRemoveObject(class CValue* gameobj) for (SCA_ControllerList::iterator itc = controllers.begin(); !(itc==controllers.end());itc++) { - (*itc)->UnlinkAllSensors(); - (*itc)->UnlinkAllActuators(); + m_logicmgr->RemoveController(*itc); } SCA_ActuatorList& actuators = newobj->GetActuators(); @@ -704,6 +921,7 @@ void KX_Scene::NewRemoveObject(class CValue* gameobj) { m_logicmgr->RemoveDestroyedActuator(*ita); } + // the sensors/controllers/actuators must also be released, this is done in ~SCA_IObject // now remove the timer properties from the time manager int numprops = newobj->GetPropertyCount(); @@ -718,113 +936,138 @@ void 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)) - newobj->Release(); + ret = newobj->Release(); if (m_tempObjectList->RemoveValue(newobj)) - newobj->Release(); + ret = newobj->Release(); if (m_parentlist->RemoveValue(newobj)) - newobj->Release(); + ret = newobj->Release(); + if (m_inactivelist->RemoveValue(newobj)) + ret = newobj->Release(); if (m_euthanasyobjects->RemoveValue(newobj)) - newobj->Release(); + ret = newobj->Release(); if (newobj == m_active_camera) { - m_active_camera->Release(); + //no AddRef done on m_active_camera so no Release + //m_active_camera->Release(); m_active_camera = NULL; } + + // in case this is a camera + m_cameras.remove((KX_Camera*)newobj); + + if (m_sceneConverter) + m_sceneConverter->UnregisterGameObject(newobj); + // return value will be 0 if the object is actually deleted (all reference gone) + return ret; } -void KX_Scene::ReplaceMesh(class CValue* gameobj,void* meshobj) +void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj) { - KX_GameObject* newobj = static_cast<KX_GameObject*>(gameobj); + KX_GameObject* gameobj = static_cast<KX_GameObject*>(obj); RAS_MeshObject* mesh = static_cast<RAS_MeshObject*>(meshobj); - const STR_String origMeshName = newobj->GetMesh(0)->GetName(); - - if( !newobj || !mesh ) + if(!gameobj || !mesh) { std::cout << "warning: invalid object, mesh will not be replaced" << std::endl; return; } - newobj->RemoveMeshes(); - newobj->AddMesh(mesh); - - bool isDeformer = (newobj->m_isDeformable && mesh->m_class == 1); - if(isDeformer) - { - /* FindBlendObjByGameObj() can return 0... - In the case of 0 here, - the replicated object that is calling this function - is some how not in the map. (which is strange because it's added) - So we will search the map by the first mesh name - to try to locate it there. If its still not found - spit some message rather than crash - */ - Object* blendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameObj(newobj)); - Object* oldblendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(mesh->GetName())); + gameobj->RemoveMeshes(); + gameobj->AddMesh(mesh); - bool parSkin = blendobj && blendobj->parent && blendobj->parent->type == OB_ARMATURE && blendobj->partype==PARSKEL; - bool releaseParent = true; - KX_GameObject* parentobj = newobj->GetParent(); - - - // lookup by mesh name if blendobj is 0 - if( !blendobj && parentobj ) + if (gameobj->m_isDeformable) + { + BL_DeformableGameObject* newobj = static_cast<BL_DeformableGameObject*>( gameobj ); + + if (newobj->GetDeformer()) { - blendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(origMeshName)); - - // replace the mesh on the parent armature - if( blendobj ) - parSkin = parentobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE; - - // can't do it - else - std::cout << "warning: child object for " << parentobj->GetName().ReadPtr() - << " not found, and can't create!" << std::endl; + delete newobj->GetDeformer(); + newobj->SetDeformer(NULL); } - if( blendobj && oldblendobj ) + if (mesh->IsDeformed()) { - isDeformer = (static_cast<Mesh*>(blendobj->data)->dvert != 0); - BL_DeformableGameObject* deformIter =0; - - // armature parent - if( parSkin && isDeformer ) + // we must create a new deformer but which one? + KX_GameObject* parentobj = newobj->GetParent(); + // this always return the original game object (also for replicate) + Object* blendobj = newobj->GetBlenderObject(); + // object that owns the new mesh + Object* oldblendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(mesh->GetName())); + Mesh* blendmesh = mesh->GetMesh(); + + bool bHasShapeKey = blendmesh->key != NULL && blendmesh->key->type==KEY_RELATIVE; + bool bHasDvert = blendmesh->dvert != NULL; + bool bHasArmature = + parentobj && // current parent is armature + parentobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE && + oldblendobj && // needed for mesh deform + blendobj->parent && // original object had armature (not sure this test is needed) + blendobj->parent->type == OB_ARMATURE && + blendobj->partype==PARSKEL && + blendmesh->dvert!=NULL; // mesh has vertex group + bool releaseParent = true; + + if (bHasShapeKey) + { + BL_ShapeDeformer* shapeDeformer; + if (bHasArmature) + { + shapeDeformer = new BL_ShapeDeformer( + newobj, + oldblendobj, blendobj, + static_cast<BL_SkinMeshObject*>(mesh), + true, + static_cast<BL_ArmatureObject*>( parentobj ) + ); + releaseParent= false; + shapeDeformer->LoadShapeDrivers(blendobj->parent); + } + else + { + shapeDeformer = new BL_ShapeDeformer( + newobj, + oldblendobj, blendobj, + static_cast<BL_SkinMeshObject*>(mesh), + false, + NULL + ); + } + newobj->SetDeformer( shapeDeformer); + } + else if (bHasArmature) { - deformIter = static_cast<BL_DeformableGameObject*>( newobj ); - delete deformIter->m_pDeformer; - BL_SkinDeformer* skinDeformer = new BL_SkinDeformer( + newobj, oldblendobj, blendobj, static_cast<BL_SkinMeshObject*>(mesh), true, static_cast<BL_ArmatureObject*>( parentobj ) ); releaseParent= false; - deformIter->m_pDeformer = skinDeformer; + newobj->SetDeformer(skinDeformer); } - - // normal deformer - if( !parSkin && isDeformer) + else if (bHasDvert) { - deformIter = static_cast<BL_DeformableGameObject*>( newobj ); - delete deformIter->m_pDeformer; - BL_MeshDeformer* meshdeformer = new BL_MeshDeformer( - oldblendobj, static_cast<BL_SkinMeshObject*>(mesh) + newobj, oldblendobj, static_cast<BL_SkinMeshObject*>(mesh) ); - - deformIter->m_pDeformer = meshdeformer; + newobj->SetDeformer(meshdeformer); } + + // release parent reference if its not being used + if( releaseParent && parentobj) + parentobj->Release(); } - // release parent reference if its not being used - if( releaseParent && parentobj) - parentobj->Release(); } - newobj->Bucketize(); + + gameobj->AddMeshUser(); } @@ -847,7 +1090,7 @@ MT_CmMatrix4x4& KX_Scene::GetProjectionMatrix() KX_Camera* KX_Scene::FindCamera(KX_Camera* cam) { - set<KX_Camera*>::iterator it = m_cameras.begin(); + list<KX_Camera*>::iterator it = m_cameras.begin(); while ( (it != m_cameras.end()) && ((*it) != cam) ) { @@ -860,7 +1103,7 @@ KX_Camera* KX_Scene::FindCamera(KX_Camera* cam) KX_Camera* KX_Scene::FindCamera(STR_String& name) { - set<KX_Camera*>::iterator it = m_cameras.begin(); + list<KX_Camera*>::iterator it = m_cameras.begin(); while ( (it != m_cameras.end()) && ((*it)->GetName() != name) ) { @@ -872,9 +1115,11 @@ KX_Camera* KX_Scene::FindCamera(STR_String& name) void KX_Scene::AddCamera(KX_Camera* cam) { - m_cameras.insert(cam); + if (!FindCamera(cam)) + m_cameras.push_back(cam); } + KX_Camera* KX_Scene::GetActiveCamera() { // NULL if not defined @@ -893,6 +1138,17 @@ void KX_Scene::SetActiveCamera(KX_Camera* cam) m_active_camera = cam; } +void KX_Scene::SetCameraOnTop(KX_Camera* cam) +{ + if (!FindCamera(cam)){ + // adding is always done at the back, so that's all that needs to be done + AddCamera(cam); + if (cam) std::cout << "Added cam " << cam->GetName() << std::endl; + } else { + m_cameras.remove(cam); + m_cameras.push_back(cam); + } +} void KX_Scene::UpdateMeshTransformations() @@ -906,12 +1162,13 @@ void KX_Scene::UpdateMeshTransformations() } } -void KX_Scene::MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera* cam) +void KX_Scene::MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera* cam, int layer) { int intersect = KX_Camera::INTERSECT; KX_GameObject *gameobj = node->Client()?(KX_GameObject*) node->Client()->GetSGClientObject():NULL; - bool dotest = (gameobj && gameobj->GetVisible()) || node->Left() || node->Right(); - + bool visible = (gameobj && gameobj->GetVisible() && (!layer || (gameobj->GetLayer() & layer))); + bool dotest = visible || node->Left() || node->Right(); + /* If the camera is inside the box, assume intersect. */ if (dotest && !node->inside( cam->NodeGetWorldPosition())) { @@ -935,19 +1192,19 @@ void KX_Scene::MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera* cam break; case KX_Camera::INTERSECT: if (gameobj) - MarkVisible(rasty, gameobj,cam); + MarkVisible(rasty, gameobj, cam, layer); if (node->Left()) - MarkVisible(node->Left(), rasty,cam); + MarkVisible(node->Left(), rasty, cam, layer); if (node->Right()) - MarkVisible(node->Right(), rasty,cam); + MarkVisible(node->Right(), rasty, cam, layer); break; case KX_Camera::INSIDE: - MarkSubTreeVisible(node, rasty, true,cam); + MarkSubTreeVisible(node, rasty, true, cam, layer); break; } } -void KX_Scene::MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible,KX_Camera* cam) +void KX_Scene::MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible, KX_Camera* cam, int layer) { if (node->Client()) { @@ -957,29 +1214,35 @@ void KX_Scene::MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool vi if (visible) { int nummeshes = gameobj->GetMeshCount(); - MT_Transform t( cam->GetWorldToCamera() * gameobj->GetSGNode()->GetWorldTransform()); - + // this adds the vertices to the display list for (int m=0;m<nummeshes;m++) - { - // this adds the vertices to the display list - (gameobj->GetMesh(m))->SchedulePolygons(t, rasty->GetDrawingMode()); - } + (gameobj->GetMesh(m))->SchedulePolygons(rasty->GetDrawingMode()); } - gameobj->MarkVisible(visible); + + gameobj->SetCulled(!visible); + gameobj->UpdateBuckets(false); } } if (node->Left()) - MarkSubTreeVisible(node->Left(), rasty, visible,cam); + MarkSubTreeVisible(node->Left(), rasty, visible, cam, layer); if (node->Right()) - MarkSubTreeVisible(node->Right(), rasty, visible,cam); + MarkSubTreeVisible(node->Right(), rasty, visible, cam, layer); } -void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Camera* cam) +void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Camera* cam,int layer) { // User (Python/Actuator) has forced object invisible... - if (!gameobj->GetVisible()) + if (!gameobj->GetSGNode() || !gameobj->GetVisible()) + return; + + // Shadow lamp layers + if(layer && !(gameobj->GetLayer() & layer)) { + gameobj->SetCulled(true); + gameobj->UpdateBuckets(false); return; + } + // If Frustum culling is off, the object is always visible. bool vis = !cam->GetFrustumCulling(); @@ -1014,35 +1277,36 @@ void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Cam if (vis) { int nummeshes = gameobj->GetMeshCount(); - MT_Transform t(cam->GetWorldToCamera() * gameobj->GetSGNode()->GetWorldTransform()); for (int m=0;m<nummeshes;m++) { // this adds the vertices to the display list - (gameobj->GetMesh(m))->SchedulePolygons(t, rasty->GetDrawingMode()); + (gameobj->GetMesh(m))->SchedulePolygons(rasty->GetDrawingMode()); } // 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); } } -void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam) +void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int layer) { // FIXME: When tree is operational #if 1 // do this incrementally in the future for (int i = 0; i < m_objectlist->GetCount(); i++) { - MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam); + MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam, layer); } #else if (cam->GetFrustumCulling()) - MarkVisible(m_objecttree, rasty, cam); + MarkVisible(m_objecttree, rasty, cam, layer); else - MarkSubTreeVisible(m_objecttree, rasty, true, cam); + MarkSubTreeVisible(m_objecttree, rasty, true, cam, layer); #endif } @@ -1096,6 +1360,8 @@ void KX_Scene::LogicEndFrame() for (i = numobj - 1; i >= 0; i--) { KX_GameObject* gameobj = (KX_GameObject*)m_euthanasyobjects->GetValue(i); + // KX_Scene::RemoveObject will also remove the object from this list + // that's why we start from the end this->RemoveObject(gameobj); } @@ -1103,11 +1369,11 @@ void KX_Scene::LogicEndFrame() for (i = numobj-1;i>=0;i--) { KX_GameObject* gameobj = (KX_GameObject*)m_delayReleaseObjects->GetValue(i); - m_delayReleaseObjects->RemoveValue(gameobj); - + // This list is not for object removal, but just object release + gameobj->Release(); } - - + // empty the list as we have removed all references + m_delayReleaseObjects->Resize(0); } @@ -1128,9 +1394,9 @@ void KX_Scene::UpdateParents(double curtime) -RAS_MaterialBucket* KX_Scene::FindBucket(class RAS_IPolyMaterial* polymat) +RAS_MaterialBucket* KX_Scene::FindBucket(class RAS_IPolyMaterial* polymat, bool &bucketCreated) { - return m_bucketmanager->RAS_BucketManagerFindBucket(polymat); + return m_bucketmanager->FindBucket(polymat, bucketCreated); } @@ -1140,10 +1406,9 @@ void KX_Scene::RenderBuckets(const MT_Transform & cameratransform, class RAS_IRenderTools* rendertools) { m_bucketmanager->Renderbuckets(cameratransform,rasty,rendertools); + KX_BlenderMaterial::EndFrame(); } - - void KX_Scene::UpdateObjectActivity(void) { if (m_activity_culling) { @@ -1212,6 +1477,11 @@ void KX_Scene::SetNodeTree(SG_Tree* root) m_objecttree = root; } +void KX_Scene::SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter) +{ + m_sceneConverter = sceneConverter; +} + void KX_Scene::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* physEnv) { m_physicsEnvironment = physEnv; diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index dbe04a18e0f..5f7e1167e27 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -36,6 +36,7 @@ #include <vector> #include <set> +#include <list> #include "GEN_Map.h" #include "GEN_HashedPtr.h" @@ -53,6 +54,7 @@ */ struct SM_MaterialProps; struct SM_ShapeProps; +struct Scene; class GEN_HashedPtr; class CListValue; @@ -81,6 +83,8 @@ class RAS_IPolyMaterial; class RAS_IRasterizer; class RAS_IRenderTools; class SCA_JoystickManager; +class btCollisionShape; +class KX_BlenderSceneConverter; /** * The KX_Scene holds all data for an independent scene. It relates * KX_Objects to the specific objects in the modules. @@ -107,6 +111,7 @@ protected: CListValue* m_objectlist; CListValue* m_parentlist; // all 'root' parents CListValue* m_lightlist; + CListValue* m_inactivelist; // all objects that are not in the active layer /** * The tree of objects in the scene. @@ -116,8 +121,7 @@ protected: /** * The set of cameras for this scene */ - set<class KX_Camera*> m_cameras; - + list<class KX_Camera*> m_cameras; /** * Various SCA managers used by the scene */ @@ -126,10 +130,12 @@ protected: SCA_MouseManager* m_mousemgr; SCA_TimeEventManager* m_timemgr; + // Scene converter where many scene entities are registered + // Used to deregister objects that are deleted + class KX_BlenderSceneConverter* m_sceneConverter; /** * physics engine abstraction */ - //e_PhysicsEngine m_physicsEngine; //who needs this ? class PHY_IPhysicsEnvironment* m_physicsEnvironment; @@ -206,6 +212,16 @@ protected: */ std::vector<KX_GameObject*> m_logicHierarchicalGameObjects; + /** + * This temporary variable will contain the list of + * object that can be added during group instantiation. + * objects outside this list will not be added (can + * happen with children that are outside the group). + * Used in AddReplicaObject. If the list is empty, it + * means don't care. + */ + std::set<CValue*> m_groupGameObjects; + /** * Pointer to system variable passed in in constructor * only used in constructor so we do not need to keep it @@ -250,9 +266,9 @@ protected: /** * Visibility testing functions. */ - void MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera*cam); - void MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible, KX_Camera*cam); - void MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj, KX_Camera*cam); + void MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera*cam,int layer=0); + void MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible, KX_Camera*cam,int layer=0); + void MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj, KX_Camera*cam, int layer=0); double m_suspendedtime; double m_suspendeddelta; @@ -262,18 +278,21 @@ 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(); RAS_BucketManager* GetBucketManager(); - RAS_MaterialBucket* FindBucket(RAS_IPolyMaterial* polymat); + RAS_MaterialBucket* FindBucket(RAS_IPolyMaterial* polymat, bool &bucketCreated); void RenderBuckets(const MT_Transform& cameratransform, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools); @@ -281,6 +300,12 @@ public: * Update all transforms according to the scenegraph. */ void UpdateParents(double curtime); + void DupliGroupRecurse(CValue* gameobj, int level); + bool IsObjectInGroup(CValue* gameobj) + { + return (m_groupGameObjects.empty() || + m_groupGameObjects.find(gameobj) != m_groupGameObjects.end()); + } SCA_IObject* AddReplicaObject(CValue* gameobj, CValue* locationobj, int lifespan=0); @@ -293,7 +318,7 @@ public: void DelayedReleaseObject(CValue* gameobj); - void NewRemoveObject(CValue* gameobj); + int NewRemoveObject(CValue* gameobj); void ReplaceMesh(CValue* gameobj, void* meshobj); /** @@ -312,6 +337,10 @@ public: ); CListValue* + GetInactiveList( + ); + + CListValue* GetRootParentList( ); @@ -327,7 +356,7 @@ public: GetTimeEventManager( ); - set<class KX_Camera*>* + list<class KX_Camera*>* GetCameras( ); @@ -365,6 +394,15 @@ public: class KX_Camera* ); + /** + * Move this camera to the end of the list so that it is rendered last. + * If the camera is not on the list, it will be added + */ + void + SetCameraOnTop( + class KX_Camera* + ); + /** Return the viewmatrix as used by the last frame. */ MT_CmMatrix4x4& GetViewMatrix( @@ -459,7 +497,7 @@ public: void SetNetworkScene(NG_NetworkScene *newScene); void SetWorldInfo(class KX_WorldInfo* wi); KX_WorldInfo* GetWorldInfo(); - void CalculateVisibleMeshes(RAS_IRasterizer* rasty, KX_Camera *cam); + void CalculateVisibleMeshes(RAS_IRasterizer* rasty, KX_Camera *cam, int layer=0); void UpdateMeshTransformations(); KX_Camera* GetpCamera(); SND_Scene* GetSoundScene(); @@ -493,6 +531,8 @@ public: bool IsClearingZBuffer(); void EnableZBufferClearing(bool isclearingZbuffer); + void SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter); + class PHY_IPhysicsEnvironment* GetPhysicsEnvironment() { return m_physicsEnvironment; @@ -546,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 ce357cd708a..35484699b17 100644 --- a/source/gameengine/Ketsji/KX_SceneActuator.cpp +++ b/source/gameengine/Ketsji/KX_SceneActuator.cpp @@ -58,13 +58,16 @@ KX_SceneActuator::KX_SceneActuator(SCA_IObject *gameobj, m_KetsjiEngine=ketsjiEngine; m_camera = camera; m_nextSceneName = nextSceneName; + if (m_camera) + m_camera->RegisterActuator(this); } /* End of constructor */ KX_SceneActuator::~KX_SceneActuator() { - // there's nothing to be done here, really.... + if (m_camera) + m_camera->UnregisterActuator(this); } /* end of destructor */ @@ -79,6 +82,34 @@ CValue* KX_SceneActuator::GetReplica() return replica; } +void KX_SceneActuator::ProcessReplica() +{ + if (m_camera) + m_camera->RegisterActuator(this); + SCA_IActuator::ProcessReplica(); +} + +bool KX_SceneActuator::UnlinkObject(SCA_IObject* clientobj) +{ + if (clientobj == (SCA_IObject*)m_camera) + { + // this object is being deleted, we cannot continue to track it. + m_camera = NULL; + return true; + } + return false; +} + +void KX_SceneActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + void **h_obj = (*obj_map)[m_camera]; + if (h_obj) { + if (m_camera) + m_camera->UnregisterActuator(this); + m_camera = (KX_Camera*)(*h_obj); + m_camera->RegisterActuator(this); + } +} bool KX_SceneActuator::Update() @@ -102,6 +133,15 @@ bool KX_SceneActuator::Update() { m_scene->SetActiveCamera(m_camera); } + else + { + // if no camera is set and the parent object is a camera, use it as the camera + SCA_IObject* parent = GetParent(); + if (parent->isA(&KX_Camera::Type)) + { + m_scene->SetActiveCamera((KX_Camera*)parent); + } + } break; default: break; @@ -219,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 }; @@ -238,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" ; @@ -261,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, @@ -274,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" ; @@ -299,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, @@ -312,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" ; @@ -323,7 +363,11 @@ PyObject* KX_SceneActuator::PySetCamera(PyObject* self, PyObject *cam; if (PyArg_ParseTuple(args, "O!", &KX_Camera::Type, &cam)) { + if (m_camera) + m_camera->UnregisterActuator(this); m_camera = (KX_Camera*) cam; + if (m_camera) + m_camera->RegisterActuator(this); Py_Return; } PyErr_Clear(); @@ -336,7 +380,13 @@ PyObject* KX_SceneActuator::PySetCamera(PyObject* self, } KX_Camera *camOb = FindCamera(camName); - if (camOb) m_camera = camOb; + if (camOb) + { + if (m_camera) + m_camera->UnregisterActuator(this); + m_camera = camOb; + m_camera->RegisterActuator(this); + } Py_Return; } @@ -344,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_SceneActuator.h b/source/gameengine/Ketsji/KX_SceneActuator.h index cfc79b93f8e..55aaf629d7c 100644 --- a/source/gameengine/Ketsji/KX_SceneActuator.h +++ b/source/gameengine/Ketsji/KX_SceneActuator.h @@ -82,6 +82,9 @@ class KX_SceneActuator : public SCA_IActuator virtual ~KX_SceneActuator(); virtual CValue* GetReplica(); + virtual void ProcessReplica(); + virtual bool UnlinkObject(SCA_IObject* clientobj); + virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map); virtual bool Update(); diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index 949156571a7..afa5af3bc04 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,12 @@ bool KX_SoundActuator::Update(double curtime, bool frame) RemoveAllEvents(); + if (!m_soundObject) + return false; + + // actual audio device playing state + bool isplaying = (m_soundObject->GetPlaystate() != SND_STOPPED) ? true : false; + if (m_pino) { bNegativeEvent = true; @@ -113,30 +122,40 @@ bool KX_SoundActuator::Update(double curtime, bool frame) if (bNegativeEvent) { // here must be a check if it is still playing - m_isplaying = false; - - switch (m_type) + if (m_isplaying && isplaying) { - case KX_SOUNDACT_PLAYSTOP: - case KX_SOUNDACT_LOOPSTOP: - case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: - { - m_soundScene->RemoveActiveObject(m_soundObject); - break; - } - case KX_SOUNDACT_PLAYEND: + switch (m_type) { - m_soundObject->SetPlaystate(SND_MUST_STOP_WHEN_FINISHED); + case KX_SOUNDACT_PLAYSTOP: + case KX_SOUNDACT_LOOPSTOP: + case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: + { + m_soundScene->RemoveActiveObject(m_soundObject); + break; + } + case KX_SOUNDACT_PLAYEND: + { + m_soundObject->SetPlaystate(SND_MUST_STOP_WHEN_FINISHED); + break; + } + case KX_SOUNDACT_LOOPEND: + case KX_SOUNDACT_LOOPBIDIRECTIONAL: + { + m_soundObject->SetLoopMode(SND_LOOP_OFF); + m_soundObject->SetPlaystate(SND_MUST_STOP_WHEN_FINISHED); + break; + } + default: + // implement me !! break; } - default: - // implement me !! - break; } + // remember that we tried to stop the actuator + m_isplaying = false; } else { - if (m_soundObject && !m_isplaying) + if (!m_isplaying) { switch (m_type) { @@ -173,8 +192,10 @@ bool KX_SoundActuator::Update(double curtime, bool frame) } } } + // verify that the sound is still playing + isplaying = (m_soundObject->GetPlaystate() != SND_STOPPED) ? true : false; - if (m_isplaying) + if (isplaying) { m_soundObject->SetPosition(((KX_GameObject*)this->GetParent())->NodeGetWorldPosition()); m_soundObject->SetVelocity(((KX_GameObject*)this->GetParent())->GetLinearVelocity()); @@ -183,14 +204,15 @@ bool KX_SoundActuator::Update(double curtime, bool frame) } else { + m_isplaying = false; result = false; } - + /* if (result && (m_soundObject->IsLifeSpanOver(curtime)) && ((m_type == KX_SOUNDACT_PLAYEND) || (m_type == KX_SOUNDACT_PLAYSTOP))) { m_pino = true; } - + */ return result; } @@ -287,11 +309,16 @@ 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(); if (!name) { - Py_Return; /* internal error */ + PyErr_SetString(PyExc_RuntimeError, "Unable to get sound filename"); + return NULL; } else return PyString_FromString(name); } @@ -300,7 +327,11 @@ 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) + // This has no effect if the actuator is not active. + // To start the sound you must activate the actuator. + // This function is to restart the sound. + m_soundObject->StartSound(); Py_Return; } @@ -308,7 +339,9 @@ 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) + // unfortunately, openal does not implement pause correctly, it is equivalent to a stop + m_soundObject->PauseSound(); Py_Return; } @@ -316,7 +349,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; } @@ -328,7 +362,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; } @@ -337,7 +372,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; @@ -351,7 +386,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; } @@ -360,7 +396,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; @@ -374,7 +410,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; } @@ -383,7 +420,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; @@ -397,7 +434,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; } @@ -406,7 +444,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; @@ -424,7 +462,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; } @@ -441,7 +480,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; } @@ -464,7 +504,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 new file mode 100644 index 00000000000..e360c4bac1f --- /dev/null +++ b/source/gameengine/Ketsji/KX_StateActuator.cpp @@ -0,0 +1,207 @@ +/* + * $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 ***** + * Actuator to toggle visibility/invisibility of objects + */ + +#include "KX_StateActuator.h" +#include "KX_GameObject.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +KX_StateActuator::KX_StateActuator( + SCA_IObject* gameobj, + int operation, + unsigned int mask, + PyTypeObject* T + ) + : SCA_IActuator(gameobj,T), + m_operation(operation), + m_mask(mask) +{ + // intentionally empty +} + +KX_StateActuator::~KX_StateActuator( + void + ) +{ + // intentionally empty +} + +CValue* +KX_StateActuator::GetReplica( + void + ) +{ + KX_StateActuator* replica = new KX_StateActuator(*this); + replica->ProcessReplica(); + // this will copy properties and so on... + CValue::AddDataToReplica(replica); + return replica; +} + +bool +KX_StateActuator::Update() +{ + bool bNegativeEvent = IsNegativeEvent(); + unsigned int objMask; + + RemoveAllEvents(); + if (bNegativeEvent) return false; + + KX_GameObject *obj = (KX_GameObject*) GetParent(); + + objMask = obj->GetState(); + switch (m_operation) + { + case OP_CPY: + objMask = m_mask; + break; + case OP_SET: + objMask |= m_mask; + break; + case OP_CLR: + objMask &= ~m_mask; + break; + case OP_NEG: + objMask ^= m_mask; + break; + default: + // unsupported operation, no nothing + return false; + } + obj->SetState(objMask); + return false; +} + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ + + + +/* Integration hooks ------------------------------------------------------- */ +PyTypeObject +KX_StateActuator::Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "KX_StateActuator", + sizeof(KX_StateActuator), + 0, + PyDestructor, + 0, + __getattr, + __setattr, + 0, //&MyPyCompare, + __repr, + 0, //&cvalue_as_number, + 0, + 0, + 0, + 0 +}; + +PyParentObject +KX_StateActuator::Parents[] = { + &KX_StateActuator::Type, + &SCA_IActuator::Type, + &SCA_ILogicBrick::Type, + &CValue::Type, + NULL +}; + +PyMethodDef +KX_StateActuator::Methods[] = { + {"setOperation", (PyCFunction) KX_StateActuator::sPySetOperation, + METH_VARARGS, (PY_METHODCHAR)SetOperation_doc}, + {"setMask", (PyCFunction) KX_StateActuator::sPySetMask, + METH_VARARGS, (PY_METHODCHAR)SetMask_doc}, + {NULL,NULL} //Sentinel +}; + +PyObject* +KX_StateActuator::_getattr( + const STR_String& attr + ) +{ + _getattr_up(SCA_IActuator); +}; + + + +/* set operation ---------------------------------------------------------- */ +const char +KX_StateActuator::SetOperation_doc[] = +"setOperation(op)\n" +"\t - op : bit operation (0=Copy, 1=Set, 2=Clear, 3=Negate)" +"\tSet the type of bit operation to be applied on object state mask.\n" +"\tUse setMask() to specify the bits that will be modified.\n"; +PyObject* + +KX_StateActuator::PySetOperation(PyObject* self, + PyObject* args, + PyObject* kwds) { + int oper; + + if(!PyArg_ParseTuple(args, "i", &oper)) { + return NULL; + } + + m_operation = oper; + + Py_Return; +} + +/* set mask ---------------------------------------------------------- */ +const char +KX_StateActuator::SetMask_doc[] = +"setMask(mask)\n" +"\t - mask : bits that will be modified" +"\tSet the value that defines the bits that will be modified by the operation.\n" +"\tThe bits that are 1 in the value will be updated in the object state,\n" +"\tthe bits that are 0 are will be left unmodified expect for the Copy operation\n" +"\twhich copies the value to the object state.\n"; +PyObject* + +KX_StateActuator::PySetMask(PyObject* self, + PyObject* args, + PyObject* kwds) { + int mask; + + if(!PyArg_ParseTuple(args, "i", &mask)) { + return NULL; + } + + m_mask = mask; + + Py_Return; +} + + diff --git a/source/gameengine/Ketsji/KX_StateActuator.h b/source/gameengine/Ketsji/KX_StateActuator.h new file mode 100644 index 00000000000..8698e51b2c1 --- /dev/null +++ b/source/gameengine/Ketsji/KX_StateActuator.h @@ -0,0 +1,83 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 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 ***** + * Actuator to toggle visibility/invisibility of objects + */ + +#ifndef __KX_STATEACTUATOR +#define __KX_STATEACTUATOR + +#include "SCA_IActuator.h" + +class KX_StateActuator : public SCA_IActuator +{ + Py_Header; + + /** Make visible? */ + enum { + OP_CPY = 0, + OP_SET, + OP_CLR, + OP_NEG + }; + int m_operation; + unsigned int m_mask; + + public: + + KX_StateActuator( + SCA_IObject* gameobj, + int operation, + unsigned int mask, + PyTypeObject* T=&Type + ); + + virtual + ~KX_StateActuator( + void + ); + + virtual CValue* + GetReplica( + void + ); + + virtual bool + Update(); + + /* --------------------------------------------------------------------- */ + /* Python interface ---------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + + virtual PyObject* _getattr(const STR_String& attr); + //KX_PYMETHOD_DOC + KX_PYMETHOD_DOC(KX_StateActuator,SetOperation); + KX_PYMETHOD_DOC(KX_StateActuator,SetMask); +}; + +#endif + diff --git a/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp b/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp index 6ea5461dbaa..c842ca1ee14 100644 --- a/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp +++ b/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp @@ -101,7 +101,7 @@ void KX_SumoPhysicsController::SetSumoTransform(bool nondynaonly) } -void KX_SumoPhysicsController::SuspendDynamics() +void KX_SumoPhysicsController::SuspendDynamics(bool) { SumoPhysicsController::SuspendDynamics(); } @@ -170,8 +170,9 @@ void KX_SumoPhysicsController::setMargin(float collisionMargin) } -void KX_SumoPhysicsController::setOrientation(const MT_Quaternion& orn) +void KX_SumoPhysicsController::setOrientation(const MT_Matrix3x3& rot) { + MT_Quaternion orn = rot.getRotation(); SumoPhysicsController::setOrientation( orn[0],orn[1],orn[2],orn[3]); @@ -204,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 868465c8f10..abe48d99043 100644 --- a/source/gameengine/Ketsji/KX_SumoPhysicsController.h +++ b/source/gameengine/Ketsji/KX_SumoPhysicsController.h @@ -68,20 +68,23 @@ public: void ApplyTorque(const MT_Vector3& torque,bool local); void ApplyForce(const MT_Vector3& force,bool local); MT_Vector3 GetLinearVelocity(); + MT_Vector3 GetAngularVelocity() // to keep compiler happy + { return MT_Vector3(0.0,0.0,0.0); } MT_Vector3 GetVelocity(const MT_Point3& pos); void SetAngularVelocity(const MT_Vector3& ang_vel,bool local); void SetLinearVelocity(const MT_Vector3& lin_vel,bool local); void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ); - void SuspendDynamics(); + void SuspendDynamics(bool); void RestoreDynamics(); virtual void getOrientation(MT_Quaternion& orn); - virtual void setOrientation(const MT_Quaternion& orn); + virtual void setOrientation(const MT_Matrix3x3& orn); virtual void setPosition(const MT_Point3& pos); virtual void setScaling(const MT_Vector3& scaling); virtual MT_Scalar GetMass(); + virtual MT_Scalar GetRadius(); virtual MT_Vector3 getReactionForce(); virtual void setRigidBody(bool rigid); diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp index 2da899c62cb..48d4cf59a2b 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp +++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp @@ -51,6 +51,7 @@ KX_TouchEventManager::KX_TouchEventManager(class SCA_LogicManager* logicmgr, m_physEnv->addTouchCallback(PHY_OBJECT_RESPONSE, KX_TouchEventManager::newCollisionResponse, this); m_physEnv->addTouchCallback(PHY_SENSOR_RESPONSE, KX_TouchEventManager::newCollisionResponse, this); + m_physEnv->addTouchCallback(PHY_BROADPH_RESPONSE, KX_TouchEventManager::newBroadphaseResponse, this); } @@ -76,19 +77,47 @@ bool KX_TouchEventManager::newCollisionResponse(void *client_data, return false; } +bool KX_TouchEventManager::newBroadphaseResponse(void *client_data, + void *object1, + void *object2, + const PHY_CollData *coll_data) +{ + PHY_IPhysicsController* ctrl = static_cast<PHY_IPhysicsController*>(object1); + KX_ClientObjectInfo* info = (ctrl) ? static_cast<KX_ClientObjectInfo*>(ctrl->getNewClientInfo()) : NULL; + // This call back should only be called for controllers of Near and Radar sensor + if (info && + info->m_sensors.size() == 1 && + (info->m_type == KX_ClientObjectInfo::NEAR || + info->m_type == KX_ClientObjectInfo::RADAR)) + { + // only one sensor for this type of object + KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(*info->m_sensors.begin()); + return touchsensor->BroadPhaseFilterCollision(object1,object2); + } + return true; +} + void KX_TouchEventManager::RegisterSensor(SCA_ISensor* sensor) { KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(sensor); - m_sensors.push_back(touchsensor); + if (m_sensors.insert(touchsensor).second) + // the sensor was effectively inserted, register it + touchsensor->RegisterSumo(this); +} - touchsensor->RegisterSumo(this); +void KX_TouchEventManager::RemoveSensor(SCA_ISensor* sensor) +{ + KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(sensor); + if (m_sensors.erase(touchsensor)) + // the sensor was effectively removed, unregister it + touchsensor->UnregisterSumo(this); } void KX_TouchEventManager::EndFrame() { - vector<SCA_ISensor*>::iterator it; + set<SCA_ISensor*>::iterator it; for ( it = m_sensors.begin(); !(it==m_sensors.end());it++) { @@ -103,7 +132,7 @@ void KX_TouchEventManager::NextFrame() { if (m_sensors.size() > 0) { - vector<SCA_ISensor*>::iterator it; + set<SCA_ISensor*>::iterator it; for (it = m_sensors.begin();!(it==m_sensors.end());++it) static_cast<KX_TouchSensor*>(*it)->SynchronizeTransform(); @@ -116,14 +145,18 @@ void KX_TouchEventManager::NextFrame() // KX_GameObject* gameOb1 = ctrl1->getClientInfo(); KX_ClientObjectInfo *client_info = static_cast<KX_ClientObjectInfo *>(ctrl1->getNewClientInfo()); - list<SCA_ISensor*>::iterator sit; - for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit) - static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision((*cit).first, (*cit).second, NULL); - + if (client_info) { + for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit) { + static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision((*cit).first, (*cit).second, NULL); + } + } client_info = static_cast<KX_ClientObjectInfo *>((*cit).second->getNewClientInfo()); - for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit) - static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision((*cit).second, (*cit).first, NULL); + if (client_info) { + for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit) { + static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision((*cit).second, (*cit).first, NULL); + } + } } m_newCollisions.clear(); @@ -132,20 +165,3 @@ void KX_TouchEventManager::NextFrame() (*it)->Activate(m_logicmgr,NULL); } } - - - -void KX_TouchEventManager::RemoveSensor(class SCA_ISensor* sensor) -{ - std::vector<SCA_ISensor*>::iterator i = - std::find(m_sensors.begin(), m_sensors.end(), sensor); - if (!(i == m_sensors.end())) - { - std::swap(*i, m_sensors.back()); - m_sensors.pop_back(); - } - - // remove the sensor forever :) - SCA_EventManager::RemoveSensor(sensor); -} - diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.h b/source/gameengine/Ketsji/KX_TouchEventManager.h index d15128284da..cc77bccfc31 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.h +++ b/source/gameengine/Ketsji/KX_TouchEventManager.h @@ -53,7 +53,12 @@ class KX_TouchEventManager : public SCA_EventManager void *object1, void *object2, const PHY_CollData *coll_data); - + + static bool newBroadphaseResponse(void *client_data, + void *object1, + void *object2, + const PHY_CollData *coll_data); + virtual bool NewHandleCollision(void* obj1,void* obj2, const PHY_CollData * coll_data); @@ -66,8 +71,8 @@ public: PHY_IPhysicsEnvironment* physEnv); virtual void NextFrame(); virtual void EndFrame(); - virtual void RemoveSensor(class SCA_ISensor* sensor); virtual void RegisterSensor(SCA_ISensor* sensor); + virtual void RemoveSensor(SCA_ISensor* sensor); SCA_LogicManager* GetLogicManager() { return m_logicmgr;} PHY_IPhysicsEnvironment *GetPhysicsEnvironment() { return m_physEnv; } diff --git a/source/gameengine/Ketsji/KX_TouchSensor.cpp b/source/gameengine/Ketsji/KX_TouchSensor.cpp index 62e400a7049..1935a0bde39 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.cpp +++ b/source/gameengine/Ketsji/KX_TouchSensor.cpp @@ -48,30 +48,30 @@ void KX_TouchSensor::SynchronizeTransform() { - - if (m_physCtrl) - { - - KX_GameObject* parent = ((KX_GameObject*)GetParent()); - MT_Vector3 pos = parent->NodeGetWorldPosition(); - MT_Quaternion orn = parent->NodeGetWorldOrientation().getRotation(); - m_physCtrl->setPosition(pos.x(),pos.y(),pos.z()); - m_physCtrl->setOrientation(orn.x(),orn.y(),orn.z(),orn.w()); - m_physCtrl->calcXform(); - } - + // the touch sensor does not require any synchronization: it uses + // the same physical object which is already synchronized by Blender } void KX_TouchSensor::EndFrame() { m_colliders->ReleaseAndRemoveAll(); + m_hitObject = NULL; m_bTriggered = false; } +void KX_TouchSensor::UnregisterToManager() +{ + // before unregistering the sensor, make sure we release all references + EndFrame(); + m_eventmgr->RemoveSensor(this); +} + bool KX_TouchSensor::Evaluate(CValue* event) { bool result = false; + bool reset = m_reset && m_level; + m_reset = false; if (m_bTriggered != m_bLastTriggered) { m_bLastTriggered = m_bTriggered; @@ -79,7 +79,9 @@ bool KX_TouchSensor::Evaluate(CValue* event) m_hitObject = NULL; result = true; } - + if (reset) + // force an event + result = true; return result; } @@ -87,18 +89,14 @@ KX_TouchSensor::KX_TouchSensor(SCA_EventManager* eventmgr,KX_GameObject* gameobj :SCA_ISensor(gameobj,eventmgr,T), m_touchedpropname(touchedpropname), m_bFindMaterial(bFindMaterial), -m_eventmgr(eventmgr), +m_eventmgr(eventmgr) /*m_sumoObj(sumoObj),*/ -m_bCollision(false), -m_bTriggered(false), -m_bLastTriggered(false) { // KX_TouchEventManager* touchmgr = (KX_TouchEventManager*) eventmgr; // m_resptable = touchmgr->GetResponseTable(); // m_solidHandle = m_sumoObj->getObjectHandle(); - m_hitObject = NULL; m_colliders = new CListValue(); KX_ClientObjectInfo *client_info = gameobj->getClientInfo(); @@ -108,8 +106,17 @@ m_bLastTriggered(false) m_physCtrl = dynamic_cast<PHY_IPhysicsController*>(gameobj->GetPhysicsController()); MT_assert( !gameobj->GetPhysicsController() || m_physCtrl ); + Init(); } +void KX_TouchSensor::Init() +{ + m_bCollision = false; + m_bTriggered = false; + m_bLastTriggered = (m_invert)?true:false; + m_hitObject = NULL; + m_reset = true; +} KX_TouchSensor::~KX_TouchSensor() { @@ -121,10 +128,7 @@ CValue* KX_TouchSensor::GetReplica() { KX_TouchSensor* replica = new KX_TouchSensor(*this); replica->m_colliders = new CListValue(); - replica->m_bCollision = false; - replica->m_bTriggered= false; - replica->m_hitObject = NULL; - replica->m_bLastTriggered = false; + replica->Init(); // this will copy properties and so on... CValue::AddDataToReplica(replica); return replica; @@ -157,6 +161,14 @@ void KX_TouchSensor::RegisterSumo(KX_TouchEventManager *touchman) } } +void KX_TouchSensor::UnregisterSumo(KX_TouchEventManager* touchman) +{ + if (m_physCtrl) + { + touchman->GetPhysicsEnvironment()->removeCollisionCallback(m_physCtrl); + } +} + bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_CollData* colldata) { // KX_TouchEventManager* toucheventmgr = (KX_TouchEventManager*)m_eventmgr; @@ -172,7 +184,10 @@ bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_Coll client_info->m_gameobject : NULL); - if (gameobj && (gameobj != parent) && client_info->isActor()) + // add the same check as in SCA_ISensor::Activate(), + // we don't want to record collision when the sensor is not active. + if (m_links && !m_suspended && + gameobj && (gameobj != parent) && client_info->isActor()) { if (!m_colliders->SearchValue(gameobj)) m_colliders->Add(gameobj->AddRef()); @@ -236,13 +251,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 }; @@ -253,7 +268,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" @@ -271,15 +286,15 @@ PyObject* KX_TouchSensor::PySetProperty(PyObject* self, if (!prop->IsError()) { m_touchedpropname = nameArg; - prop->Release(); } else { ; /* not found ... */ } + prop->Release(); 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" @@ -290,7 +305,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, @@ -306,7 +321,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"; @@ -348,8 +363,8 @@ PyObject* KX_TouchSensor::PyGetHitObjectList(PyObject* self, CValue* val = m_colliders->GetValue(i)->FindIdentifier(m_touchedpropname); if (!val->IsError()) { newList->Add(m_colliders->GetValue(i)->AddRef()); - val->Release(); } + val->Release(); } i++; @@ -360,7 +375,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" ; @@ -372,7 +387,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_TouchSensor.h b/source/gameengine/Ketsji/KX_TouchSensor.h index dd869fa69c9..8fbb1c676ba 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.h +++ b/source/gameengine/Ketsji/KX_TouchSensor.h @@ -54,8 +54,6 @@ protected: class SCA_EventManager* m_eventmgr; class PHY_IPhysicsController* m_physCtrl; - class PHY_ResponseTable* m_responstTable; - class PHY_PhysicsController* m_responsObject; bool m_bCollision; bool m_bTriggered; @@ -74,16 +72,23 @@ public: virtual CValue* GetReplica(); virtual void SynchronizeTransform(); virtual bool Evaluate(CValue* event); + virtual void Init(); virtual void ReParent(SCA_IObject* parent); virtual void RegisterSumo(KX_TouchEventManager* touchman); + virtual void UnregisterSumo(KX_TouchEventManager* touchman); + virtual void UnregisterToManager(); // virtual DT_Bool HandleCollision(void* obj1,void* obj2, // const DT_CollData * coll_data); virtual bool NewHandleCollision(void*obj1,void*obj2,const PHY_CollData* colldata); - PHY_PhysicsController* GetPhysicsController() { return m_responsObject;} + // Allows to do pre-filtering and save computation time + // obj1 = sensor physical controller, obj2 = physical controller of second object + // return value = true if collision should be checked on pair of object + virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2) { return true; } + virtual bool IsPositiveTrigger() { diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp index dc637bf0837..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 @@ -69,12 +71,19 @@ KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj, m_upflag = upflag; m_parentobj = 0; - if (m_object){ - KX_GameObject* curobj = (KX_GameObject*) GetParent(); + if (m_object) + m_object->RegisterActuator(this); - m_parentobj = curobj->GetParent(); // check if the object is parented - if (m_parentobj) { // if so, store the initial local rotation - m_parentlocalmat = m_parentobj->GetSGNode()->GetLocalOrientation(); + if (gameobj->isA(&KX_GameObject::Type)) + { + // if the object is vertex parented, don't check parent orientation as the link is broken + if (!((KX_GameObject*)gameobj)->IsVertexParent()){ + m_parentobj = ((KX_GameObject*)gameobj)->GetParent(); // check if the object is parented + if (m_parentobj) { + // if so, store the initial local rotation + // this is needed to revert the effect of the parent inverse node (TBC) + m_parentlocalmat = m_parentobj->GetSGNode()->GetLocalOrientation(); + } } } @@ -139,19 +148,19 @@ void compatible_eulFast(float *eul, float *oldrot) { float dx, dy, dz; - /* verschillen van ong 360 graden corrigeren */ + /* angular difference of 360 degrees */ dx= eul[0] - oldrot[0]; dy= eul[1] - oldrot[1]; dz= eul[2] - oldrot[2]; - if( fabs(dx) > 5.1) { + if( fabs(dx) > MT_PI) { if(dx > 0.0) eul[0] -= MT_2_PI; else eul[0]+= MT_2_PI; } - if( fabs(dy) > 5.1) { + if( fabs(dy) > MT_PI) { if(dy > 0.0) eul[1] -= MT_2_PI; else eul[1]+= MT_2_PI; } - if( fabs(dz) > 5.1 ) { + if( fabs(dz) > MT_PI ) { if(dz > 0.0) eul[2] -= MT_2_PI; else eul[2]+= MT_2_PI; } } @@ -176,10 +185,53 @@ MT_Matrix3x3 matrix3x3_interpol(MT_Matrix3x3 oldmat, MT_Matrix3x3 mat, int m_tim KX_TrackToActuator::~KX_TrackToActuator() -{ - // there's nothing to be done here, really.... +{ + if (m_object) + m_object->UnregisterActuator(this); + if (m_parentobj) + m_parentobj->Release(); } /* end of destructor */ +void KX_TrackToActuator::ProcessReplica() +{ + // the replica is tracking the same object => register it + if (m_object) + m_object->RegisterActuator(this); + if (m_parentobj) + m_parentobj->AddRef(); + SCA_IActuator::ProcessReplica(); +} + + +bool KX_TrackToActuator::UnlinkObject(SCA_IObject* clientobj) +{ + if (clientobj == m_object) + { + // this object is being deleted, we cannot continue to track it. + m_object = NULL; + return true; + } + return false; +} + +void KX_TrackToActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + void **h_obj = (*obj_map)[m_object]; + if (h_obj) { + if (m_object) + m_object->UnregisterActuator(this); + m_object = (SCA_IObject*)(*h_obj); + m_object->RegisterActuator(this); + } + + void **h_parobj = (*obj_map)[m_parentobj]; + if (h_parobj) { + if (m_parentobj) + m_parentobj->Release(); + m_parentobj= (KX_GameObject*)(*h_parobj); + m_parentobj->AddRef(); + } +} bool KX_TrackToActuator::Update(double curtime, bool frame) @@ -196,7 +248,8 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) { KX_GameObject* curobj = (KX_GameObject*) GetParent(); MT_Vector3 dir = ((KX_GameObject*)m_object)->NodeGetWorldPosition() - curobj->NodeGetWorldPosition(); - dir.normalize(); + if (dir.length2()) + dir.normalize(); MT_Vector3 up(0,0,1); @@ -222,12 +275,12 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) #endif if (m_allow3D) { - up = (up - up.dot(dir) * dir).normalized(); + up = (up - up.dot(dir) * dir).safe_normalized(); } else { - dir = (dir - up.dot(dir)*up).normalized(); + dir = (dir - up.dot(dir)*up).safe_normalized(); } MT_Vector3 left; @@ -238,8 +291,8 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) case 0: // TRACK X { // (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up - left = dir.normalized(); - dir = (left.cross(up)).normalized(); + left = dir.safe_normalized(); + dir = (left.cross(up)).safe_normalized(); mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], @@ -251,7 +304,7 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) case 1: // TRACK Y { // (0.0 , 1.0 , 0.0 ) y direction is forward, z (0.0 , 0.0 , 1.0 ) up - left = (dir.cross(up)).normalized(); + left = (dir.cross(up)).safe_normalized(); mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], @@ -263,10 +316,10 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) case 2: // track Z { - left = up.normalized(); - up = dir.normalized(); + left = up.safe_normalized(); + up = dir.safe_normalized(); dir = left; - left = (dir.cross(up)).normalized(); + left = (dir.cross(up)).safe_normalized(); mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], @@ -278,8 +331,8 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) case 3: // TRACK -X { // (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up - left = -dir.normalized(); - dir = -(left.cross(up)).normalized(); + left = -dir.safe_normalized(); + dir = -(left.cross(up)).safe_normalized(); mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], @@ -291,7 +344,7 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) case 4: // TRACK -Y { // (0.0 , -1.0 , 0.0 ) -y direction is forward, z (0.0 , 0.0 , 1.0 ) up - left = (-dir.cross(up)).normalized(); + left = (-dir.cross(up)).safe_normalized(); mat.setValue ( left[0], -dir[0],up[0], left[1], -dir[1],up[1], @@ -301,10 +354,10 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) } case 5: // track -Z { - left = up.normalized(); - up = -dir.normalized(); + left = up.safe_normalized(); + up = -dir.safe_normalized(); dir = left; - left = (dir.cross(up)).normalized(); + left = (dir.cross(up)).safe_normalized(); mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], @@ -317,8 +370,8 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) default: { // (1.0 , 0.0 , 0.0 ) -x direction is forward, z (0.0 , 0.0 , 1.0 ) up - left = -dir.normalized(); - dir = -(left.cross(up)).normalized(); + left = -dir.safe_normalized(); + dir = -(left.cross(up)).safe_normalized(); mat.setValue ( left[0], dir[0],up[0], left[1], dir[1],up[1], @@ -403,12 +456,12 @@ PyParentObject KX_TrackToActuator::Parents[] = { PyMethodDef KX_TrackToActuator::Methods[] = { - {"setObject", (PyCFunction) KX_TrackToActuator::sPySetObject, METH_VARARGS, 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 }; @@ -422,49 +475,53 @@ 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: string\n" +"\t- object: KX_GameObject, string or None\n" "\tSet the object to track with the parent of this actuator.\n"; -PyObject* KX_TrackToActuator::PySetObject(PyObject* self, PyObject* args, PyObject* kwds) { - PyObject* gameobj; - if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj)) - { - m_object = (SCA_IObject*)gameobj; - - Py_Return; - } - PyErr_Clear(); +PyObject* KX_TrackToActuator::PySetObject(PyObject* self, PyObject* value) +{ + KX_GameObject *gameobj; - char* objectname; - if (PyArg_ParseTuple(args, "s", &objectname)) - { - m_object= static_cast<SCA_IObject*>(SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname))); - - Py_Return; - } + if (!ConvertPythonToGameObject(value, &gameobj, true)) + return NULL; // ConvertPythonToGameObject sets the error + + if (m_object != NULL) + m_object->UnregisterActuator(this); + + m_object = (SCA_IObject*)gameobj; + if (m_object) + m_object->RegisterActuator(this); - return NULL; + Py_RETURN_NONE; } /* 2. getObject */ -char KX_TrackToActuator::GetObject_doc[] = -"getObject()\n" -"\tReturns the object to track with the parent of this actuator.\n"; -PyObject* KX_TrackToActuator::PyGetObject(PyObject* self, PyObject* args, PyObject* kwds) +const char KX_TrackToActuator::GetObject_doc[] = +"getObject(name_only = 1)\n" +"name_only - optional arg, when true will return the KX_GameObject rather then its name\n" +"\tReturns the object to track with the parent of this actuator\n"; +PyObject* KX_TrackToActuator::PyGetObject(PyObject* self, PyObject* args) { + int ret_name_only = 1; + if (!PyArg_ParseTuple(args, "|i", &ret_name_only)) + return NULL; + if (!m_object) - Py_Return; - - return PyString_FromString(m_object->GetName()); + Py_RETURN_NONE; + + if (ret_name_only) + return PyString_FromString(m_object->GetName()); + else + return m_object->AddRef(); } /* 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"; @@ -485,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"; @@ -497,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) @@ -508,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_TrackToActuator.h b/source/gameengine/Ketsji/KX_TrackToActuator.h index 944eaadf025..445132a6094 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.h +++ b/source/gameengine/Ketsji/KX_TrackToActuator.h @@ -66,15 +66,18 @@ class KX_TrackToActuator : public SCA_IActuator return replica; }; + virtual void ProcessReplica(); + virtual bool UnlinkObject(SCA_IObject* clientobj); + virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map); virtual bool Update(double curtime, bool frame); /* Python part */ virtual PyObject* _getattr(const STR_String& attr); /* 1. setObject */ - KX_PYMETHOD_DOC(KX_TrackToActuator,SetObject); + KX_PYMETHOD_DOC_O(KX_TrackToActuator,SetObject); /* 2. getObject */ - KX_PYMETHOD_DOC(KX_TrackToActuator,GetObject); + KX_PYMETHOD_DOC_VARARGS(KX_TrackToActuator,GetObject); /* 3. setTime */ KX_PYMETHOD_DOC(KX_TrackToActuator,SetTime); /* 4. getTime */ diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp index fba2ecc223b..028f96f6c5b 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" @@ -47,30 +49,34 @@ PyObject* KX_VehicleWrapper::PyAddWheel(PyObject* self, if (PyArg_ParseTuple(args,"OOOOffi",&wheelGameObject,&pylistPos,&pylistDir,&pylistAxleDir,&suspensionRestLength,&wheelRadius,&hasSteering)) { KX_GameObject* gameOb = (KX_GameObject*) wheelGameObject; + + if (gameOb->GetSGNode()) + { + PHY_IMotionState* motionState = new KX_MotionState(gameOb->GetSGNode()); + + MT_Vector3 attachPos,attachDir,attachAxle; + PyVecTo(pylistPos,attachPos); + PyVecTo(pylistDir,attachDir); + PyVecTo(pylistAxleDir,attachAxle); + PHY__Vector3 aPos,aDir,aAxle; + aPos[0] = attachPos[0]; + aPos[1] = attachPos[1]; + aPos[2] = attachPos[2]; + aDir[0] = attachDir[0]; + aDir[1] = attachDir[1]; + aDir[2] = attachDir[2]; + aAxle[0] = -attachAxle[0];//someone reverse some conventions inside Bullet (axle winding) + aAxle[1] = -attachAxle[1]; + aAxle[2] = -attachAxle[2]; + + printf("attempt for addWheel: suspensionRestLength%f wheelRadius %f, hasSteering:%d\n",suspensionRestLength,wheelRadius,hasSteering); + m_vehicle->AddWheel(motionState,aPos,aDir,aAxle,suspensionRestLength,wheelRadius,hasSteering); + } - PHY_IMotionState* motionState = new KX_MotionState(gameOb->GetSGNode()); - - MT_Vector3 attachPos,attachDir,attachAxle; - PyVecTo(pylistPos,attachPos); - PyVecTo(pylistDir,attachDir); - PyVecTo(pylistAxleDir,attachAxle); - PHY__Vector3 aPos,aDir,aAxle; - aPos[0] = attachPos[0]; - aPos[1] = attachPos[1]; - aPos[2] = attachPos[2]; - aDir[0] = attachDir[0]; - aDir[1] = attachDir[1]; - aDir[2] = attachDir[2]; - aAxle[0] = -attachAxle[0];//someone reverse some conventions inside Bullet (axle winding) - aAxle[1] = -attachAxle[1]; - aAxle[2] = -attachAxle[2]; - - printf("attempt for addWheel: suspensionRestLength%f wheelRadius %f, hasSteering:%d\n",suspensionRestLength,wheelRadius,hasSteering); - m_vehicle->AddWheel(motionState,aPos,aDir,aAxle,suspensionRestLength,wheelRadius,hasSteering); - + } else { + return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } @@ -90,8 +96,7 @@ PyObject* KX_VehicleWrapper::PyGetWheelPosition(PyObject* self, MT_Vector3 pos(position[0],position[1],position[2]); return PyObjectFrom(pos); } - Py_INCREF(Py_None); - return Py_None; + return NULL; } PyObject* KX_VehicleWrapper::PyGetWheelRotation(PyObject* self, @@ -103,8 +108,7 @@ PyObject* KX_VehicleWrapper::PyGetWheelRotation(PyObject* self, { return PyFloat_FromDouble(m_vehicle->GetWheelRotation(wheelIndex)); } - Py_INCREF(Py_None); - return Py_None; + return NULL; } PyObject* KX_VehicleWrapper::PyGetWheelOrientationQuaternion(PyObject* self, @@ -120,8 +124,7 @@ PyObject* KX_VehicleWrapper::PyGetWheelOrientationQuaternion(PyObject* self, MT_Matrix3x3 ornmat(quatorn); return PyObjectFrom(ornmat); } - Py_INCREF(Py_None); - return Py_None; + return NULL; } @@ -155,8 +158,10 @@ PyObject* KX_VehicleWrapper::PyApplyEngineForce(PyObject* self, force *= -1.f;//someone reverse some conventions inside Bullet (axle winding) m_vehicle->ApplyEngineForce(force,wheelIndex); } - Py_INCREF(Py_None); - return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } PyObject* KX_VehicleWrapper::PySetTyreFriction(PyObject* self, @@ -170,8 +175,10 @@ PyObject* KX_VehicleWrapper::PySetTyreFriction(PyObject* self, { m_vehicle->SetWheelFriction(wheelFriction,wheelIndex); } - Py_INCREF(Py_None); - return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } PyObject* KX_VehicleWrapper::PySetSuspensionStiffness(PyObject* self, @@ -185,8 +192,10 @@ PyObject* KX_VehicleWrapper::PySetSuspensionStiffness(PyObject* self, { m_vehicle->SetSuspensionStiffness(suspensionStiffness,wheelIndex); } - Py_INCREF(Py_None); - return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } PyObject* KX_VehicleWrapper::PySetSuspensionDamping(PyObject* self, @@ -199,9 +208,10 @@ PyObject* KX_VehicleWrapper::PySetSuspensionDamping(PyObject* self, if (PyArg_ParseTuple(args,"fi",&suspensionDamping,&wheelIndex)) { m_vehicle->SetSuspensionDamping(suspensionDamping,wheelIndex); + } else { + return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyObject* KX_VehicleWrapper::PySetSuspensionCompression(PyObject* self, @@ -214,9 +224,10 @@ PyObject* KX_VehicleWrapper::PySetSuspensionCompression(PyObject* self, if (PyArg_ParseTuple(args,"fi",&suspensionCompression,&wheelIndex)) { m_vehicle->SetSuspensionCompression(suspensionCompression,wheelIndex); + } else { + return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyObject* KX_VehicleWrapper::PySetRollInfluence(PyObject* self, @@ -230,8 +241,10 @@ PyObject* KX_VehicleWrapper::PySetRollInfluence(PyObject* self, { m_vehicle->SetRollInfluence(rollInfluence,wheelIndex); } - Py_INCREF(Py_None); - return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } @@ -246,8 +259,10 @@ PyObject* KX_VehicleWrapper::PyApplyBraking(PyObject* self, { m_vehicle->ApplyBraking(braking,wheelIndex); } - Py_INCREF(Py_None); - return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } @@ -264,8 +279,10 @@ PyObject* KX_VehicleWrapper::PySetSteeringValue(PyObject* self, { m_vehicle->SetSteeringValue(steeringValue,wheelIndex); } - Py_INCREF(Py_None); - return Py_None; + else { + return NULL; + } + Py_RETURN_NONE; } 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 fe226f22635..bdc0b335b02 100644 --- a/source/gameengine/Ketsji/Makefile +++ b/source/gameengine/Ketsji/Makefile @@ -35,9 +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 @@ -60,6 +64,7 @@ CPPFLAGS += -I../../blender/blenlib CPPFLAGS += -I../../blender/editors/include CPPFLAGS += -I../../blender/makesdna CPPFLAGS += -I../../blender/imbuf +CPPFLAGS += -I../../blender/gpu CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include ########################### diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript index f9f7920d244..7d2cfb403c0 100644 --- a/source/gameengine/Ketsji/SConscript +++ b/source/gameengine/Ketsji/SConscript @@ -5,7 +5,22 @@ Import ('env') sources = env.Glob('*.cpp') -incs = '. #source/kernel/gen_system #intern/string #intern/guardedalloc' +#XXX +# Mathutils C files. +#sources.extend([\ +# '#source/blender/python/api2_2x/Mathutils.c',\ +# '#source/blender/python/api2_2x/constant.c',\ +# '#source/blender/python/api2_2x/euler.c',\ +# '#source/blender/python/api2_2x/gen_utils.c',\ +# '#source/blender/python/api2_2x/matrix.c',\ +# '#source/blender/python/api2_2x/point.c',\ +# '#source/blender/python/api2_2x/quat.c',\ +# '#source/blender/python/api2_2x/vector.c',\ +#]) + +incs = '. #source/blender/python/api2_2x' # Only for Mathutils! - no other deps + +incs += ' #source/kernel/gen_system #intern/string #intern/guardedalloc' incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer #intern/bmfont' incs += ' #intern/SoundSystem #intern/SoundSystem/include #intern/SoundSystem/openal' incs += ' #intern/SoundSystem/dummy #intern/SoundSystem/intern #source/gameengine/Converter' @@ -18,7 +33,7 @@ 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' +incs += ' #source/blender/misc #source/blender/blenloader #extern/glew/include #source/blender/gpu' cflags = [] if env['OURPLATFORM'] == 'win32-vc': @@ -27,8 +42,10 @@ if env['OURPLATFORM'] == 'win32-vc': incs += ' ' + env['BF_SOLID_INC'] incs += ' ' + env['BF_PYTHON_INC'] -incs += ' ' + env['BF_SDL_INC'] incs += ' ' + env['BF_BULLET_INC'] incs += ' ' + env['BF_OPENGL_INC'] +if env['WITH_BF_SDL']: + incs += ' ' + env['BF_SDL_INC'] + env.BlenderLib ( 'bf_ketsji', sources, Split(incs), [], libtype=['game','player'], priority=[25, 60], compileflags = cflags ) |