diff options
Diffstat (limited to 'source/gameengine/Ketsji')
81 files changed, 3018 insertions, 1329 deletions
diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp index a50c07a486a..12a1caee221 100644 --- a/source/gameengine/Ketsji/BL_Action.cpp +++ b/source/gameengine/Ketsji/BL_Action.cpp @@ -49,6 +49,7 @@ extern "C" { // Needed for material IPOs #include "BKE_material.h" #include "DNA_material_types.h" +#include "DNA_scene_types.h" } #include "MEM_guardedalloc.h" @@ -162,6 +163,14 @@ bool BL_Action::Play(const char* name, m_obj->GetSGNode()->AddSGController(sg_contr); sg_contr->SetObject(m_obj->GetSGNode()); + // World + sg_contr = BL_CreateWorldIPO(m_action, kxscene->GetBlenderScene()->world, kxscene->GetSceneConverter()); + if (sg_contr) { + m_sg_contr_list.push_back(sg_contr); + m_obj->GetSGNode()->AddSGController(sg_contr); + sg_contr->SetObject(m_obj->GetSGNode()); + } + // Try obcolor sg_contr = BL_CreateObColorIPO(m_action, m_obj, kxscene->GetSceneConverter()); if (sg_contr) { @@ -292,6 +301,18 @@ float BL_Action::GetFrame() return m_localtime; } +const char *BL_Action::GetName() +{ + if (m_action != NULL) { + return m_action->id.name + 2; + } + else { + return ""; + } + + +} + void BL_Action::SetFrame(float frame) { // Clamp the frame to the start and end frame diff --git a/source/gameengine/Ketsji/BL_Action.h b/source/gameengine/Ketsji/BL_Action.h index dd1cd1f69ff..379dd52df5b 100644 --- a/source/gameengine/Ketsji/BL_Action.h +++ b/source/gameengine/Ketsji/BL_Action.h @@ -112,6 +112,8 @@ public: // Accessors float GetFrame(); + const char *GetName(); + struct bAction *GetAction(); // Mutators diff --git a/source/gameengine/Ketsji/BL_ActionManager.cpp b/source/gameengine/Ketsji/BL_ActionManager.cpp index 07adce73b4a..9e4690548d3 100644 --- a/source/gameengine/Ketsji/BL_ActionManager.cpp +++ b/source/gameengine/Ketsji/BL_ActionManager.cpp @@ -26,9 +26,13 @@ #include "BL_Action.h" #include "BL_ActionManager.h" +#include "DNA_ID.h" + +#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->flag & LIB_DOIT)) BL_ActionManager::BL_ActionManager(class KX_GameObject *obj): - m_obj(obj) + m_obj(obj), + m_prevUpdate(-1.0f) { } @@ -64,6 +68,12 @@ float BL_ActionManager::GetActionFrame(short layer) return action ? action->GetFrame() : 0.f; } +const char *BL_ActionManager::GetActionName(short layer) +{ + BL_Action *action = GetAction(layer); + return action ? action->GetName() : ""; +} + void BL_ActionManager::SetActionFrame(short layer, float frame) { BL_Action *action = GetAction(layer); @@ -122,6 +132,18 @@ void BL_ActionManager::StopAction(short layer) if (action) action->Stop(); } +void BL_ActionManager::RemoveTaggedActions() +{ + for (BL_ActionMap::iterator it = m_layers.begin(); it != m_layers.end();) { + if (IS_TAGGED(it->second->GetAction())) { + delete it->second; + m_layers.erase(it++); + } + else + ++it; + } +} + bool BL_ActionManager::IsActionDone(short layer) { BL_Action *action = GetAction(layer); @@ -131,6 +153,10 @@ bool BL_ActionManager::IsActionDone(short layer) void BL_ActionManager::Update(float curtime) { + if (m_prevUpdate == curtime) + return; + m_prevUpdate = curtime; + BL_ActionMap::iterator it; for (it = m_layers.begin(); it != m_layers.end(); ) { diff --git a/source/gameengine/Ketsji/BL_ActionManager.h b/source/gameengine/Ketsji/BL_ActionManager.h index 5b340257881..97d6d88cf22 100644 --- a/source/gameengine/Ketsji/BL_ActionManager.h +++ b/source/gameengine/Ketsji/BL_ActionManager.h @@ -20,7 +20,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file BL_ActionManager.cpp +/** \file BL_ActionManager.h * \ingroup ketsji */ @@ -51,6 +51,9 @@ private: class KX_GameObject* m_obj; BL_ActionMap m_layers; + // The last update time to avoid double animation update. + float m_prevUpdate; + /** * Check if an action exists */ @@ -82,6 +85,11 @@ public: float GetActionFrame(short layer); /** + * Gets the name of the current action + */ + const char *GetActionName(short layer); + + /** * Sets the current frame of an action */ void SetActionFrame(short layer, float frame); @@ -107,6 +115,11 @@ public: void StopAction(short layer); /** + * Remove playing tagged actions. + */ + void RemoveTaggedActions(); + + /** * Check if an action has finished playing */ bool IsActionDone(short layer); diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp index bcdef85bc8a..b5151615f3b 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.cpp +++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp @@ -62,7 +62,7 @@ BL_BlenderShader::~BL_BlenderShader() void BL_BlenderShader::ReloadMaterial() { - mGPUMat = (mMat) ? GPU_material_from_blender(mBlenderScene, mMat) : NULL; + mGPUMat = (mMat) ? GPU_material_from_blender(mBlenderScene, mMat, false) : NULL; } void BL_BlenderShader::SetProg(bool enable, double time, RAS_IRasterizer* rasty) @@ -77,7 +77,7 @@ void BL_BlenderShader::SetProg(bool enable, double time, RAS_IRasterizer* rasty) view.getValue((float*)viewmat); viewinv.getValue((float*)viewinvmat); - GPU_material_bind(mGPUMat, mLightLayer, mBlenderScene->lay, time, 1, viewmat, viewinvmat, false); + GPU_material_bind(mGPUMat, mLightLayer, mBlenderScene->lay, time, 1, viewmat, viewinvmat, NULL, false); } else GPU_material_unbind(mGPUMat); @@ -168,7 +168,7 @@ void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) obcol[0] = obcol[1] = obcol[2] = obcol[3] = 1.0f; float auto_bump_scale = ms.m_pDerivedMesh!=0 ? ms.m_pDerivedMesh->auto_bump_scale : 1.0f; - GPU_material_bind_uniforms(gpumat, obmat, obcol, auto_bump_scale); + GPU_material_bind_uniforms(gpumat, obmat, obcol, auto_bump_scale, NULL); mAlphaBlend = GPU_material_alpha_blend(gpumat, obcol); } diff --git a/source/gameengine/Ketsji/BL_Material.cpp b/source/gameengine/Ketsji/BL_Material.cpp index 006c1f7202c..4f707e6267f 100644 --- a/source/gameengine/Ketsji/BL_Material.cpp +++ b/source/gameengine/Ketsji/BL_Material.cpp @@ -47,10 +47,10 @@ BL_Material::BL_Material() void BL_Material::Initialize() { - rgb[0] = 0; - rgb[1] = 0; - rgb[2] = 0; - rgb[3] = 0; + rgb[0] = 0xFFFFFFFFL; + rgb[1] = 0xFFFFFFFFL; + rgb[2] = 0xFFFFFFFFL; + rgb[3] = 0xFFFFFFFFL; IdMode = 0; ras_mode = 0; glslmat = 0; @@ -69,7 +69,7 @@ void BL_Material::Initialize() alpha = 1.f; emit = 0.f; material = 0; - memset(&tface, 0, sizeof(tface)); + memset(&mtexpoly, 0, sizeof(mtexpoly)); materialindex = 0; amb=0.5f; num_enabled = 0; diff --git a/source/gameengine/Ketsji/BL_Material.h b/source/gameengine/Ketsji/BL_Material.h index 83f9b601e0d..9207a41f56d 100644 --- a/source/gameengine/Ketsji/BL_Material.h +++ b/source/gameengine/Ketsji/BL_Material.h @@ -84,7 +84,7 @@ public: Material* material; - MTFace tface; /* copy of the derived meshes tface */ + MTexPoly mtexpoly; /* copy of the derived meshes tface */ Image* img[MAXTEX]; EnvMap* cubemap[MAXTEX]; diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp index 872ac19351d..a59c3686a18 100644 --- a/source/gameengine/Ketsji/BL_Shader.cpp +++ b/source/gameengine/Ketsji/BL_Shader.cpp @@ -22,7 +22,7 @@ * \ingroup ketsji */ -#include "GL/glew.h" +#include "glew-mx.h" #include <iostream> #include "BL_Shader.h" diff --git a/source/gameengine/Ketsji/BL_Shader.h b/source/gameengine/Ketsji/BL_Shader.h index 4c671d0c9a3..e3dc4b19773 100644 --- a/source/gameengine/Ketsji/BL_Shader.h +++ b/source/gameengine/Ketsji/BL_Shader.h @@ -6,7 +6,7 @@ #ifndef __BL_SHADER_H__ #define __BL_SHADER_H__ -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" #include "BL_Material.h" #include "BL_Texture.h" // -- diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp index 1578c745b9f..8f717c05c0f 100644 --- a/source/gameengine/Ketsji/BL_Texture.cpp +++ b/source/gameengine/Ketsji/BL_Texture.cpp @@ -22,7 +22,7 @@ * \ingroup ketsji */ -#include "GL/glew.h" +#include "glew-mx.h" #include <iostream> #include <map> @@ -170,7 +170,7 @@ bool BL_Texture::InitFromImage(int unit, Image *img, bool mipmap) glGenTextures(1, (GLuint*)&mTexture); #ifdef WITH_DDS - if (ibuf->ftype & DDS) + if (ibuf->ftype == IMB_FTYPE_DDS) InitGLCompressedTex(ibuf, mipmap); else InitGLTex(ibuf->rect, ibuf->x, ibuf->y, mipmap); @@ -203,9 +203,21 @@ void BL_Texture::InitGLTex(unsigned int *pix,int x,int y,bool mipmap) glBindTexture(GL_TEXTURE_2D, mTexture ); if ( mipmap ) { + int i; + ImBuf *ibuf; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, x, y, GL_RGBA, GL_UNSIGNED_BYTE, pix ); + + ibuf = IMB_allocFromBuffer(pix, NULL, x, y); + + IMB_makemipmap(ibuf, true); + + for (i = 0; i < ibuf->miptot; i++) { + ImBuf *mip = IMB_getmipmap(ibuf, i); + + glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect); + } + IMB_freeImBuf(ibuf); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -239,26 +251,34 @@ void BL_Texture::InitNonPow2Tex(unsigned int *pix,int x,int y,bool mipmap) int nx= power_of_2_min_i(x); int ny= power_of_2_min_i(y); - unsigned int *newPixels = (unsigned int *)malloc(nx*ny*sizeof(unsigned int)); - - gluScaleImage(GL_RGBA, x, y, GL_UNSIGNED_BYTE, pix, nx,ny, GL_UNSIGNED_BYTE, newPixels); + ImBuf *ibuf = IMB_allocFromBuffer(pix, NULL, x, y); + IMB_scaleImBuf(ibuf, nx, ny); + glBindTexture(GL_TEXTURE_2D, mTexture ); if ( mipmap ) { + int i; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, nx, ny, GL_RGBA, GL_UNSIGNED_BYTE, newPixels ); + + IMB_makemipmap(ibuf, true); + + for (i = 0; i < ibuf->miptot; i++) { + ImBuf *mip = IMB_getmipmap(ibuf, i); + + glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect); + } } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nx, ny, 0, GL_RGBA, GL_UNSIGNED_BYTE, newPixels ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nx, ny, 0, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect ); } if (GLEW_EXT_texture_filter_anisotropic) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - free(newPixels); + IMB_freeImBuf(ibuf); } @@ -400,13 +420,16 @@ unsigned int BL_Texture::GetTextureType() const int BL_Texture::GetMaxUnits() { if (g_max_units < 0) { - GLint unit; - if (GLEW_ARB_multitexture) { + GLint unit = 0; + + if (GPU_glsl_support()) { + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &unit); + } + else if (GLEW_ARB_multitexture) { glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &unit); - g_max_units = (MAXTEX>=unit)?unit:MAXTEX; - } else { - g_max_units = 0; } + + g_max_units = (MAXTEX >= unit) ? unit : MAXTEX; } return g_max_units; diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index 03d1524b310..2607e2bb4b7 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -49,6 +49,7 @@ set(INC ../../blender/python/generic ../../blender/python/mathutils ../../../intern/container + ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/string ) @@ -229,7 +230,7 @@ set(SRC ) -add_definitions(-DGLEW_STATIC) +add_definitions(${GL_DEFINITIONS}) if(WITH_IMAGE_DDS) add_definitions(-DWITH_DDS) @@ -247,11 +248,12 @@ if(WITH_CODEC_FFMPEG) endif() if(WITH_AUDASPACE) - list(APPEND INC - ../../../intern/audaspace/intern - ../../../intern/audaspace/FX + add_definitions(${AUDASPACE_DEFINITIONS}) + + list(APPEND INC_SYS + ${AUDASPACE_C_INCLUDE_DIRS} + ${AUDASPACE_PY_INCLUDE_DIRS} ) - add_definitions(-DWITH_AUDASPACE) endif() if(WITH_BULLET) diff --git a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt index 0c661cf2c87..cfc6ded4e65 100644 --- a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt +++ b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt @@ -30,6 +30,7 @@ set(INC ../../GameLogic ../../Network ../../SceneGraph + ../../../blender/blenlib ../../../../intern/container ../../../../intern/string ) diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp index 6260596159d..1fadd9382e0 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp @@ -39,9 +39,9 @@ #include "NG_NetworkScene.h" #include "NG_NetworkObject.h" #include "SCA_IObject.h" -#include "InputParser.h" -#include "ListValue.h" -#include "StringValue.h" +#include "EXP_InputParser.h" +#include "EXP_ListValue.h" +#include "EXP_StringValue.h" #ifdef NAN_NET_DEBUG #include <iostream> diff --git a/source/gameengine/Ketsji/KXNetwork/SConscript b/source/gameengine/Ketsji/KXNetwork/SConscript index 355dcc4f78f..ab03e03e74d 100644 --- a/source/gameengine/Ketsji/KXNetwork/SConscript +++ b/source/gameengine/Ketsji/KXNetwork/SConscript @@ -39,6 +39,7 @@ incs = [ '#source/gameengine/Ketsji', '#source/gameengine/Network', '#source/gameengine/SceneGraph', + '../../../blender/blenlib', ] incs = ' '.join(incs) diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index 9ebdfea6156..d85d33d9834 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -22,7 +22,7 @@ * \ingroup ketsji */ -#include "GL/glew.h" +#include "glew-mx.h" #include "KX_BlenderMaterial.h" #include "BL_Material.h" @@ -30,6 +30,7 @@ #include "KX_Light.h" #include "KX_GameObject.h" #include "KX_MeshProxy.h" +#include "KX_PyMath.h" #include "MT_Vector3.h" #include "MT_Vector4.h" @@ -52,6 +53,7 @@ #include "BKE_mesh.h" // ------------------------------------ #include "BLI_utildefines.h" +#include "BLI_math.h" #define spit(x) std::cout << x << std::endl; @@ -94,6 +96,21 @@ void KX_BlenderMaterial::Initialize( ((data->ras_mode &TEX)), game ); + Material *ma = data->material; + + // Save material data to restore on exit + mSavedData.r = ma->r; + mSavedData.g = ma->g; + mSavedData.b = ma->b; + mSavedData.a = ma->alpha; + mSavedData.specr = ma->specr; + mSavedData.specg = ma->specg; + mSavedData.specb = ma->specb; + mSavedData.spec = ma->spec; + mSavedData.ref = ma->ref; + mSavedData.hardness = ma->har; + mSavedData.emit = ma->emit; + mMaterial = data; mShader = 0; mBlenderShader = 0; @@ -124,16 +141,30 @@ void KX_BlenderMaterial::Initialize( KX_BlenderMaterial::~KX_BlenderMaterial() { + Material *ma = mMaterial->material; + // Restore Blender material data + ma->r = mSavedData.r; + ma->g = mSavedData.g; + ma->b = mSavedData.b; + ma->alpha = mSavedData.a; + ma->specr = mSavedData.specr; + ma->specg = mSavedData.specg; + ma->specb = mSavedData.specb; + ma->spec = mSavedData.spec; + ma->ref = mSavedData.ref; + ma->har = mSavedData.hardness; + ma->emit = mSavedData.emit; + // cleanup work if (mConstructed) // clean only if material was actually used OnExit(); } -MTFace* KX_BlenderMaterial::GetMTFace() const +MTexPoly *KX_BlenderMaterial::GetMTexPoly() const { // fonts on polys - return &mMaterial->tface; + return &mMaterial->mtexpoly; } unsigned int* KX_BlenderMaterial::GetMCol() const @@ -160,7 +191,7 @@ Material *KX_BlenderMaterial::GetBlenderMaterial() const Image *KX_BlenderMaterial::GetBlenderImage() const { - return mMaterial->tface.tpage; + return mMaterial->mtexpoly.tpage; } Scene* KX_BlenderMaterial::GetBlenderScene() const @@ -793,17 +824,19 @@ void KX_BlenderMaterial::UpdateIPO( ) { // only works one deep now - mMaterial->speccolor[0] = (float)(specrgb)[0]; - mMaterial->speccolor[1] = (float)(specrgb)[1]; - mMaterial->speccolor[2] = (float)(specrgb)[2]; - mMaterial->matcolor[0] = (float)(rgba[0]); - mMaterial->matcolor[1] = (float)(rgba[1]); - mMaterial->matcolor[2] = (float)(rgba[2]); - mMaterial->alpha = (float)(alpha); - mMaterial->hard = (float)(hard); - mMaterial->emit = (float)(emit); - mMaterial->spec_f = (float)(spec); - mMaterial->ref = (float)(ref); + + // GLSL Multitexture Input + mMaterial->material->specr = mMaterial->speccolor[0] = (float)(specrgb)[0]; + mMaterial->material->specg = mMaterial->speccolor[1] = (float)(specrgb)[1]; + mMaterial->material->specb = mMaterial->speccolor[2] = (float)(specrgb)[2]; + mMaterial->material->r = mMaterial->matcolor[0] = (float)(rgba[0]); + mMaterial->material->g = mMaterial->matcolor[1] = (float)(rgba[1]); + mMaterial->material->b = mMaterial->matcolor[2] = (float)(rgba[2]); + mMaterial->material->alpha = mMaterial->alpha = (float)(rgba[3]); + mMaterial->material->har = mMaterial->hard = (float)(hard); + mMaterial->material->emit = mMaterial->emit = (float)(emit); + mMaterial->material->spec = mMaterial->spec_f = (float)(spec); + mMaterial->material->ref = mMaterial->ref = (float)(ref); } void KX_BlenderMaterial::Replace_IScene(SCA_IScene *val) @@ -813,6 +846,11 @@ void KX_BlenderMaterial::Replace_IScene(SCA_IScene *val) OnConstruction(); } +BL_Material *KX_BlenderMaterial::GetBLMaterial() +{ + return mMaterial; +} + void KX_BlenderMaterial::SetBlenderGLSLShader() { if (!mBlenderShader) @@ -824,6 +862,111 @@ void KX_BlenderMaterial::SetBlenderGLSLShader() } } +#ifdef USE_MATHUTILS + +#define MATHUTILS_COL_CB_MATERIAL_SPECULAR_COLOR 1 +#define MATHUTILS_COL_CB_MATERIAL_DIFFUSE_COLOR 2 + +static unsigned char mathutils_kxblendermaterial_color_cb_index = -1; /* index for our callbacks */ + +static int mathutils_kxblendermaterial_generic_check(BaseMathObject *bmo) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>BGE_PROXY_REF(bmo->cb_user); + if (!self) + return -1; + + return 0; +} + +static int mathutils_kxblendermaterial_color_get(BaseMathObject *bmo, int subtype) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial*>BGE_PROXY_REF(bmo->cb_user); + if (!self) + return -1; + + switch (subtype) { + case MATHUTILS_COL_CB_MATERIAL_DIFFUSE_COLOR: + { + copy_v3_v3(bmo->data, self->GetBLMaterial()->matcolor); + break; + } + case MATHUTILS_COL_CB_MATERIAL_SPECULAR_COLOR: + { + copy_v3_v3(bmo->data, self->GetBLMaterial()->speccolor); + break; + } + } + + return 0; +} + +static int mathutils_kxblendermaterial_color_set(BaseMathObject *bmo, int subtype) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>BGE_PROXY_REF(bmo->cb_user); + if (!self) + return -1; + + switch (subtype) { + case MATHUTILS_COL_CB_MATERIAL_DIFFUSE_COLOR: + { + BL_Material *mat = self->GetBLMaterial(); + copy_v3_v3(mat->matcolor, bmo->data); + mat->material->r = bmo->data[0]; + mat->material->g = bmo->data[1]; + mat->material->b = bmo->data[2]; + break; + } + case MATHUTILS_COL_CB_MATERIAL_SPECULAR_COLOR: + { + BL_Material *mat = self->GetBLMaterial(); + copy_v3_v3(mat->speccolor, bmo->data); + mat->material->specr = bmo->data[0]; + mat->material->specg = bmo->data[1]; + mat->material->specb = bmo->data[2]; + break; + } + } + + return 0; +} + +static int mathutils_kxblendermaterial_color_get_index(BaseMathObject *bmo, int subtype, int index) +{ + /* lazy, avoid repeteing the case statement */ + if (mathutils_kxblendermaterial_color_get(bmo, subtype) == -1) + return -1; + return 0; +} + +static int mathutils_kxblendermaterial_color_set_index(BaseMathObject *bmo, int subtype, int index) +{ + float f = bmo->data[index]; + + /* lazy, avoid repeateing the case statement */ + if (mathutils_kxblendermaterial_color_get(bmo, subtype) == -1) + return -1; + + bmo->data[index] = f; + return mathutils_kxblendermaterial_color_set(bmo, subtype); +} + +static Mathutils_Callback mathutils_kxblendermaterial_color_cb = { + mathutils_kxblendermaterial_generic_check, + mathutils_kxblendermaterial_color_get, + mathutils_kxblendermaterial_color_set, + mathutils_kxblendermaterial_color_get_index, + mathutils_kxblendermaterial_color_set_index +}; + + +void KX_BlenderMaterial_Mathutils_Callback_Init() +{ + // register mathutils callbacks, ok to run more than once. + mathutils_kxblendermaterial_color_cb_index = Mathutils_RegisterCallback(&mathutils_kxblendermaterial_color_cb); +} + +#endif // USE_MATHUTILS + #ifdef WITH_PYTHON PyMethodDef KX_BlenderMaterial::Methods[] = @@ -838,6 +981,14 @@ PyAttributeDef KX_BlenderMaterial::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("shader", KX_BlenderMaterial, pyattr_get_shader), KX_PYATTRIBUTE_RO_FUNCTION("material_index", KX_BlenderMaterial, pyattr_get_materialIndex), KX_PYATTRIBUTE_RW_FUNCTION("blending", KX_BlenderMaterial, pyattr_get_blending, pyattr_set_blending), + KX_PYATTRIBUTE_RW_FUNCTION("alpha", KX_BlenderMaterial, pyattr_get_alpha, pyattr_set_alpha), + KX_PYATTRIBUTE_RW_FUNCTION("hardness", KX_BlenderMaterial, pyattr_get_hardness, pyattr_set_hardness), + KX_PYATTRIBUTE_RW_FUNCTION("specularIntensity", KX_BlenderMaterial, pyattr_get_specular_intensity, pyattr_set_specular_intensity), + KX_PYATTRIBUTE_RW_FUNCTION("specularColor", KX_BlenderMaterial, pyattr_get_specular_color, pyattr_set_specular_color), + KX_PYATTRIBUTE_RW_FUNCTION("diffuseIntensity", KX_BlenderMaterial, pyattr_get_diffuse_intensity, pyattr_set_diffuse_intensity), + KX_PYATTRIBUTE_RW_FUNCTION("diffuseColor", KX_BlenderMaterial, pyattr_get_diffuse_color, pyattr_set_diffuse_color), + KX_PYATTRIBUTE_RW_FUNCTION("emit", KX_BlenderMaterial, pyattr_get_emit, pyattr_set_emit), + { NULL } //Sentinel }; @@ -882,6 +1033,170 @@ PyObject *KX_BlenderMaterial::pyattr_get_blending(void *self_v, const KX_PYATTRI return Py_BuildValue("(ll)", (long int)bfunc[0], (long int)bfunc[1]); } +PyObject *KX_BlenderMaterial::pyattr_get_alpha(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + return PyFloat_FromDouble(self->GetBLMaterial()->alpha); +} + +int KX_BlenderMaterial::pyattr_set_alpha(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + float val = PyFloat_AsDouble(value); + + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + + CLAMP(val, 0.0f, 1.0f); + + BL_Material *mat = self->GetBLMaterial(); + mat->alpha = mat->material->alpha = val; + return PY_SET_ATTR_SUCCESS; +} +PyObject *KX_BlenderMaterial::pyattr_get_hardness(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + return PyLong_FromLong(self->GetBLMaterial()->hard); +} + +int KX_BlenderMaterial::pyattr_set_hardness(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + int val = PyLong_AsLong(value); + + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "material.%s = int: KX_BlenderMaterial, expected a int", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + + CLAMP(val, 1, 511); + + BL_Material *mat = self->GetBLMaterial(); + mat->hard = mat->material->har = val; + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_BlenderMaterial::pyattr_get_specular_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + return PyFloat_FromDouble(self->GetBLMaterial()->spec_f); +} + +int KX_BlenderMaterial::pyattr_set_specular_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + float val = PyFloat_AsDouble(value); + + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + + CLAMP(val, 0.0f, 1.0f); + + BL_Material *mat = self->GetBLMaterial(); + mat->spec_f = mat->material->spec = val; + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_BlenderMaterial::pyattr_get_specular_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ +#ifdef USE_MATHUTILS + return Color_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), mathutils_kxblendermaterial_color_cb_index, MATHUTILS_COL_CB_MATERIAL_SPECULAR_COLOR); +#else + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + return PyColorFromVector(MT_Vector3(self->GetBLMaterial()->speccolor)); +#endif +} + +int KX_BlenderMaterial::pyattr_set_specular_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + MT_Vector3 color; + if (!PyVecTo(value, color)) + return PY_SET_ATTR_FAIL; + + BL_Material *mat = self->GetBLMaterial(); + color.getValue(mat->speccolor); + mat->material->specr = color[0]; + mat->material->specg = color[1]; + mat->material->specb = color[2]; + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_BlenderMaterial::pyattr_get_diffuse_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + return PyFloat_FromDouble(self->GetBLMaterial()->ref); +} + +int KX_BlenderMaterial::pyattr_set_diffuse_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + float val = PyFloat_AsDouble(value); + + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + + CLAMP(val, 0.0f, 1.0f); + + BL_Material *mat = self->GetBLMaterial(); + mat->ref = mat->material->ref = val; + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_BlenderMaterial::pyattr_get_diffuse_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ +#ifdef USE_MATHUTILS + return Color_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), mathutils_kxblendermaterial_color_cb_index, MATHUTILS_COL_CB_MATERIAL_DIFFUSE_COLOR); +#else + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + return PyColorFromVector(MT_Vector3(self->GetBLMaterial()->matcolor)); +#endif +} + +int KX_BlenderMaterial::pyattr_set_diffuse_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + MT_Vector3 color; + if (!PyVecTo(value, color)) + return PY_SET_ATTR_FAIL; + + BL_Material *mat = self->GetBLMaterial(); + color.getValue(mat->matcolor); + mat->material->r = color[0]; + mat->material->g = color[1]; + mat->material->b = color[2]; + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_BlenderMaterial::pyattr_get_emit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + return PyFloat_FromDouble(self->GetBLMaterial()->emit); +} + +int KX_BlenderMaterial::pyattr_set_emit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_BlenderMaterial *self = static_cast<KX_BlenderMaterial *>(self_v); + float val = PyFloat_AsDouble(value); + + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + + CLAMP(val, 0.0f, 2.0f); + + BL_Material *mat = self->GetBLMaterial(); + mat->emit = mat->material->emit = val; + return PY_SET_ATTR_SUCCESS; +} + int KX_BlenderMaterial::pyattr_set_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_BlenderMaterial* self = static_cast<KX_BlenderMaterial*>(self_v); diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h index b7c64215eaf..df089cb7f99 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.h +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h @@ -15,7 +15,7 @@ #include "BL_Shader.h" #include "BL_BlenderShader.h" -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" #include "MT_Vector3.h" #include "MT_Vector4.h" @@ -30,6 +30,11 @@ struct MTFace; class KX_Scene; + +#ifdef USE_MATHUTILS +void KX_BlenderMaterial_Mathutils_Callback_Init(void); +#endif + class KX_BlenderMaterial : public PyObjectPlus, public RAS_IPolyMaterial { Py_Header @@ -79,7 +84,7 @@ public: Material* GetBlenderMaterial() const; Image* GetBlenderImage() const; - MTFace* GetMTFace() const; + MTexPoly *GetMTexPoly() const; unsigned int* GetMCol() const; BL_Texture * getTex (unsigned int idx) { return (idx < MAXTEX) ? mTextures + idx : NULL; @@ -99,6 +104,8 @@ public: virtual void Replace_IScene(SCA_IScene *val); + BL_Material *GetBLMaterial(); + #ifdef WITH_PYTHON // -------------------------------- virtual PyObject *py_repr(void) { return PyUnicode_From_STR_String(mMaterial->matname); } @@ -107,6 +114,20 @@ public: static PyObject *pyattr_get_materialIndex(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject *pyattr_get_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_alpha(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_alpha(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_hardness(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_hardness(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_specular_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_specular_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_specular_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_specular_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_diffuse_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_diffuse_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_diffuse_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_diffuse_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_emit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_emit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); KX_PYMETHOD_DOC(KX_BlenderMaterial, getShader); KX_PYMETHOD_DOC(KX_BlenderMaterial, getMaterialIndex); @@ -134,6 +155,15 @@ private: bool mConstructed; // if false, don't clean on exit int mLightLayer; + struct { + float r, g, b, a; + float specr, specg, specb; + float spec; + float ref; + float hardness; + float emit; + } mSavedData; + void InitTextures(); void SetBlenderGLSLShader(); diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp index 4ab768e4240..644c71a68e4 100644 --- a/source/gameengine/Ketsji/KX_Camera.cpp +++ b/source/gameengine/Ketsji/KX_Camera.cpp @@ -31,11 +31,11 @@ */ -#include "GL/glew.h" +#include "glew-mx.h" #include "KX_Camera.h" #include "KX_Scene.h" #include "KX_PythonInit.h" -#include "KX_Python.h" +#include "EXP_Python.h" #include "KX_PyMath.h" #include "RAS_ICanvas.h" @@ -224,6 +224,22 @@ short KX_Camera::GetSensorFit() const return m_camdata.m_sensor_fit; } +/** + * Gets the horizontal shift of the sensor - for camera matching. + */ +float KX_Camera::GetShiftHorizontal() const +{ + return m_camdata.m_shift_x; +} + +/** + * Gets the vertical shift of the sensor - for camera matching. + */ +float KX_Camera::GetShiftVertical() const +{ + return m_camdata.m_shift_y; +} + float KX_Camera::GetCameraNear() const { return m_camdata.m_clipstart; @@ -463,6 +479,7 @@ bool KX_Camera::GetFrustumCulling() const void KX_Camera::EnableViewport(bool viewport) { + InvalidateProjectionMatrix(false); // We need to reset projection matrix m_camdata.m_viewport = viewport; } @@ -528,7 +545,9 @@ PyAttributeDef KX_Camera::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("ortho_scale", KX_Camera, pyattr_get_ortho_scale, pyattr_set_ortho_scale), KX_PYATTRIBUTE_RW_FUNCTION("near", KX_Camera, pyattr_get_near, pyattr_set_near), KX_PYATTRIBUTE_RW_FUNCTION("far", KX_Camera, pyattr_get_far, pyattr_set_far), - + KX_PYATTRIBUTE_RW_FUNCTION("shift_x", KX_Camera, pyattr_get_shift_x, pyattr_set_shift_x), + KX_PYATTRIBUTE_RW_FUNCTION("shift_y", KX_Camera, pyattr_get_shift_y, pyattr_set_shift_y), + KX_PYATTRIBUTE_RW_FUNCTION("useViewport", KX_Camera, pyattr_get_use_viewport, pyattr_set_use_viewport), KX_PYATTRIBUTE_RW_FUNCTION("projection_matrix", KX_Camera, pyattr_get_projection_matrix, pyattr_set_projection_matrix), @@ -747,7 +766,7 @@ int KX_Camera::pyattr_set_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, KX_Camera* self = static_cast<KX_Camera*>(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { - PyErr_SetString(PyExc_AttributeError, "camera.lens = float: KX_Camera, expected a float greater then zero"); + PyErr_SetString(PyExc_AttributeError, "camera.lens = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } @@ -772,7 +791,7 @@ int KX_Camera::pyattr_set_fov(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, P KX_Camera* self = static_cast<KX_Camera*>(self_v); float fov = PyFloat_AsDouble(value); if (fov <= 0.0) { - PyErr_SetString(PyExc_AttributeError, "camera.fov = float: KX_Camera, expected a float greater then zero"); + PyErr_SetString(PyExc_AttributeError, "camera.fov = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } @@ -796,7 +815,7 @@ int KX_Camera::pyattr_set_ortho_scale(void *self_v, const KX_PYATTRIBUTE_DEF *at KX_Camera* self = static_cast<KX_Camera*>(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { - PyErr_SetString(PyExc_AttributeError, "camera.ortho_scale = float: KX_Camera, expected a float greater then zero"); + PyErr_SetString(PyExc_AttributeError, "camera.ortho_scale = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } @@ -816,7 +835,7 @@ int KX_Camera::pyattr_set_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, KX_Camera* self = static_cast<KX_Camera*>(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { - PyErr_SetString(PyExc_AttributeError, "camera.near = float: KX_Camera, expected a float greater then zero"); + PyErr_SetString(PyExc_AttributeError, "camera.near = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } @@ -836,7 +855,7 @@ int KX_Camera::pyattr_set_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, P KX_Camera* self = static_cast<KX_Camera*>(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { - PyErr_SetString(PyExc_AttributeError, "camera.far = float: KX_Camera, expected a float greater then zero"); + PyErr_SetString(PyExc_AttributeError, "camera.far = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } @@ -845,6 +864,45 @@ int KX_Camera::pyattr_set_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, P return PY_SET_ATTR_SUCCESS; } +PyObject *KX_Camera::pyattr_get_shift_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Camera* self = static_cast<KX_Camera*>(self_v); + return PyFloat_FromDouble(self->m_camdata.m_shift_x); +} + +int KX_Camera::pyattr_set_shift_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Camera* self = static_cast<KX_Camera*>(self_v); + float param = PyFloat_AsDouble(value); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "camera.shift_x = float: KX_Camera, expected a float greater than zero"); + return PY_SET_ATTR_FAIL; + } + + self->m_camdata.m_shift_x = param; + self->m_set_projection_matrix = false; + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_Camera::pyattr_get_shift_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Camera* self = static_cast<KX_Camera*>(self_v); + return PyFloat_FromDouble(self->m_camdata.m_shift_y); +} + +int KX_Camera::pyattr_set_shift_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Camera* self = static_cast<KX_Camera*>(self_v); + float param = PyFloat_AsDouble(value); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "camera.shift_y = float: KX_Camera, expected a float greater than zero"); + return PY_SET_ATTR_FAIL; + } + + self->m_camdata.m_shift_y = param; + self->m_set_projection_matrix = false; + return PY_SET_ATTR_SUCCESS; +} PyObject *KX_Camera::pyattr_get_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { @@ -885,7 +943,7 @@ int KX_Camera::pyattr_set_projection_matrix(void *self_v, const KX_PYATTRIBUTE_D PyObject *KX_Camera::pyattr_get_modelview_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_Camera* self = static_cast<KX_Camera*>(self_v); - return PyObjectFrom(self->GetModelviewMatrix()); + return PyObjectFrom(self->GetWorldToCamera()); } PyObject *KX_Camera::pyattr_get_camera_to_world(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -994,7 +1052,7 @@ KX_PYMETHODDEF_DOC_O(KX_Camera, getScreenPosition, GLdouble modelmatrix[16]; GLdouble projmatrix[16]; - MT_Matrix4x4 m_modelmatrix = this->GetModelviewMatrix(); + MT_Matrix4x4 m_modelmatrix = this->GetWorldToCamera(); MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix(); m_modelmatrix.getValue(modelmatrix); @@ -1037,7 +1095,7 @@ KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenVect, GLdouble modelmatrix[16]; GLdouble projmatrix[16]; - MT_Matrix4x4 m_modelmatrix = this->GetModelviewMatrix(); + MT_Matrix4x4 m_modelmatrix = this->GetWorldToCamera(); MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix(); m_modelmatrix.getValue(modelmatrix); diff --git a/source/gameengine/Ketsji/KX_Camera.h b/source/gameengine/Ketsji/KX_Camera.h index 454c4a54ec1..8addf0b7aed 100644 --- a/source/gameengine/Ketsji/KX_Camera.h +++ b/source/gameengine/Ketsji/KX_Camera.h @@ -40,7 +40,7 @@ #include "MT_Vector3.h" #include "MT_Point3.h" #include "KX_GameObject.h" -#include "IntValue.h" +#include "EXP_IntValue.h" #include "RAS_CameraData.h" #ifdef WITH_PYTHON @@ -192,7 +192,7 @@ public: void InvalidateProjectionMatrix(bool valid = false); /** Gets the modelview matrix that is used by the rasterizer. - * \warning If the Camera is a dynamic object then this method may return garbage. Use GetCameraToWorld() instead. + * \warning If the Camera is a dynamic object then this method may return garbage. Use GetWorldToCamera() instead. */ const MT_Matrix4x4& GetModelviewMatrix() const; @@ -206,6 +206,10 @@ public: float GetSensorHeight() const; /** Gets the mode FOV is calculating from sensor dimensions */ short GetSensorFit() const; + /** Gets the horizontal shift of the sensor - for camera matching */ + float GetShiftHorizontal() const; + /** Gets the vertical shift of the sensor - for camera matching */ + float GetShiftVertical() const; /** Gets the near clip distance. */ float GetCameraNear() const; /** Gets the far clip distance. */ @@ -306,7 +310,11 @@ public: static int pyattr_set_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - + static PyObject* pyattr_get_shift_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_shift_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_shift_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_shift_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); diff --git a/source/gameengine/Ketsji/KX_CameraActuator.cpp b/source/gameengine/Ketsji/KX_CameraActuator.cpp index acf30b4866c..f065e3f0001 100644 --- a/source/gameengine/Ketsji/KX_CameraActuator.cpp +++ b/source/gameengine/Ketsji/KX_CameraActuator.cpp @@ -40,7 +40,7 @@ #include <float.h> #include "KX_GameObject.h" -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" /* ------------------------------------------------------------------------- */ /* Native functions */ @@ -288,19 +288,23 @@ bool KX_CameraActuator::Update(double curtime, bool frame) from[1] += fac * fp1[1]; from[2] += fac * fp1[2]; - /* alleen alstie ervoor ligt: cross testen en loodrechte bijtellen */ + /* only for it lies: cross test and perpendicular bites up */ if (inp < 0.0f) { - if (fp1[0] * fp2[1] - fp1[1] * fp2[0] > 0.0f) { + /* Don't do anything if the cross product is too small. + * The camera up-axis becomes unstable and starts to oscillate. + * The 0.01f threshold is arbitrary but seems to work well in practice. */ + float cross = fp1[0] * fp2[1] - fp1[1] * fp2[0]; + if (cross > 0.01f) { from[0] -= fac * fp1[1]; from[1] += fac * fp1[0]; } - else { + else if (cross < -0.01f) { from[0] += fac * fp1[1]; from[1] -= fac * fp1[0]; } } - /* CONSTRAINT 5: minimum / maximum afstand */ + /* CONSTRAINT 5: minimum / maximum distance */ rc[0] = (lookat[0]-from[0]); rc[1] = (lookat[1]-from[1]); @@ -323,7 +327,7 @@ bool KX_CameraActuator::Update(double curtime, bool frame) } - /* CONSTRAINT 7: track to schaduw */ + /* CONSTRAINT 7: track to floor below actor */ rc[0] = (lookat[0]-from[0]); rc[1] = (lookat[1]-from[1]); rc[2] = (lookat[2]-from[2]); diff --git a/source/gameengine/Ketsji/KX_CharacterWrapper.h b/source/gameengine/Ketsji/KX_CharacterWrapper.h index d4d8f195102..dd7ba680ec7 100644 --- a/source/gameengine/Ketsji/KX_CharacterWrapper.h +++ b/source/gameengine/Ketsji/KX_CharacterWrapper.h @@ -6,7 +6,7 @@ #ifndef __KX_CHARACTERWRAPPER_H__ #define __KX_CHARACTERWRAPPER_H__ -#include "Value.h" +#include "EXP_Value.h" #include "PHY_DynamicTypes.h" class PHY_ICharacter; diff --git a/source/gameengine/Ketsji/KX_ClientObjectInfo.h b/source/gameengine/Ketsji/KX_ClientObjectInfo.h index e947eb4be6d..81ae5b58009 100644 --- a/source/gameengine/Ketsji/KX_ClientObjectInfo.h +++ b/source/gameengine/Ketsji/KX_ClientObjectInfo.h @@ -52,19 +52,16 @@ struct KX_ClientObjectInfo OBACTORSENSOR } m_type; KX_GameObject* m_gameobject; - void* m_auxilary_info; std::list<SCA_ISensor*> m_sensors; public: - KX_ClientObjectInfo(KX_GameObject *gameobject, clienttype type = STATIC, void *auxilary_info = NULL) : + KX_ClientObjectInfo(KX_GameObject *gameobject, clienttype type = STATIC) : m_type(type), - m_gameobject(gameobject), - m_auxilary_info(auxilary_info) + m_gameobject(gameobject) {} KX_ClientObjectInfo(const KX_ClientObjectInfo ©) : m_type(copy.m_type), - m_gameobject(copy.m_gameobject), - m_auxilary_info(copy.m_auxilary_info) + m_gameobject(copy.m_gameobject) { } diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp index e5662b54b83..e07660cef72 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp @@ -41,6 +41,7 @@ #include "KX_GameObject.h" #include "KX_RayCast.h" #include "KX_PythonInit.h" // KX_GetActiveScene +#include "RAS_MeshObject.h" #include <stdio.h> @@ -129,15 +130,17 @@ bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo *client, KX_RayCast *resu } else { - if (m_option & KX_ACT_CONSTRAINT_MATERIAL) - { - if (client->m_auxilary_info) - { - bFound = !strcmp(m_property.Ptr(), ((char*)client->m_auxilary_info)); + if (m_option & KX_ACT_CONSTRAINT_MATERIAL) { + for (unsigned int i = 0; i < m_hitObject->GetMeshCount(); ++i) { + RAS_MeshObject *meshObj = m_hitObject->GetMesh(i); + for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { + bFound = strcmp(m_property.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; + if (bFound) + break; + } } } - else - { + else { bFound = m_hitObject->GetProperty(m_property) != NULL; } } diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp index 29d92762285..2f32b5e3216 100644 --- a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp @@ -30,7 +30,7 @@ */ -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" #include "KX_ConstraintWrapper.h" #include "PHY_IPhysicsEnvironment.h" diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.h b/source/gameengine/Ketsji/KX_ConstraintWrapper.h index b7124c76439..5e20b7a9aca 100644 --- a/source/gameengine/Ketsji/KX_ConstraintWrapper.h +++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.h @@ -32,7 +32,7 @@ #ifndef __KX_CONSTRAINTWRAPPER_H__ #define __KX_CONSTRAINTWRAPPER_H__ -#include "Value.h" +#include "EXP_Value.h" #include "PHY_DynamicTypes.h" class KX_ConstraintWrapper : public PyObjectPlus diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp index c7f7f586865..07bed647b29 100644 --- a/source/gameengine/Ketsji/KX_Dome.cpp +++ b/source/gameengine/Ketsji/KX_Dome.cpp @@ -41,7 +41,7 @@ #include "RAS_CameraData.h" #include "BLI_math.h" -#include "GL/glew.h" +#include "glew-mx.h" // constructor KX_Dome::KX_Dome ( @@ -2044,7 +2044,9 @@ void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i) cam->NodeUpdateGS(0.f); scene->CalculateVisibleMeshes(m_rasterizer,cam); - scene->UpdateAnimations(m_engine->GetFrameTime()); + + m_engine->UpdateAnimations(scene); + scene->RenderBuckets(camtrans, m_rasterizer); } diff --git a/source/gameengine/Ketsji/KX_Dome.h b/source/gameengine/Ketsji/KX_Dome.h index a7e798a3944..420565e62f6 100644 --- a/source/gameengine/Ketsji/KX_Dome.h +++ b/source/gameengine/Ketsji/KX_Dome.h @@ -38,7 +38,7 @@ #include "RAS_IRasterizer.h" #include "KX_KetsjiEngine.h" -#include "GL/glew.h" +#include "glew-mx.h" #include <vector> #include "MEM_guardedalloc.h" diff --git a/source/gameengine/Ketsji/KX_FontObject.cpp b/source/gameengine/Ketsji/KX_FontObject.cpp index 9789a8294ee..420f1f7eb98 100644 --- a/source/gameengine/Ketsji/KX_FontObject.cpp +++ b/source/gameengine/Ketsji/KX_FontObject.cpp @@ -35,7 +35,7 @@ #include "KX_Scene.h" #include "KX_PythonInit.h" #include "BLI_math.h" -#include "StringValue.h" +#include "EXP_StringValue.h" #include "RAS_IRasterizer.h" /* paths needed for font load */ @@ -118,7 +118,6 @@ CValue* KX_FontObject::GetReplica() void KX_FontObject::ProcessReplica() { KX_GameObject::ProcessReplica(); - KX_GetActiveScene()->AddFont(this); } int GetFontId(VFont *vfont) diff --git a/source/gameengine/Ketsji/KX_FontObject.h b/source/gameengine/Ketsji/KX_FontObject.h index 209ab6ca69f..bf70eedfde6 100644 --- a/source/gameengine/Ketsji/KX_FontObject.h +++ b/source/gameengine/Ketsji/KX_FontObject.h @@ -54,6 +54,7 @@ public: */ virtual CValue* GetReplica(); virtual void ProcessReplica(); + virtual int GetGameObjectType() { return OBJ_TEXT; } protected: std::vector<STR_String> m_text; diff --git a/source/gameengine/Ketsji/KX_GameActuator.cpp b/source/gameengine/Ketsji/KX_GameActuator.cpp index c6087ac676d..a23af680104 100644 --- a/source/gameengine/Ketsji/KX_GameActuator.cpp +++ b/source/gameengine/Ketsji/KX_GameActuator.cpp @@ -178,6 +178,11 @@ bool KX_GameActuator::Update() // obtain file size: fseek (fp , 0 , SEEK_END); marshal_length = ftell(fp); + if (marshal_length == -1) { + printf("warning: could not read position of '%s'\n", mashal_path); + fclose(fp); + break; + } rewind(fp); marshal_buffer = (char*) malloc (sizeof(char)*marshal_length); diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index c681e0842c4..c3da80bc14f 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -36,14 +36,6 @@ # pragma warning( disable:4786 ) #endif -#if defined(_WIN64) && !defined(FREE_WINDOWS64) -typedef unsigned __int64 uint_ptr; -#elif defined(FREE_WINDOWS64) -typedef unsigned long long uint_ptr; -#else -typedef unsigned long uint_ptr; -#endif - #include "RAS_IPolygonMaterial.h" #include "KX_BlenderMaterial.h" #include "KX_GameObject.h" @@ -55,6 +47,7 @@ typedef unsigned long uint_ptr; #include "KX_MeshProxy.h" #include "KX_PolyProxy.h" #include <stdio.h> // printf +#include <climits> // USHRT_MAX #include "SG_Controller.h" #include "PHY_IGraphicController.h" #include "SG_Node.h" @@ -76,7 +69,13 @@ typedef unsigned long uint_ptr; #include "BL_ActionManager.h" #include "BL_Action.h" -#include "PyObjectPlus.h" /* python stuff */ +#include "EXP_PyObjectPlus.h" /* python stuff */ +#include "BLI_utildefines.h" + +#ifdef WITH_PYTHON +# include "EXP_PythonCallBack.h" +# include "python_utildefines.h" +#endif // This file defines relationships between parents and children // in the game engine. @@ -97,9 +96,10 @@ KX_GameObject::KX_GameObject( : SCA_IObject(), m_bDyna(false), m_layer(0), + m_currentLodLevel(0), + m_previousLodLevel(0), m_pBlenderObject(NULL), m_pBlenderGroupObject(NULL), - m_bSuspendDynamics(false), m_bUseObjectColor(false), m_bIsNegativeScaling(false), m_objectColor(1.0, 1.0, 1.0, 1.0), @@ -297,6 +297,21 @@ void KX_GameObject::SetDupliGroupObject(KX_GameObject* obj) m_pDupliGroupObject = obj; } +void KX_GameObject::AddConstraint(bRigidBodyJointConstraint *cons) +{ + m_constraints.push_back(cons); +} + +std::vector<bRigidBodyJointConstraint*> KX_GameObject::GetConstraints() +{ + return m_constraints; +} + +void KX_GameObject::ClearConstraints() +{ + m_constraints.clear(); +} + KX_GameObject* KX_GameObject::GetParent() { KX_GameObject* result = NULL; @@ -454,6 +469,11 @@ void KX_GameObject::StopAction(short layer) GetActionManager()->StopAction(layer); } +void KX_GameObject::RemoveTaggedActions() +{ + GetActionManager()->RemoveTaggedActions(); +} + bool KX_GameObject::IsActionDone(short layer) { return GetActionManager()->IsActionDone(layer); @@ -474,6 +494,11 @@ float KX_GameObject::GetActionFrame(short layer) return GetActionManager()->GetActionFrame(layer); } +const char *KX_GameObject::GetActionName(short layer) +{ + return GetActionManager()->GetActionName(layer); +} + void KX_GameObject::SetActionFrame(short layer, float frame) { GetActionManager()->SetActionFrame(layer, frame); @@ -551,13 +576,26 @@ void KX_GameObject::ActivateGraphicController(bool recurse) } } -void KX_GameObject::SetUserCollisionGroup(short group) +void KX_GameObject::SetUserCollisionGroup(unsigned short group) { m_userCollisionGroup = group; + if (m_pPhysicsController) + m_pPhysicsController->RefreshCollisions(); } -void KX_GameObject::SetUserCollisionMask(short mask) +void KX_GameObject::SetUserCollisionMask(unsigned short mask) { m_userCollisionMask = mask; + if (m_pPhysicsController) + m_pPhysicsController->RefreshCollisions(); +} + +unsigned short KX_GameObject::GetUserCollisionGroup() +{ + return m_userCollisionGroup; +} +unsigned short KX_GameObject::GetUserCollisionMask() +{ + return m_userCollisionMask; } bool KX_GameObject::CheckCollision(KX_GameObject* other) @@ -575,6 +613,46 @@ CValue* KX_GameObject::GetReplica() return replica; } +bool KX_GameObject::IsDynamicsSuspended() const +{ + if (m_pPhysicsController) + return m_pPhysicsController->IsSuspended(); + return false; +} + +float KX_GameObject::getLinearDamping() const +{ + if (m_pPhysicsController) + return m_pPhysicsController->GetLinearDamping(); + return 0; +} + +float KX_GameObject::getAngularDamping() const +{ + if (m_pPhysicsController) + return m_pPhysicsController->GetAngularDamping(); + return 0; +} + +void KX_GameObject::setLinearDamping(float damping) +{ + if (m_pPhysicsController) + m_pPhysicsController->SetLinearDamping(damping); +} + + +void KX_GameObject::setAngularDamping(float damping) +{ + if (m_pPhysicsController) + m_pPhysicsController->SetAngularDamping(damping); +} + + +void KX_GameObject::setDamping(float linear, float angular) +{ + if (m_pPhysicsController) + m_pPhysicsController->SetDamping(linear, angular); +} void KX_GameObject::ApplyForce(const MT_Vector3& force,bool local) @@ -741,35 +819,74 @@ void KX_GameObject::AddLodMesh(RAS_MeshObject* mesh) m_lodmeshes.push_back(mesh); } + +static float calcHysteresis(KX_Scene *kxscene, LodLevel *lod) +{ + float hystvariance = 0.0f; + + if (!kxscene->IsActivedLodHysteresis()) + return hystvariance; + + short hysteresis = 0; + // if exists, LoD level hysteresis will override scene hysteresis + if (lod->next->flags & OB_LOD_USE_HYST) + hysteresis = lod->next->obhysteresis; + else + hysteresis = kxscene->GetLodHysteresisValue(); + + return hystvariance = MT_abs(lod->next->distance - lod->distance) * hysteresis / 100; +} + void KX_GameObject::UpdateLod(MT_Vector3 &cam_pos) { // Handle dupligroups - if (this->m_pInstanceObjects) { - KX_GameObject * instob; - int count = this->m_pInstanceObjects->GetCount(); + if (m_pInstanceObjects) { + KX_GameObject *instob; + int count = m_pInstanceObjects->GetCount(); for (int i = 0; i < count; i++) { - instob = (KX_GameObject*)this->m_pInstanceObjects->GetValue(i); + instob = (KX_GameObject*)m_pInstanceObjects->GetValue(i); instob->UpdateLod(cam_pos); } } - if (this->m_lodmeshes.empty()) return; + if (m_lodmeshes.empty()) + return; - MT_Vector3 delta = this->NodeGetWorldPosition() - cam_pos; + MT_Vector3 delta = NodeGetWorldPosition() - cam_pos; float distance2 = delta.length2(); int level = 0; - Object *bob = this->GetBlenderObject(); - LodLevel *lod = (LodLevel*) bob->lodlevels.first; + float hystvariance = 0.0f; + Object *bob = GetBlenderObject(); + LodLevel *lod = (LodLevel *)bob->lodlevels.first; + KX_Scene *kxscene = GetScene(); + for (; lod; lod = lod->next, level++) { - if (!lod->source || lod->source->type != OB_MESH) level--; - if (!lod->next || lod->next->distance * lod->next->distance > distance2) break; - } + if (!lod->source || lod->source->type != OB_MESH) + level--; - RAS_MeshObject *mesh = this->m_lodmeshes[level]; + if (!lod->next) + break; + + if (level == m_previousLodLevel || level == (m_previousLodLevel + 1)) { + hystvariance = calcHysteresis(kxscene, lod); + float newdistance = lod->next->distance + hystvariance; + if (newdistance * newdistance > distance2) + break; + } + else if (level == (m_previousLodLevel - 1)) { + hystvariance = calcHysteresis(kxscene, lod); + float newdistance = lod->next->distance - hystvariance; + if (newdistance * newdistance > distance2) + break; + } + } - if (mesh != this->m_meshes[0]) { - this->GetScene()->ReplaceMesh(this, mesh, true, false); + RAS_MeshObject *mesh = m_lodmeshes[level]; + m_currentLodLevel = level; + if (mesh != m_meshes[0]) { + m_previousLodLevel = level; + GetScene()->ReplaceMesh(this, mesh, true, false); } } @@ -930,27 +1047,6 @@ KX_GameObject::SetVisible( } } -bool KX_GameObject::GetCulled() -{ - // If we're set to not cull, double-check with - // the mesh slots first. This is kind of nasty, but - // it allows us to get proper culling information. - if (!m_bCulled) - { - SG_QList::iterator<RAS_MeshSlot> mit(m_meshSlots); - for (mit.begin(); !mit.end(); ++mit) - { - if ((*mit)->m_bCulled) - { - m_bCulled = true; - break; - } - } - } - - return m_bCulled; -} - static void setOccluder_recursive(SG_Node* node, bool v) { NodeList& children = node->GetSGChildren(); @@ -1486,36 +1582,27 @@ void KX_GameObject::RegisterCollisionCallbacks() pe->AddSensor(spc); } } -void KX_GameObject::RunCollisionCallbacks(KX_GameObject *collider) +void KX_GameObject::RunCollisionCallbacks(KX_GameObject *collider, const MT_Vector3 &point, const MT_Vector3 &normal) { - #ifdef WITH_PYTHON - Py_ssize_t len; - PyObject* collision_callbacks = m_collisionCallbacks; - - if (collision_callbacks && (len=PyList_GET_SIZE(collision_callbacks))) - { - PyObject* args = Py_BuildValue("(O)", collider->GetProxy()); // save python creating each call - PyObject *func; - PyObject *ret; +#ifdef WITH_PYTHON + if (!m_collisionCallbacks || PyList_GET_SIZE(m_collisionCallbacks) == 0) + return; - // Iterate the list and run the callbacks - for (Py_ssize_t pos=0; pos < len; pos++) - { - func = PyList_GET_ITEM(collision_callbacks, pos); - ret = PyObject_Call(func, args, NULL); + /** Current logic controller is set by each python logic bricks before run, + * but if no python logic brick ran the logic manager can be wrong + * (if the user use muti scenes) and it will cause problems with function + * ConvertPythonToGameObject which use the current logic manager for object's name. + * Note: the scene is already set in logic frame loop. + */ + SCA_ILogicBrick::m_sCurrentLogicManager = GetScene()->GetLogicManager(); - if (ret == NULL) { - PyErr_Print(); - PyErr_Clear(); - } - else { - Py_DECREF(ret); - } - } + PyObject *args[] = {collider->GetProxy(), PyObjectFrom(point), PyObjectFrom(normal)}; + RunPythonCallBackList(m_collisionCallbacks, args, 1, ARRAY_SIZE(args)); - Py_DECREF(args); + for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) { + Py_DECREF(args[i]); } - #endif +#endif } /* Suspend/ resume: for the dynamic behavior, there is a simple @@ -1529,7 +1616,8 @@ void KX_GameObject::Resume(void) { if (m_suspended) { SCA_IObject::Resume(); - if (GetPhysicsController()) + // Child objects must be static, so we block changing to dynamic + if (GetPhysicsController() && !GetParent()) GetPhysicsController()->RestoreDynamics(); m_suspended = false; @@ -1587,9 +1675,11 @@ CListValue* KX_GameObject::GetChildrenRecursive() KX_Scene* KX_GameObject::GetScene() { SG_Node* node = this->GetSGNode(); - KX_Scene* scene = static_cast<KX_Scene*>(node->GetSGClientInfo()); - - return scene; + if (node == NULL) { + // this happens for object in non active layers, rely on static scene then + return KX_GetActiveScene(); + } + return static_cast<KX_Scene*>(node->GetSGClientInfo()); } /* --------------------------------------------------------------------- @@ -1823,7 +1913,7 @@ static Mathutils_Callback mathutils_kxgameob_matrix_cb = { void KX_GameObject_Mathutils_Callback_Init(void) { - // register mathutils callbacks, ok to run more then once. + // register mathutils callbacks, ok to run more than once. mathutils_kxgameob_vector_cb_index= Mathutils_RegisterCallback(&mathutils_kxgameob_vector_cb); mathutils_kxgameob_matrix_cb_index= Mathutils_RegisterCallback(&mathutils_kxgameob_matrix_cb); } @@ -1842,10 +1932,11 @@ PyMethodDef KX_GameObject::Methods[] = { {"getAngularVelocity", (PyCFunction) KX_GameObject::sPyGetAngularVelocity, METH_VARARGS}, {"setAngularVelocity", (PyCFunction) KX_GameObject::sPySetAngularVelocity, METH_VARARGS}, {"getVelocity", (PyCFunction) KX_GameObject::sPyGetVelocity, METH_VARARGS}, + {"setDamping", (PyCFunction) KX_GameObject::sPySetDamping, METH_VARARGS}, {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_NOARGS}, {"alignAxisToVect",(PyCFunction) KX_GameObject::sPyAlignAxisToVect, METH_VARARGS}, {"getAxisVect",(PyCFunction) KX_GameObject::sPyGetAxisVect, METH_O}, - {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics,METH_NOARGS}, + {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics, METH_VARARGS}, {"restoreDynamics", (PyCFunction)KX_GameObject::sPyRestoreDynamics,METH_NOARGS}, {"enableRigidBody", (PyCFunction)KX_GameObject::sPyEnableRigidBody,METH_NOARGS}, {"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_NOARGS}, @@ -1873,6 +1964,7 @@ PyMethodDef KX_GameObject::Methods[] = { KX_PYMETHODTABLE_KEYWORDS(KX_GameObject, playAction), KX_PYMETHODTABLE(KX_GameObject, stopAction), KX_PYMETHODTABLE(KX_GameObject, getActionFrame), + KX_PYMETHODTABLE(KX_GameObject, getActionName), KX_PYMETHODTABLE(KX_GameObject, setActionFrame), KX_PYMETHODTABLE(KX_GameObject, isPlayingAction), @@ -1883,6 +1975,7 @@ PyMethodDef KX_GameObject::Methods[] = { }; PyAttributeDef KX_GameObject::Attributes[] = { + KX_PYATTRIBUTE_INT_RO("currentLodLevel", KX_GameObject, m_currentLodLevel), KX_PYATTRIBUTE_RO_FUNCTION("name", KX_GameObject, pyattr_get_name), KX_PYATTRIBUTE_RO_FUNCTION("parent", KX_GameObject, pyattr_get_parent), KX_PYATTRIBUTE_RO_FUNCTION("groupMembers", KX_GameObject, pyattr_get_group_members), @@ -1890,8 +1983,11 @@ PyAttributeDef KX_GameObject::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("scene", KX_GameObject, pyattr_get_scene), KX_PYATTRIBUTE_RO_FUNCTION("life", KX_GameObject, pyattr_get_life), KX_PYATTRIBUTE_RW_FUNCTION("mass", KX_GameObject, pyattr_get_mass, pyattr_set_mass), + KX_PYATTRIBUTE_RO_FUNCTION("isSuspendDynamics", KX_GameObject, pyattr_get_is_suspend_dynamics), KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMin", KX_GameObject, pyattr_get_lin_vel_min, pyattr_set_lin_vel_min), KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMax", KX_GameObject, pyattr_get_lin_vel_max, pyattr_set_lin_vel_max), + KX_PYATTRIBUTE_RW_FUNCTION("angularVelocityMin", KX_GameObject, pyattr_get_ang_vel_min, pyattr_set_ang_vel_min), + KX_PYATTRIBUTE_RW_FUNCTION("angularVelocityMax", KX_GameObject, pyattr_get_ang_vel_max, pyattr_set_ang_vel_max), KX_PYATTRIBUTE_RW_FUNCTION("visible", KX_GameObject, pyattr_get_visible, pyattr_set_visible), KX_PYATTRIBUTE_RW_FUNCTION("record_animation", KX_GameObject, pyattr_get_record_animation, pyattr_set_record_animation), KX_PYATTRIBUTE_BOOL_RW ("occlusion", KX_GameObject, m_bOccluder), @@ -1901,6 +1997,8 @@ PyAttributeDef KX_GameObject::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("scaling", KX_GameObject, pyattr_get_worldScaling, pyattr_set_localScaling), KX_PYATTRIBUTE_RW_FUNCTION("timeOffset",KX_GameObject, pyattr_get_timeOffset,pyattr_set_timeOffset), KX_PYATTRIBUTE_RW_FUNCTION("collisionCallbacks", KX_GameObject, pyattr_get_collisionCallbacks, pyattr_set_collisionCallbacks), + KX_PYATTRIBUTE_RW_FUNCTION("collisionGroup", KX_GameObject, pyattr_get_collisionGroup, pyattr_set_collisionGroup), + KX_PYATTRIBUTE_RW_FUNCTION("collisionMask", KX_GameObject, pyattr_get_collisionMask, pyattr_set_collisionMask), KX_PYATTRIBUTE_RW_FUNCTION("state", KX_GameObject, pyattr_get_state, pyattr_set_state), KX_PYATTRIBUTE_RO_FUNCTION("meshes", KX_GameObject, pyattr_get_meshes), KX_PYATTRIBUTE_RW_FUNCTION("localOrientation",KX_GameObject,pyattr_get_localOrientation,pyattr_set_localOrientation), @@ -1917,6 +2015,8 @@ PyAttributeDef KX_GameObject::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("angularVelocity", KX_GameObject, pyattr_get_localAngularVelocity, pyattr_set_worldAngularVelocity), KX_PYATTRIBUTE_RW_FUNCTION("localAngularVelocity", KX_GameObject, pyattr_get_localAngularVelocity, pyattr_set_localAngularVelocity), KX_PYATTRIBUTE_RW_FUNCTION("worldAngularVelocity", KX_GameObject, pyattr_get_worldAngularVelocity, pyattr_set_worldAngularVelocity), + KX_PYATTRIBUTE_RW_FUNCTION("linearDamping", KX_GameObject, pyattr_get_linearDamping, pyattr_set_linearDamping), + KX_PYATTRIBUTE_RW_FUNCTION("angularDamping", KX_GameObject, pyattr_get_angularDamping, pyattr_set_angularDamping), KX_PYATTRIBUTE_RO_FUNCTION("children", KX_GameObject, pyattr_get_children), KX_PYATTRIBUTE_RO_FUNCTION("childrenRecursive", KX_GameObject, pyattr_get_children_recursive), KX_PYATTRIBUTE_RO_FUNCTION("attrDict", KX_GameObject, pyattr_get_attrDict), @@ -2245,6 +2345,56 @@ int KX_GameObject::pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIB return PY_SET_ATTR_SUCCESS; } +PyObject *KX_GameObject::pyattr_get_collisionGroup(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + return PyLong_FromLong(self->GetUserCollisionGroup()); +} + +int KX_GameObject::pyattr_set_collisionGroup(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + int val = PyLong_AsLong(value); + + if (val == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "gameOb.collisionGroup = int: KX_GameObject, expected an int bit field"); + return PY_SET_ATTR_FAIL; + } + + if (val < 0 || val > USHRT_MAX) { + PyErr_Format(PyExc_AttributeError, "gameOb.collisionGroup = int: KX_GameObject, expected a int bit field between 0 and %i", USHRT_MAX); + return PY_SET_ATTR_FAIL; + } + + self->SetUserCollisionGroup(val); + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_GameObject::pyattr_get_collisionMask(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + return PyLong_FromLong(self->GetUserCollisionMask()); +} + +int KX_GameObject::pyattr_set_collisionMask(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + int val = PyLong_AsLong(value); + + if (val == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "gameOb.collisionMask = int: KX_GameObject, expected an int bit field"); + return PY_SET_ATTR_FAIL; + } + + if (val < 0 || val > USHRT_MAX) { + PyErr_Format(PyExc_AttributeError, "gameOb.collisionMask = int: KX_GameObject, expected a int bit field between 0 and %i", USHRT_MAX); + return PY_SET_ATTR_FAIL; + } + + self->SetUserCollisionMask(val); + return PY_SET_ATTR_SUCCESS; +} + PyObject* KX_GameObject::pyattr_get_scene(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_GameObject *self = static_cast<KX_GameObject*>(self_v); @@ -2301,6 +2451,19 @@ int KX_GameObject::pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrd return PY_SET_ATTR_SUCCESS; } +PyObject *KX_GameObject::pyattr_get_is_suspend_dynamics(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + + // Only objects with a physics controller can be suspended + if (!self->GetPhysicsController()) { + PyErr_SetString(PyExc_AttributeError, "This object has not Physics Controller"); + return NULL; + } + + return PyBool_FromLong(self->IsDynamicsSuspended()); +} + PyObject *KX_GameObject::pyattr_get_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_GameObject* self = static_cast<KX_GameObject*>(self_v); @@ -2347,6 +2510,54 @@ int KX_GameObject::pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF return PY_SET_ATTR_SUCCESS; } +PyObject *KX_GameObject::pyattr_get_ang_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject *self = static_cast<KX_GameObject*>(self_v); + PHY_IPhysicsController *spc = self->GetPhysicsController(); + return PyFloat_FromDouble(spc ? spc->GetAngularVelocityMin() : 0.0f); +} + +int KX_GameObject::pyattr_set_ang_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject *self = static_cast<KX_GameObject*>(self_v); + PHY_IPhysicsController *spc = self->GetPhysicsController(); + MT_Scalar val = PyFloat_AsDouble(value); + if (val < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, + "gameOb.angularVelocityMin = float: KX_GameObject, expected a nonnegative float"); + return PY_SET_ATTR_FAIL; + } + + if (spc) + spc->SetAngularVelocityMin(val); + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_GameObject::pyattr_get_ang_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject *self = static_cast<KX_GameObject*>(self_v); + PHY_IPhysicsController *spc = self->GetPhysicsController(); + return PyFloat_FromDouble(spc ? spc->GetAngularVelocityMax() : 0.0f); +} + +int KX_GameObject::pyattr_set_ang_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject *self = static_cast<KX_GameObject*>(self_v); + PHY_IPhysicsController *spc = self->GetPhysicsController(); + MT_Scalar val = PyFloat_AsDouble(value); + if (val < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, + "gameOb.angularVelocityMax = float: KX_GameObject, expected a nonnegative float"); + return PY_SET_ATTR_FAIL; + } + + if (spc) + spc->SetAngularVelocityMax(val); + + return PY_SET_ATTR_SUCCESS; +} + PyObject *KX_GameObject::pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { @@ -2393,7 +2604,9 @@ int KX_GameObject::pyattr_set_record_animation(void *self_v, const KX_PYATTRIBUT PyObject *KX_GameObject::pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_GLOBAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_GLOBAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->NodeGetWorldPosition()); @@ -2415,7 +2628,9 @@ int KX_GameObject::pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_D PyObject *KX_GameObject::pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_LOCAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_LOCAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->NodeGetLocalPosition()); @@ -2437,7 +2652,9 @@ int KX_GameObject::pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_D PyObject *KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_INERTIA_LOCAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_INERTIA_LOCAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); if (self->GetPhysicsController1()) @@ -2449,7 +2666,9 @@ PyObject *KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIB PyObject *KX_GameObject::pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Matrix_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, 3, mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_GLOBAL); + return Matrix_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, 3, + mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_GLOBAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->NodeGetWorldOrientation()); @@ -2474,7 +2693,9 @@ int KX_GameObject::pyattr_set_worldOrientation(void *self_v, const KX_PYATTRIBUT PyObject *KX_GameObject::pyattr_get_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Matrix_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, 3, mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_LOCAL); + return Matrix_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, 3, + mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_LOCAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->NodeGetLocalOrientation()); @@ -2498,7 +2719,9 @@ int KX_GameObject::pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUT PyObject *KX_GameObject::pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_GLOBAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_GLOBAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->NodeGetWorldScaling()); @@ -2520,7 +2743,9 @@ int KX_GameObject::pyattr_set_worldScaling(void *self_v, const KX_PYATTRIBUTE_DE PyObject *KX_GameObject::pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_LOCAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_LOCAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->NodeGetLocalScaling()); @@ -2622,7 +2847,9 @@ int KX_GameObject::pyattr_set_worldTransform(void *self_v, const KX_PYATTRIBUTE_ PyObject *KX_GameObject::pyattr_get_worldLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_GLOBAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_GLOBAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(GetLinearVelocity(false)); @@ -2644,7 +2871,9 @@ int KX_GameObject::pyattr_set_worldLinearVelocity(void *self_v, const KX_PYATTRI PyObject *KX_GameObject::pyattr_get_localLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_LOCAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_LOCAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(GetLinearVelocity(true)); @@ -2666,7 +2895,9 @@ int KX_GameObject::pyattr_set_localLinearVelocity(void *self_v, const KX_PYATTRI PyObject *KX_GameObject::pyattr_get_worldAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_GLOBAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_GLOBAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(GetAngularVelocity(false)); @@ -2688,7 +2919,9 @@ int KX_GameObject::pyattr_set_worldAngularVelocity(void *self_v, const KX_PYATTR PyObject *KX_GameObject::pyattr_get_localAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_LOCAL); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_LOCAL); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(GetAngularVelocity(true)); @@ -2707,6 +2940,34 @@ int KX_GameObject::pyattr_set_localAngularVelocity(void *self_v, const KX_PYATTR return PY_SET_ATTR_SUCCESS; } +PyObject *KX_GameObject::pyattr_get_linearDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + return PyFloat_FromDouble(self->getLinearDamping()); +} + +int KX_GameObject::pyattr_set_linearDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + float val = PyFloat_AsDouble(value); + self->setLinearDamping(val); + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_GameObject::pyattr_get_angularDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + return PyFloat_FromDouble(self->getAngularDamping()); +} + +int KX_GameObject::pyattr_set_angularDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + float val = PyFloat_AsDouble(value); + self->setAngularDamping(val); + return PY_SET_ATTR_SUCCESS; +} + PyObject *KX_GameObject::pyattr_get_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { @@ -2781,7 +3042,9 @@ PyObject *KX_GameObject::pyattr_get_meshes(void *self_v, const KX_PYATTRIBUTE_DE PyObject *KX_GameObject::pyattr_get_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 4, mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_OBJECT_COLOR); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 4, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_OBJECT_COLOR); #else KX_GameObject* self = static_cast<KX_GameObject*>(self_v); return PyObjectFrom(self->GetObjectColor()); @@ -3003,6 +3266,18 @@ PyObject *KX_GameObject::PySetAngularVelocity(PyObject *args) return NULL; } +PyObject *KX_GameObject::PySetDamping(PyObject *args) +{ + float linear; + float angular; + + if (!PyArg_ParseTuple(args,"ff|i:setDamping", &linear, &angular)) + return NULL; + + setDamping(linear, angular); + Py_RETURN_NONE; +} + PyObject *KX_GameObject::PySetVisible(PyObject *args) { int visible, recursive = 0; @@ -3147,10 +3422,16 @@ PyObject *KX_GameObject::PyApplyImpulse(PyObject *args) -PyObject *KX_GameObject::PySuspendDynamics() +PyObject *KX_GameObject::PySuspendDynamics(PyObject *args) { + bool ghost = false; + + if (!PyArg_ParseTuple(args, "|b", &ghost)) + return NULL; + if (GetPhysicsController()) - GetPhysicsController()->SuspendDynamics(); + GetPhysicsController()->SuspendDynamics(ghost); + Py_RETURN_NONE; } @@ -3158,7 +3439,8 @@ PyObject *KX_GameObject::PySuspendDynamics() PyObject *KX_GameObject::PyRestoreDynamics() { - if (GetPhysicsController()) + // Child objects must be static, so we block changing to dynamic + if (GetPhysicsController() && !GetParent()) GetPhysicsController()->RestoreDynamics(); Py_RETURN_NONE; } @@ -3200,12 +3482,12 @@ PyObject *KX_GameObject::PyGetAxisVect(PyObject *value) PyObject *KX_GameObject::PyGetPhysicsId() { PHY_IPhysicsController* ctrl = GetPhysicsController(); - uint_ptr physid=0; + unsigned long long physid = 0; if (ctrl) { - physid= (uint_ptr)ctrl; + physid = (unsigned long long)ctrl; } - return PyLong_FromLong((long)physid); + return PyLong_FromUnsignedLongLong(physid); } PyObject *KX_GameObject::PyGetPropertyNames() @@ -3648,7 +3930,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, stopAction, "stopAction(layer=0)\n" "Stop playing the action on the given layer\n") { - short layer=0; + short layer = 0; if (!PyArg_ParseTuple(args, "|h:stopAction", &layer)) return NULL; @@ -3664,7 +3946,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, getActionFrame, "getActionFrame(layer=0)\n" "Gets the current frame of the action playing in the supplied layer\n") { - short layer=0; + short layer = 0; if (!PyArg_ParseTuple(args, "|h:getActionFrame", &layer)) return NULL; @@ -3674,11 +3956,25 @@ KX_PYMETHODDEF_DOC(KX_GameObject, getActionFrame, return PyFloat_FromDouble(GetActionFrame(layer)); } +KX_PYMETHODDEF_DOC(KX_GameObject, getActionName, + "getActionName(layer=0)\n" + "Gets the name of the current action playing in the supplied layer\n") +{ + short layer = 0; + + if (!PyArg_ParseTuple(args, "|h:getActionName", &layer)) + return NULL; + + layer_check(layer, "getActionName"); + + return PyUnicode_FromString(GetActionName(layer)); +} + KX_PYMETHODDEF_DOC(KX_GameObject, setActionFrame, "setActionFrame(frame, layer=0)\n" "Set the current frame of the action playing in the supplied layer\n") { - short layer=0; + short layer = 0; float frame; if (!PyArg_ParseTuple(args, "f|h:setActionFrame", &frame, &layer)) @@ -3695,7 +3991,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, isPlayingAction, "isPlayingAction(layer=0)\n" "Checks to see if there is an action playing in the given layer\n") { - short layer=0; + short layer = 0; if (!PyArg_ParseTuple(args, "|h:isPlayingAction", &layer)) return NULL; @@ -3793,11 +4089,11 @@ bool ConvertPythonToGameObject(PyObject *value, KX_GameObject **object, bool py_ } } - if ( PyObject_TypeCheck(value, &KX_GameObject::Type) || - PyObject_TypeCheck(value, &KX_LightObject::Type) || - PyObject_TypeCheck(value, &KX_Camera::Type) || - PyObject_TypeCheck(value, &KX_FontObject::Type) || - PyObject_TypeCheck(value, &KX_NavMeshObject::Type)) + if (PyObject_TypeCheck(value, &KX_GameObject::Type) || + PyObject_TypeCheck(value, &KX_LightObject::Type) || + PyObject_TypeCheck(value, &KX_Camera::Type) || + PyObject_TypeCheck(value, &KX_FontObject::Type) || + PyObject_TypeCheck(value, &KX_NavMeshObject::Type)) { *object = static_cast<KX_GameObject*>BGE_PROXY_REF(value); diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index d4fa4851696..c10802a83b2 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -40,7 +40,7 @@ #include <stddef.h> -#include "ListValue.h" +#include "EXP_ListValue.h" #include "SCA_IObject.h" #include "SG_Node.h" #include "MT_Transform.h" @@ -49,6 +49,7 @@ #include "CTR_HashedPtr.h" #include "KX_Scene.h" #include "KX_KetsjiEngine.h" /* for m_anim_framerate */ +#include "DNA_constraint_types.h" /* for constraint replication */ #include "DNA_object_types.h" #include "SCA_LogicManager.h" /* for ConvertPythonToGameObject to search object names */ @@ -88,18 +89,19 @@ protected: int m_layer; std::vector<RAS_MeshObject*> m_meshes; std::vector<RAS_MeshObject*> m_lodmeshes; + int m_currentLodLevel; + short m_previousLodLevel; SG_QList m_meshSlots; // head of mesh slots of this struct Object* m_pBlenderObject; struct Object* m_pBlenderGroupObject; - bool m_bSuspendDynamics; bool m_bUseObjectColor; bool m_bIsNegativeScaling; MT_Vector4 m_objectColor; // Bit fields for user control over physics collisions - short m_userCollisionGroup; - short m_userCollisionMask; + unsigned short m_userCollisionGroup; + unsigned short m_userCollisionMask; // visible = user setting // culled = while rendering, depending on camera @@ -116,6 +118,7 @@ protected: SG_Node* m_pSGNode; MT_CmMatrix4x4 m_OpenGL_4x4Matrix; + std::vector<bRigidBodyJointConstraint*> m_constraints; KX_ObstacleSimulation* m_pObstacleSimulation; @@ -192,6 +195,14 @@ public: void UpdateBlenderObjectMatrix(Object* blendobj=NULL); + /** + * Used for constraint replication for group instances. + * The list of constraints is filled during data conversion. + */ + void AddConstraint(bRigidBodyJointConstraint *cons); + std::vector<bRigidBodyJointConstraint*> GetConstraints(); + void ClearConstraints(); + /** * Get a pointer to the game object that is the parent of * this object. Or NULL if there is no parent. The returned @@ -266,6 +277,11 @@ public: float GetActionFrame(short layer); /** + * Gets the name of the current action + */ + const char *GetActionName(short layer); + + /** * Sets the current frame of an action */ void SetActionFrame(short layer, float frame); @@ -291,6 +307,11 @@ public: void StopAction(short layer); /** + * Remove playing tagged actions. + */ + void RemoveTaggedActions(); + + /** * Check if an action has finished playing */ bool IsActionDone(short layer); @@ -506,8 +527,17 @@ public: */ void ActivateGraphicController(bool recurse); - void SetUserCollisionGroup(short filter); - void SetUserCollisionMask(short mask); + /** Set the object's collison group + * \param filter The group bitfield + */ + void SetUserCollisionGroup(unsigned short filter); + + /** Set the object's collison mask + * \param filter The mask bitfield + */ + void SetUserCollisionMask(unsigned short mask); + unsigned short GetUserCollisionGroup(); + unsigned short GetUserCollisionMask(); /** * Extra broadphase check for user controllable collisions */ @@ -607,6 +637,8 @@ public: return m_bDyna; } + bool IsDynamicsSuspended() const; + /** * Should we record animation for this object? */ @@ -684,6 +716,12 @@ public: bool local ); + virtual float getLinearDamping() const; + virtual float getAngularDamping() const; + virtual void setLinearDamping(float damping); + virtual void setAngularDamping(float damping); + virtual void setDamping(float linear, float angular); + /** * Update the physics object transform based upon the current SG_Node * position. @@ -852,10 +890,10 @@ public: /** * Was this object culled? */ - bool + inline bool GetCulled( void - ); + ) { return m_bCulled; } /** * Set culled flag of this object @@ -886,7 +924,7 @@ public: * Change the layer of the object (when it is added in another layer * than the original layer) */ - void + virtual void SetLayer( int l ); @@ -913,7 +951,7 @@ public: void RegisterCollisionCallbacks(); void UnregisterCollisionCallbacks(); - void RunCollisionCallbacks(KX_GameObject *collider); + void RunCollisionCallbacks(KX_GameObject *collider, const MT_Vector3 &point, const MT_Vector3 &normal); /** * Stop making progress */ @@ -965,6 +1003,7 @@ public: KX_PYMETHOD_VARARGS(KX_GameObject,GetAngularVelocity); KX_PYMETHOD_VARARGS(KX_GameObject,SetAngularVelocity); KX_PYMETHOD_VARARGS(KX_GameObject,GetVelocity); + KX_PYMETHOD_VARARGS(KX_GameObject,SetDamping); KX_PYMETHOD_NOARGS(KX_GameObject,GetReactionForce); @@ -976,7 +1015,7 @@ public: 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_VARARGS(KX_GameObject,SuspendDynamics); KX_PYMETHOD_NOARGS(KX_GameObject,RestoreDynamics); KX_PYMETHOD_NOARGS(KX_GameObject,EnableRigidBody); KX_PYMETHOD_NOARGS(KX_GameObject,DisableRigidBody); @@ -1003,6 +1042,7 @@ public: KX_PYMETHOD_DOC(KX_GameObject, playAction); KX_PYMETHOD_DOC(KX_GameObject, stopAction); KX_PYMETHOD_DOC(KX_GameObject, getActionFrame); + KX_PYMETHOD_DOC(KX_GameObject, getActionName); KX_PYMETHOD_DOC(KX_GameObject, setActionFrame); KX_PYMETHOD_DOC(KX_GameObject, isPlayingAction); @@ -1020,10 +1060,15 @@ public: static PyObject* pyattr_get_life(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_is_suspend_dynamics(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_ang_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_ang_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_ang_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_ang_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_record_animation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); @@ -1066,10 +1111,18 @@ public: static int pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_collisionCallbacks(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_collisionGroup(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_collisionGroup(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_collisionMask(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_collisionMask(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_linearDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_linearDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_angularDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_angularDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); /* Experimental! */ static PyObject* pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); diff --git a/source/gameengine/Ketsji/KX_ISceneConverter.h b/source/gameengine/Ketsji/KX_ISceneConverter.h index a07d4b2195c..2e1c16c6e32 100644 --- a/source/gameengine/Ketsji/KX_ISceneConverter.h +++ b/source/gameengine/Ketsji/KX_ISceneConverter.h @@ -33,7 +33,7 @@ #define __KX_ISCENECONVERTER_H__ #include "STR_String.h" -#include "KX_Python.h" +#include "EXP_Python.h" #ifdef WITH_CXX_GUARDEDALLOC #include "MEM_guardedalloc.h" @@ -45,8 +45,8 @@ class KX_ISceneConverter { public: - KX_ISceneConverter() :addInitFromFrame(false) {}//this addInitFromFrame is a back hack, todo remove - virtual ~KX_ISceneConverter () {}; + KX_ISceneConverter() {} + virtual ~KX_ISceneConverter () {} /* * scenename: name of the scene to be converted, @@ -59,7 +59,7 @@ public: class RAS_IRasterizer* rendertools, class RAS_ICanvas* canvas, bool libloading=false)=0; - + virtual void RemoveScene(class KX_Scene *scene)=0; // handle any pending merges from asynchronous loads @@ -69,11 +69,9 @@ public: virtual void SetNewFileName(const STR_String& filename) = 0; virtual bool TryAndLoadNewFile() = 0; - bool addInitFromFrame;//rcruiz virtual void ResetPhysicsObjectsAnimationIpo(bool clearIpo) = 0; - ///this generates ipo curves for position, rotation, allowing to use game physics in animation virtual void WritePhysicsObjectToAnimationIpo(int frameNumber) = 0; virtual void TestHandlesPhysicsObjectToAnimationIpo() = 0; diff --git a/source/gameengine/Ketsji/KX_IpoActuator.cpp b/source/gameengine/Ketsji/KX_IpoActuator.cpp index 1597d7f8809..ec7a4146b7d 100644 --- a/source/gameengine/Ketsji/KX_IpoActuator.cpp +++ b/source/gameengine/Ketsji/KX_IpoActuator.cpp @@ -36,7 +36,7 @@ #include "KX_IpoActuator.h" #include "KX_GameObject.h" -#include "FloatValue.h" +#include "EXP_FloatValue.h" #include "KX_KetsjiEngine.h" diff --git a/source/gameengine/Ketsji/KX_IpoConvert.cpp b/source/gameengine/Ketsji/KX_IpoConvert.cpp index 57130bf57b2..7b00760ee7b 100644 --- a/source/gameengine/Ketsji/KX_IpoConvert.cpp +++ b/source/gameengine/Ketsji/KX_IpoConvert.cpp @@ -269,52 +269,80 @@ SG_Controller *BL_CreateCameraIPO(struct bAction *action, KX_GameObject* camera return ipocontr; } -void BL_ConvertWorldIpos(struct World* blenderworld,KX_BlenderSceneConverter *converter) -{ - - if (blenderworld->adt) { - KX_WorldIpoController* ipocontr = new KX_WorldIpoController(); - -// Erwin, hook up the world ipo controller here -// Gino: hook it up to what ? -// is there a userinterface element for that ? -// for now, we have some new python hooks to access the data, for a work-around - - ipocontr->m_mist_start = blenderworld->miststa; - ipocontr->m_mist_dist = blenderworld->mistdist; - ipocontr->m_mist_rgb[0] = blenderworld->horr; - ipocontr->m_mist_rgb[1] = blenderworld->horg; - ipocontr->m_mist_rgb[2] = blenderworld->horb; +SG_Controller * BL_CreateWorldIPO( bAction *action, struct World *blenderworld, KX_BlenderSceneConverter *converter ) +{ + KX_WorldIpoController *ipocontr = NULL; - BL_InterpolatorList *adtList= GetAdtList(blenderworld->adt->action, converter); + if (blenderworld) { + BL_InterpolatorList *adtList = GetAdtList(action, converter); - // For each active channel in the adtList add an - // interpolator to the game object. - + // For each active channel in the adtList add an interpolator to the game object. KX_IInterpolator *interpolator; KX_IScalarInterpolator *interp; - + + for (int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("ambient_color", i))) { + if (!ipocontr) { + ipocontr = new KX_WorldIpoController(); + } + interpolator = new KX_ScalarInterpolator(&ipocontr->m_ambi_rgb[i], interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyAmbientColor(true); + } + } + for (int i=0; i<3; i++) { if ((interp = adtList->GetScalarInterpolator("horizon_color", i))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_mist_rgb[i], interp); + if (!ipocontr) { + ipocontr = new KX_WorldIpoController(); + } + interpolator = new KX_ScalarInterpolator(&ipocontr->m_hori_rgb[i], interp); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyMistColor(true); + ipocontr->SetModifyHorizonColor(true); } } - if ((interp = adtList->GetScalarInterpolator("mist.depth", 0))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_mist_dist, interp); + if ((interp = adtList->GetScalarInterpolator("mist_settings.start", 0))) { + if (!ipocontr) { + ipocontr = new KX_WorldIpoController(); + } + interpolator = new KX_ScalarInterpolator(&ipocontr->m_mist_start, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyMistStart(true); + } + + if ((interp = adtList->GetScalarInterpolator("mist_settings.depth", 0))) { + if (!ipocontr) { + ipocontr = new KX_WorldIpoController(); + } + interpolator = new KX_ScalarInterpolator(&ipocontr->m_mist_dist, interp); ipocontr->AddInterpolator(interpolator); ipocontr->SetModifyMistDist(true); } - if ((interp = adtList->GetScalarInterpolator("mist.start", 0))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_mist_start, interp); + if ((interp = adtList->GetScalarInterpolator("mist_settings.intensity", 0))) { + if (!ipocontr) { + ipocontr = new KX_WorldIpoController(); + } + interpolator = new KX_ScalarInterpolator(&ipocontr->m_mist_intensity, interp); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyMistStart(true); + ipocontr->SetModifyMistIntensity(true); + } + + if (ipocontr) { + ipocontr->m_mist_start = blenderworld->miststa; + ipocontr->m_mist_dist = blenderworld->mistdist; + ipocontr->m_mist_intensity = blenderworld->misi; + ipocontr->m_hori_rgb[0] = blenderworld->horr; + ipocontr->m_hori_rgb[1] = blenderworld->horg; + ipocontr->m_hori_rgb[2] = blenderworld->horb; + ipocontr->m_ambi_rgb[0] = blenderworld->ambr; + ipocontr->m_ambi_rgb[1] = blenderworld->ambg; + ipocontr->m_ambi_rgb[2] = blenderworld->ambb; } } + return ipocontr; } SG_Controller *BL_CreateMaterialIpo( @@ -368,7 +396,7 @@ SG_Controller *BL_CreateMaterialIpo( ipocontr->AddInterpolator(interpolator); } - if ((sinterp = adtList->GetScalarInterpolator("specularity", 0))) { + if ((sinterp = adtList->GetScalarInterpolator("specular_intensity", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(matname_hash); } @@ -376,7 +404,7 @@ SG_Controller *BL_CreateMaterialIpo( ipocontr->AddInterpolator(interpolator); } - if ((sinterp = adtList->GetScalarInterpolator("diffuse_reflection", 0))) { + if ((sinterp = adtList->GetScalarInterpolator("diffuse_intensity", 0))) { if (!ipocontr) { ipocontr = new KX_MaterialIpoController(matname_hash); } diff --git a/source/gameengine/Ketsji/KX_IpoConvert.h b/source/gameengine/Ketsji/KX_IpoConvert.h index a653e4e110b..6db43552811 100644 --- a/source/gameengine/Ketsji/KX_IpoConvert.h +++ b/source/gameengine/Ketsji/KX_IpoConvert.h @@ -50,7 +50,8 @@ SG_Controller *BL_CreateLampIPO(bAction *action, KX_GameObject* lightobj, KX_BlenderSceneConverter *converter); -void BL_ConvertWorldIpos(struct World* blenderworld, +SG_Controller *BL_CreateWorldIPO(bAction *action, + struct World *blenderworld, KX_BlenderSceneConverter *converter); SG_Controller *BL_CreateCameraIPO(bAction *action, diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 14772cda113..72c512589a4 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -41,11 +41,11 @@ #include "KX_KetsjiEngine.h" -#include "ListValue.h" -#include "IntValue.h" -#include "VectorValue.h" -#include "BoolValue.h" -#include "FloatValue.h" +#include "EXP_ListValue.h" +#include "EXP_IntValue.h" +#include "EXP_VectorValue.h" +#include "EXP_BoolValue.h" +#include "EXP_FloatValue.h" #include "RAS_BucketManager.h" #include "RAS_Rect.h" @@ -62,11 +62,6 @@ #include "KX_PyConstraintBinding.h" #include "PHY_IPhysicsEnvironment.h" -#ifdef WITH_AUDASPACE -# include "AUD_C-API.h" -# include "AUD_I3DDevice.h" -#endif - #include "NG_NetworkScene.h" #include "NG_NetworkDeviceInterface.h" @@ -80,9 +75,6 @@ #include "KX_NavMeshObject.h" -// If define: little test for Nzc: guarded drawing. If the canvas is -// not valid, skip rendering this frame. -//#define NZC_GUARDED_OUTPUT #define DEFAULT_LOGIC_TIC_RATE 60.0 //#define DEFAULT_PHYSICS_TIC_RATE 60.0 @@ -140,6 +132,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_frameTime(0.f), m_clockTime(0.f), m_previousClockTime(0.f), + m_previousAnimTime(0.f), m_exitcode(KX_EXIT_REQUEST_NO_REQUEST), @@ -314,10 +307,11 @@ void KX_KetsjiEngine::RenderDome() // for each scene, call the proceed functions { scene = *sceneit; + KX_SetActiveScene(scene); KX_Camera* cam = scene->GetActiveCamera(); // pass the scene's worldsettings to the rasterizer - SetWorldSettings(scene->GetWorldInfo()); + scene->GetWorldInfo()->UpdateWorldSettings(); // shadow buffers if (i == 0) { @@ -391,8 +385,10 @@ void KX_KetsjiEngine::RenderDome() ); } m_dome->Draw(); + // Draw Callback for the last scene #ifdef WITH_PYTHON + PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); scene->RunDrawingCallbacks(scene->GetPostDrawCB()); #endif EndFrame(); @@ -477,7 +473,7 @@ void KX_KetsjiEngine::ClearFrame() if (doclear) { KX_Scene* firstscene = *m_scenes.begin(); - SetBackGround(firstscene->GetWorldInfo()); + firstscene->GetWorldInfo()->UpdateBackGround(); m_canvas->SetViewPort(clearvp.GetLeft(), clearvp.GetBottom(), clearvp.GetRight(), clearvp.GetTop()); @@ -686,6 +682,9 @@ bool KX_KetsjiEngine::NextFrame() SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE); scene->UpdateParents(m_frameTime); + // update levels of detail + scene->UpdateObjectLods(); + m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_PHYSICS2); scene->GetPhysicsEnvironment()->BeginFrame(); @@ -730,64 +729,6 @@ bool KX_KetsjiEngine::NextFrame() frames--; } - bool bUseAsyncLogicBricks= false;//true; - - if (bUseAsyncLogicBricks) - { - // Logic update sub frame: this will let some logic bricks run at the - // full frame rate. - for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit) - // for each scene, call the proceed functions - { - KX_Scene* scene = *sceneit; - - if (!scene->IsSuspended()) - { - // if the scene was suspended recalcutlate the delta tu "curtime" - m_suspendedtime = scene->getSuspendedTime(); - if (scene->getSuspendedTime()!=0.0) - scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime()); - m_suspendeddelta = scene->getSuspendedDelta(); - - // set Python hooks for each scene -#ifdef WITH_PYTHON - PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); -#endif - KX_SetActiveScene(scene); - - m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_PHYSICS1); - scene->UpdateParents(m_clockTime); - - // Perform physics calculations on the scene. This can involve - // many iterations of the physics solver. - m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); - scene->GetPhysicsEnvironment()->ProceedDeltaTime(m_clockTime,timestep,timestep); - // Update scenegraph after physics step. This maps physics calculations - // into node positions. - m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_PHYSICS2); - scene->UpdateParents(m_clockTime); - - // Do some cleanup work for this logic frame - m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); - scene->LogicUpdateFrame(m_clockTime, false); - - // Actuators can affect the scenegraph - m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_ACTUATOR); - scene->UpdateParents(m_clockTime); - - scene->setSuspendedTime(0.0); - } // suspended - else - if (scene->getSuspendedTime()==0.0) - scene->setSuspendedTime(m_clockTime); - - m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true); - } - } - // Start logging time spend outside main loop m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true); @@ -855,7 +796,7 @@ void KX_KetsjiEngine::Render() KX_Scene* scene = *sceneit; KX_Camera* cam = scene->GetActiveCamera(); // pass the scene's worldsettings to the rasterizer - SetWorldSettings(scene->GetWorldInfo()); + scene->GetWorldInfo()->UpdateWorldSettings(); // this is now done incrementatlly in KX_Scene::CalculateVisibleMeshes //scene->UpdateMeshTransformations(); @@ -912,7 +853,7 @@ void KX_KetsjiEngine::Render() KX_Camera* cam = scene->GetActiveCamera(); // pass the scene's worldsettings to the rasterizer - SetWorldSettings(scene->GetWorldInfo()); + scene->GetWorldInfo()->UpdateWorldSettings(); if (scene->IsClearingZBuffer()) m_rasterizer->ClearDepthBuffer(); @@ -992,54 +933,6 @@ const STR_String& KX_KetsjiEngine::GetExitString() return m_exitstring; } - -void KX_KetsjiEngine::SetBackGround(KX_WorldInfo* wi) -{ - if (wi->hasWorld()) - { - if (m_rasterizer->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) - { - m_rasterizer->SetBackColor( - wi->getBackColorRed(), - wi->getBackColorGreen(), - wi->getBackColorBlue(), - 0.0 - ); - } - } -} - - - -void KX_KetsjiEngine::SetWorldSettings(KX_WorldInfo* wi) -{ - if (wi->hasWorld()) - { - // ... - m_rasterizer->SetAmbientColor( - wi->getAmbientColorRed(), - wi->getAmbientColorGreen(), - wi->getAmbientColorBlue() - ); - - if (m_rasterizer->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID) - { - if (wi->hasMist()) - { - m_rasterizer->SetFog( - wi->getMistStart(), - wi->getMistDistance(), - wi->getMistColorRed(), - wi->getMistColorGreen(), - wi->getMistColorBlue() - ); - } - } - } -} - - - void KX_KetsjiEngine::EnableCameraOverride(const STR_String& forscene) { m_overrideCam = true; @@ -1124,6 +1017,23 @@ void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect } } +void KX_KetsjiEngine::UpdateAnimations(KX_Scene *scene) +{ + // Handle the animations independently of the logic time step + if (GetRestrictAnimationFPS()) { + double anim_timestep = 1.0 / KX_GetActiveScene()->GetAnimationFPS(); + if (m_frameTime - m_previousAnimTime > anim_timestep || m_frameTime == m_previousAnimTime) { + // Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep) + // printf("Anim fps: %f\n", 1.0/(m_frameTime - m_previousAnimTime)); + m_previousAnimTime = m_frameTime; + for (KX_SceneList::iterator sceneit = m_scenes.begin(); sceneit != m_scenes.end(); ++sceneit) + (*sceneit)->UpdateAnimations(m_frameTime); + } + } + else + scene->UpdateAnimations(m_frameTime); +} + void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) { CListValue *lightlist = scene->GetLightList(); @@ -1155,14 +1065,13 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) raslight->BindShadowBuffer(m_canvas, cam, camtrans); /* update scene */ - m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); scene->CalculateVisibleMeshes(m_rasterizer, cam, raslight->GetShadowLayer()); m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); - scene->UpdateAnimations(GetFrameTime()); - + SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); + UpdateAnimations(scene); m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); - + SG_SetActiveStage(SG_STAGE_RENDER); /* render */ m_rasterizer->ClearDepthBuffer(); @@ -1187,6 +1096,13 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) if (!cam) return; + + KX_SetActiveScene(scene); + +#ifdef WITH_PYTHON + scene->RunDrawingCallbacks(scene->GetPreDrawSetupCB()); +#endif + GetSceneViewport(scene, cam, area, viewport); // store the computed viewport in the scene @@ -1238,6 +1154,8 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) nearfrust, farfrust, cam->GetSensorFit(), + cam->GetShiftHorizontal(), + cam->GetShiftVertical(), frustum ); if (!cam->GetViewport()) { @@ -1258,6 +1176,8 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) cam->GetSensorWidth(), cam->GetSensorHeight(), cam->GetSensorFit(), + cam->GetShiftHorizontal(), + cam->GetShiftVertical(), nearfrust, farfrust, frustum @@ -1297,13 +1217,13 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); - - scene->UpdateAnimations(GetFrameTime()); + UpdateAnimations(scene); m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_RENDER); #ifdef WITH_PYTHON + PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); // Run any pre-drawing python callbacks scene->RunDrawingCallbacks(scene->GetPreDrawCB()); #endif @@ -1322,13 +1242,20 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) */ void KX_KetsjiEngine::PostRenderScene(KX_Scene* scene) { + KX_SetActiveScene(scene); + // We need to first make sure our viewport is correct (enabling multiple viewports can mess this up) m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight()); - m_rasterizer->FlushDebugShapes(); + m_rasterizer->FlushDebugShapes(scene); scene->Render2DFilters(m_canvas); + #ifdef WITH_PYTHON + PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); scene->RunDrawingCallbacks(scene->GetPostDrawCB()); + + // Python draw callback can also call debug draw functions, so we have to clear debug shapes. + m_rasterizer->FlushDebugShapes(scene); #endif } @@ -1734,18 +1661,17 @@ void KX_KetsjiEngine::AddScheduledScenes() bool KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene) { - // Don't allow replacement if the new scene doesn't exists. - // Allows smarter game design (used to have no check here). - // Note that it creates a small backward compatbility issue - // for a game that did a replace followed by a lib load with the - // new scene in the lib => it won't work anymore, the lib - // must be loaded before doing the replace. - if (m_sceneconverter->GetBlenderSceneForName(newscene) != NULL) - { - m_replace_scenes.push_back(std::make_pair(oldscene,newscene)); - return true; - } - return false; + // Don't allow replacement if the new scene doesn't exists. + // Allows smarter game design (used to have no check here). + // Note that it creates a small backward compatbility issue + // for a game that did a replace followed by a lib load with the + // new scene in the lib => it won't work anymore, the lib + // must be loaded before doing the replace. + if (m_sceneconverter->GetBlenderSceneForName(newscene) != NULL) { + m_replace_scenes.push_back(std::make_pair(oldscene,newscene)); + return true; + } + return false; } // replace scene is not the same as removing and adding because the @@ -1767,21 +1693,20 @@ void KX_KetsjiEngine::ReplaceScheduledScenes() int i=0; /* Scenes are not supposed to be included twice... I think */ KX_SceneList::iterator sceneit; - for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++) - { - KX_Scene* scene = *sceneit; - if (scene->GetName() == oldscenename) - { - // avoid crash if the new scene doesn't exist, just do nothing - Scene *blScene = m_sceneconverter->GetBlenderSceneForName(newscenename); - if (blScene) { - m_sceneconverter->RemoveScene(scene); - KX_Scene* tmpscene = CreateScene(blScene); - m_scenes[i]=tmpscene; - PostProcessScene(tmpscene); - } else { - printf("warning: scene %s could not be found, not replaced!\n",newscenename.ReadPtr()); - } + for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++) { + KX_Scene* scene = *sceneit; + if (scene->GetName() == oldscenename) { + // avoid crash if the new scene doesn't exist, just do nothing + Scene *blScene = m_sceneconverter->GetBlenderSceneForName(newscenename); + if (blScene) { + m_sceneconverter->RemoveScene(scene); + KX_Scene* tmpscene = CreateScene(blScene); + m_scenes[i]=tmpscene; + PostProcessScene(tmpscene); + } + else { + printf("warning: scene %s could not be found, not replaced!\n",newscenename.ReadPtr()); + } } i++; } @@ -1825,6 +1750,16 @@ void KX_KetsjiEngine::SetAnimRecordMode(bool animation_record, int startFrame) m_currentFrame = startFrame; } +int KX_KetsjiEngine::getAnimRecordFrame() const +{ + return m_currentFrame; +} + +void KX_KetsjiEngine::setAnimRecordFrame(int framenr) +{ + m_currentFrame = framenr; +} + bool KX_KetsjiEngine::GetUseFixedTime(void) const { return m_bFixedTime; diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index 2b80e3bd69a..04e09c8db15 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -38,7 +38,7 @@ #include "STR_String.h" #include "KX_ISystem.h" #include "KX_Scene.h" -#include "KX_Python.h" +#include "EXP_Python.h" #include "KX_WorldInfo.h" #include <vector> @@ -111,6 +111,7 @@ private: double m_frameTime;//discrete timestamp of the 'game logic frame' double m_clockTime;//current time double m_previousClockTime;//previous clock time + double m_previousAnimTime; //the last time animations were updated double m_remainingTime; static int m_maxLogicFrame; /* maximum number of consecutive logic frame */ @@ -204,14 +205,12 @@ private: void PostRenderScene(KX_Scene* scene); void RenderDebugProperties(); void RenderShadowBuffers(KX_Scene *scene); - void SetBackGround(KX_WorldInfo* worldinfo); public: KX_KetsjiEngine(class KX_ISystem* system); virtual ~KX_KetsjiEngine(); // set the devices and stuff. the client must take care of creating these - void SetWorldSettings(KX_WorldInfo* worldinfo); void SetKeyboardDevice(SCA_IInputDevice* keyboarddevice); void SetMouseDevice(SCA_IInputDevice* mousedevice); void SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice); @@ -226,6 +225,9 @@ public: KX_ISceneConverter* GetSceneConverter() { return m_sceneconverter; } void SetAnimRecordMode(bool animation_record, int startFrame); + int getAnimRecordFrame() const; + void setAnimRecordFrame(int framenr); + RAS_IRasterizer* GetRasterizer() { return m_rasterizer; } RAS_ICanvas* GetCanvas() { return m_canvas; } SCA_IInputDevice* GetKeyboardDevice() { return m_keyboarddevice; } @@ -258,7 +260,7 @@ public: void ConvertAndAddScene(const STR_String& scenename,bool overlay); void RemoveScene(const STR_String& scenename); - bool ReplaceScene(const STR_String& oldscene,const STR_String& newscene); + bool ReplaceScene(const STR_String& oldscene,const STR_String& newscene); void SuspendScene(const STR_String& scenename); void ResumeScene(const STR_String& scenename); @@ -273,6 +275,9 @@ public: void SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat); void SetCameraOverrideClipping(float near, float far); void SetCameraOverrideLens(float lens); + + // Update animations for object in this scene + void UpdateAnimations(KX_Scene *scene); /** * Sets display of all frames. diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp index 33cfec57fc0..0dec5715588 100644 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ b/source/gameengine/Ketsji/KX_Light.cpp @@ -108,6 +108,7 @@ void KX_LightObject::UpdateScene(KX_Scene *kxscene) void KX_LightObject::SetLayer(int layer) { + KX_GameObject::SetLayer(layer); m_lightobj->m_layer = layer; } @@ -166,27 +167,31 @@ PyAttributeDef KX_LightObject::Attributes[] = { PyObject *KX_LightObject::pyattr_get_layer(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - KX_LightObject* self = static_cast<KX_LightObject*>(self_v); + KX_LightObject *self = static_cast<KX_LightObject *>(self_v); return PyLong_FromLong(self->m_lightobj->m_layer); } int KX_LightObject::pyattr_set_layer(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_LightObject* self = static_cast<KX_LightObject*>(self_v); + KX_LightObject *self = static_cast<KX_LightObject *>(self_v); + int layer = PyLong_AsLong(value); - if (PyLong_Check(value)) { - int val = PyLong_AsLong(value); - if (val < 1) - val = 1; - else if (val > 20) - val = 20; + if (layer == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } - self->m_lightobj->m_layer = val; - return PY_SET_ATTR_SUCCESS; + if (layer < 1) { + PyErr_Format(PyExc_TypeError, "expected an integer greater than 1 for attribute \"%s\"", attrdef->m_name); + return PY_SET_ATTR_FAIL; + } + else if(layer > MAX_LIGHT_LAYERS) { + PyErr_Format(PyExc_TypeError, "expected an integer less than %i for attribute \"%s\"", MAX_LIGHT_LAYERS, attrdef->m_name); + return PY_SET_ATTR_FAIL; } - PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); - return PY_SET_ATTR_FAIL; + self->SetLayer(layer); + return PY_SET_ATTR_SUCCESS; } PyObject *KX_LightObject::pyattr_get_energy(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h index 503ed7411e9..3a58584223d 100644 --- a/source/gameengine/Ketsji/KX_Light.h +++ b/source/gameengine/Ketsji/KX_Light.h @@ -34,6 +34,8 @@ #include "KX_GameObject.h" +#define MAX_LIGHT_LAYERS ((1 << 20) - 1) + struct GPULamp; struct Scene; struct Base; @@ -58,7 +60,7 @@ public: RAS_ILightObject* GetLightData() { return m_lightobj;} void UpdateScene(class KX_Scene *kxscene); - void SetLayer(int layer); + virtual void SetLayer(int layer); virtual int GetGameObjectType() { return OBJ_LIGHT; } diff --git a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp index a9617aa47b8..1faf8f17d54 100644 --- a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp +++ b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp @@ -32,21 +32,6 @@ bool KX_MaterialIpoController::Update(double currentTime) { if (m_modified) { - m_rgba[0]=0; - m_rgba[1]=0; - m_rgba[2]=0; - m_rgba[3]=0; - - m_specrgb[0] =0; - m_specrgb[1] =0; - m_specrgb[2] =0; - m_hard =0; - m_spec=0; - m_ref=0; - m_emit=0; - m_alpha = 0; - - T_InterpolatorList::iterator i; for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { (*i)->Execute(m_ipotime); diff --git a/source/gameengine/Ketsji/KX_MeshProxy.cpp b/source/gameengine/Ketsji/KX_MeshProxy.cpp index a6f2f728674..c98766c9c81 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.cpp +++ b/source/gameengine/Ketsji/KX_MeshProxy.cpp @@ -43,7 +43,7 @@ #include "KX_PyMath.h" -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" PyTypeObject KX_MeshProxy::Type = { PyVarObject_HEAD_INIT(NULL, 0) diff --git a/source/gameengine/Ketsji/KX_MouseActuator.cpp b/source/gameengine/Ketsji/KX_MouseActuator.cpp index aae5d18189a..154ad1da3a1 100644 --- a/source/gameengine/Ketsji/KX_MouseActuator.cpp +++ b/source/gameengine/Ketsji/KX_MouseActuator.cpp @@ -126,24 +126,33 @@ bool KX_MouseActuator::Update() float movement[2]; MT_Vector3 rotation; float setposition[2] = {0.0}; + float center_x = 0.5, center_y = 0.5; getMousePosition(position); movement[0] = position[0]; movement[1] = position[1]; + //preventing undesired drifting when resolution is odd + if ((m_canvas->GetWidth() % 2) != 0) { + center_x = ((m_canvas->GetWidth() - 1.0) / 2.0) / (m_canvas->GetWidth()); + } + if ((m_canvas->GetHeight() % 2) != 0) { + center_y = ((m_canvas->GetHeight() - 1.0) / 2.0) / (m_canvas->GetHeight()); + } + //preventing initial skipping. if ((m_oldposition[0] <= -0.9) && (m_oldposition[1] <= -0.9)) { if (m_reset_x) { - m_oldposition[0] = 0.5; + m_oldposition[0] = center_x; } else { m_oldposition[0] = position[0]; } if (m_reset_y) { - m_oldposition[1] = 0.5; + m_oldposition[1] = center_y; } else { m_oldposition[1] = position[1]; @@ -156,8 +165,8 @@ bool KX_MouseActuator::Update() if (m_use_axis_x) { if (m_reset_x) { - setposition[0] = 0.5; - movement[0] -= 0.5; + setposition[0] = center_x; + movement[0] -= center_x; } else { setposition[0] = position[0]; @@ -166,12 +175,10 @@ bool KX_MouseActuator::Update() movement[0] *= -1.0; - /* Don't apply the rotation when width resolution is odd (+ little movement) to - avoid undesired drifting or when we are under a certain threshold for mouse + /* Don't apply the rotation when we are under a certain threshold for mouse movement */ - if (!((m_canvas->GetWidth() % 2 != 0) && MT_abs(movement[0]) < 0.01) && - ((movement[0] > (m_threshold[0] / 10.0)) || + if (((movement[0] > (m_threshold[0] / 10.0)) || ((movement[0] * (-1.0)) > (m_threshold[0] / 10.0)))) { movement[0] *= m_sensitivity[0]; @@ -209,15 +216,15 @@ bool KX_MouseActuator::Update() } } else { - setposition[0] = 0.5; + setposition[0] = center_x; } //Calculating Y axis. if (m_use_axis_y) { if (m_reset_y) { - setposition[1] = 0.5; - movement[1] -= 0.5; + setposition[1] = center_y; + movement[1] -= center_y; } else { setposition[1] = position[1]; @@ -226,12 +233,10 @@ bool KX_MouseActuator::Update() movement[1] *= -1.0; - /* Don't apply the rotation when height resolution is odd (+ little movement) to - avoid undesired drifting or when we are under a certain threshold for mouse + /* Don't apply the rotation when we are under a certain threshold for mouse movement */ - if (!((m_canvas->GetHeight() % 2 != 0) && MT_abs(movement[1]) < 0.01) && - ((movement[1] > (m_threshold[1] / 10.0)) || + if (((movement[1] > (m_threshold[1] / 10.0)) || ((movement[1] * (-1.0)) > (m_threshold[1] / 10.0)))) { movement[1] *= m_sensitivity[1]; @@ -270,10 +275,13 @@ bool KX_MouseActuator::Update() } } else { - setposition[1] = 0.5; + setposition[1] = center_y; } - setMousePosition(setposition[0], setposition[1]); + // only trigger mouse event when it is necessary + if (m_oldposition[0] != position[0] || m_oldposition[1] != position[1]) { + setMousePosition(setposition[0], setposition[1]); + } m_oldposition[0] = position[0]; m_oldposition[1] = position[1]; @@ -311,7 +319,7 @@ void KX_MouseActuator::ProcessReplica() void KX_MouseActuator::getMousePosition(float* pos) { - MT_assert(!m_mouse); + MT_assert(m_mouse); const SCA_InputEvent & xevent = m_mouse->GetEventValue(SCA_IInputDevice::KX_MOUSEX); const SCA_InputEvent & yevent = m_mouse->GetEventValue(SCA_IInputDevice::KX_MOUSEY); @@ -329,7 +337,7 @@ void KX_MouseActuator::setMousePosition(float fx, float fy) m_canvas->SetMousePosition(x, y); } -#ifndef DISABLE_PYTHON +#ifdef WITH_PYTHON /* ------------------------------------------------------------------------- */ /* Python functions */ @@ -399,8 +407,8 @@ int KX_MouseActuator::pyattr_set_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF if (PyList_Size(value) != 2) return PY_SET_ATTR_FAIL; - item1 = PyList_GetItem(value, 0); - item2 = PyList_GetItem(value, 1); + item1 = PyList_GET_ITEM(value, 0); + item2 = PyList_GET_ITEM(value, 1); if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) { return PY_SET_ATTR_FAIL; @@ -430,8 +438,8 @@ int KX_MouseActuator::pyattr_set_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF if (PyList_Size(value) != 2) return PY_SET_ATTR_FAIL; - item1 = PyList_GetItem(value, 0); - item2 = PyList_GetItem(value, 1); + item1 = PyList_GET_ITEM(value, 0); + item2 = PyList_GET_ITEM(value, 1); if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) { return PY_SET_ATTR_FAIL; @@ -461,8 +469,8 @@ int KX_MouseActuator::pyattr_set_angle(void *self_v, const KX_PYATTRIBUTE_DEF *a if (PyList_Size(value) != 2) return PY_SET_ATTR_FAIL; - item1 = PyList_GetItem(value, 0); - item2 = PyList_GetItem(value, 1); + item1 = PyList_GET_ITEM(value, 0); + item2 = PyList_GET_ITEM(value, 1); if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) { return PY_SET_ATTR_FAIL; @@ -528,4 +536,4 @@ PyObject* KX_MouseActuator::PyReset() Py_RETURN_NONE; } -#endif +#endif /* WITH_PYTHON */ diff --git a/source/gameengine/Ketsji/KX_MouseActuator.h b/source/gameengine/Ketsji/KX_MouseActuator.h index bf90bd21dac..e244e271428 100644 --- a/source/gameengine/Ketsji/KX_MouseActuator.h +++ b/source/gameengine/Ketsji/KX_MouseActuator.h @@ -104,6 +104,9 @@ public: virtual void getMousePosition(float*); virtual void setMousePosition(float, float); + +#ifdef WITH_PYTHON + /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ @@ -122,6 +125,8 @@ public: static PyObject* pyattr_get_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); +#endif /* WITH_PYTHON */ + }; #endif //__KX_MOUSEACTUATOR_DOC diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp index a9f6bb0d2ff..46f27e1a2df 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -36,10 +36,13 @@ # pragma warning(disable:4786) #endif +#include <stdio.h> + #include "MT_Point3.h" #include "RAS_FramingManager.h" #include "RAS_ICanvas.h" #include "RAS_IRasterizer.h" +#include "RAS_MeshObject.h" #include "SCA_IScene.h" #include "KX_Scene.h" #include "KX_Camera.h" @@ -163,15 +166,17 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *r } else { - if (m_bFindMaterial) - { - if (client_info->m_auxilary_info) - { - bFound = (m_propertyname== ((char*)client_info->m_auxilary_info)); + if (m_bFindMaterial) { + for (unsigned int i = 0; i < hitKXObj->GetMeshCount(); ++i) { + RAS_MeshObject *meshObj = hitKXObj->GetMesh(i); + for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { + bFound = strcmp(m_propertyname.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; + if (bFound) + break; + } } } - else - { + else { bFound = hitKXObj->GetProperty(m_propertyname) != NULL; } } @@ -195,6 +200,8 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *r */ bool KX_MouseFocusSensor::NeedRayCast(KX_ClientObjectInfo* client) { + KX_GameObject *hitKXObj = client->m_gameobject; + if (client->m_type > KX_ClientObjectInfo::ACTOR) { // Unknown type of object, skip it. @@ -206,14 +213,21 @@ bool KX_MouseFocusSensor::NeedRayCast(KX_ClientObjectInfo* client) { 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))) + bool found = false; + for (unsigned int i = 0; i < hitKXObj->GetMeshCount(); ++i) { + RAS_MeshObject *meshObj = hitKXObj->GetMesh(i); + for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { + found = strcmp(m_propertyname.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; + if (found) + break; + } + } + if (!found) return false; } else { - if (client->m_gameobject->GetProperty(m_propertyname) == NULL) + if (hitKXObj->GetProperty(m_propertyname) == NULL) return false; } } @@ -269,8 +283,8 @@ bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam) m_kxengine->GetSceneViewport(m_kxscene, cam, area, viewport); /* Check if the mouse is in the viewport */ - if (( m_x < viewport.m_x2 && // less then right - m_x > viewport.m_x1 && // more then then left + if (( m_x < viewport.m_x2 && // less than right + m_x > viewport.m_x1 && // more than then left m_y_inv < viewport.m_y2 && // below top m_y_inv > viewport.m_y1) == 0) // above bottom { diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.cpp b/source/gameengine/Ketsji/KX_NavMeshObject.cpp index 8360681759a..b8907ca5c6b 100644 --- a/source/gameengine/Ketsji/KX_NavMeshObject.cpp +++ b/source/gameengine/Ketsji/KX_NavMeshObject.cpp @@ -45,7 +45,7 @@ extern "C" { #include "KX_PythonInit.h" #include "KX_PyMath.h" -#include "Value.h" +#include "EXP_Value.h" #include "Recast.h" #include "DetourStatNavMeshBuilder.h" #include "KX_ObstacleSimulation.h" @@ -98,12 +98,14 @@ void KX_NavMeshObject::ProcessReplica() { KX_GameObject::ProcessReplica(); m_navMesh = NULL; /* without this, building frees the navmesh we copied from */ - BuildNavMesh(); + if (!BuildNavMesh()) { + std::cout << "Error in " << __func__ << ": unable to build navigation mesh" << std::endl; + return; + } KX_Scene* scene = KX_GetActiveScene(); KX_ObstacleSimulation* obssimulation = scene->GetObstacleSimulation(); if (obssimulation) obssimulation->AddObstaclesForNavMesh(this); - } bool KX_NavMeshObject::BuildVertIndArrays(float *&vertices, int& nverts, @@ -321,7 +323,11 @@ bool KX_NavMeshObject::BuildNavMesh() } } - buildMeshAdjacency(polys, npolys, nverts, vertsPerPoly); + if (!buildMeshAdjacency(polys, npolys, nverts, vertsPerPoly)) { + std::cout << __func__ << ": unable to build mesh adjacency information." << std::endl; + delete[] vertices; + return false; + } float cs = 0.2f; diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.h b/source/gameengine/Ketsji/KX_NavMeshObject.h index 1599361b334..af178f9aaee 100644 --- a/source/gameengine/Ketsji/KX_NavMeshObject.h +++ b/source/gameengine/Ketsji/KX_NavMeshObject.h @@ -28,7 +28,7 @@ #define __KX_NAVMESHOBJECT_H__ #include "DetourStatNavMesh.h" #include "KX_GameObject.h" -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" #include <vector> class RAS_MeshObject; diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp index 0eec86987be..12abcb250a7 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp @@ -75,7 +75,8 @@ KX_ObjectActuator( m_reference(refobj), m_active_combined_velocity (false), m_linear_damping_active(false), - m_angular_damping_active(false) + m_angular_damping_active(false), + m_jumping(false) { if (m_bitLocalFlag.ServoControl) { @@ -140,6 +141,7 @@ bool KX_ObjectActuator::Update() 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); + m_jumping = false; return false; } else if (parent) @@ -223,6 +225,11 @@ bool KX_ObjectActuator::Update() else if (m_bitLocalFlag.CharacterMotion) { MT_Vector3 dir = m_dloc; + if (m_bitLocalFlag.DLoc) { + MT_Matrix3x3 basis = parent->GetPhysicsController()->GetOrientation(); + dir = basis * dir; + } + if (m_bitLocalFlag.AddOrSetCharLoc) { MT_Vector3 old_dir = character->GetWalkDirection(); @@ -236,21 +243,20 @@ bool KX_ObjectActuator::Update() } // We always want to set the walk direction since a walk direction of (0, 0, 0) should stop the character - if (m_bitLocalFlag.DLoc) - { - MT_Matrix3x3 basis = parent->GetPhysicsController()->GetOrientation(); - dir = basis*dir; - } character->SetWalkDirection(dir/parent->GetScene()->GetPhysicsEnvironment()->GetNumTimeSubSteps()); if (!m_bitLocalFlag.ZeroDRot) { parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0); } - if (m_bitLocalFlag.CharacterJump) - { - character->Jump(); + if (m_bitLocalFlag.CharacterJump) { + if (!m_jumping) { + character->Jump(); + m_jumping = true; + } + else if (character->OnGround()) + m_jumping = false; } } else { @@ -516,7 +522,9 @@ static Mathutils_Callback mathutils_obactu_vector_cb = { PyObject *KX_ObjectActuator::pyattr_get_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_LINV); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_LINV); } int KX_ObjectActuator::pyattr_set_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) @@ -532,7 +540,9 @@ int KX_ObjectActuator::pyattr_set_linV(void *self_v, const KX_PYATTRIBUTE_DEF *a PyObject *KX_ObjectActuator::pyattr_get_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - return Vector_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), 3, mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_ANGV); + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_ANGV); } int KX_ObjectActuator::pyattr_set_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.h b/source/gameengine/Ketsji/KX_ObjectActuator.h index 1f2453e3700..b5622d97611 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.h +++ b/source/gameengine/Ketsji/KX_ObjectActuator.h @@ -116,7 +116,8 @@ class KX_ObjectActuator : public SCA_IActuator bool m_active_combined_velocity; bool m_linear_damping_active; bool m_angular_damping_active; - + bool m_jumping; + public: enum KX_OBJECT_ACT_VEC_TYPE { KX_OBJECT_ACT_NODEF = 0, diff --git a/source/gameengine/Ketsji/KX_ParentActuator.cpp b/source/gameengine/Ketsji/KX_ParentActuator.cpp index 6926fdb1d4c..6ffa2593792 100644 --- a/source/gameengine/Ketsji/KX_ParentActuator.cpp +++ b/source/gameengine/Ketsji/KX_ParentActuator.cpp @@ -37,7 +37,7 @@ #include "KX_GameObject.h" #include "KX_PythonInit.h" -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" /* ------------------------------------------------------------------------- */ /* Native functions */ diff --git a/source/gameengine/Ketsji/KX_PolyProxy.cpp b/source/gameengine/Ketsji/KX_PolyProxy.cpp index ccc10eb06e3..4454543161b 100644 --- a/source/gameengine/Ketsji/KX_PolyProxy.cpp +++ b/source/gameengine/Ketsji/KX_PolyProxy.cpp @@ -140,21 +140,21 @@ PyObject *KX_PolyProxy::pyattr_get_v1(void *self_v, const KX_PYATTRIBUTE_DEF *at { KX_PolyProxy* self = static_cast<KX_PolyProxy*>(self_v); - return PyLong_FromLong(self->m_polygon->GetVertexOffset(0)); + return PyLong_FromLong(self->m_polygon->GetVertexOffsetAbsolute(0)); } PyObject *KX_PolyProxy::pyattr_get_v2(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_PolyProxy* self = static_cast<KX_PolyProxy*>(self_v); - return PyLong_FromLong(self->m_polygon->GetVertexOffset(1)); + return PyLong_FromLong(self->m_polygon->GetVertexOffsetAbsolute(1)); } PyObject *KX_PolyProxy::pyattr_get_v3(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_PolyProxy* self = static_cast<KX_PolyProxy*>(self_v); - return PyLong_FromLong(self->m_polygon->GetVertexOffset(2)); + return PyLong_FromLong(self->m_polygon->GetVertexOffsetAbsolute(2)); } PyObject *KX_PolyProxy::pyattr_get_v4(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) @@ -163,7 +163,7 @@ PyObject *KX_PolyProxy::pyattr_get_v4(void *self_v, const KX_PYATTRIBUTE_DEF *at if (3 < self->m_polygon->VertexCount()) { - return PyLong_FromLong(self->m_polygon->GetVertexOffset(3)); + return PyLong_FromLong(self->m_polygon->GetVertexOffsetAbsolute(3)); } return PyLong_FromLong(0); } @@ -243,7 +243,7 @@ KX_PYMETHODDEF_DOC(KX_PolyProxy, getVertexIndex, } if (index < m_polygon->VertexCount()) { - return PyLong_FromLong(m_polygon->GetVertexOffset(index)); + return PyLong_FromLong(m_polygon->GetVertexOffsetAbsolute(index)); } return PyLong_FromLong(0); } diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp index ebf1b9ec577..a0084662490 100644 --- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp +++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp @@ -41,7 +41,7 @@ #include "KX_GameObject.h" // ConvertPythonToGameObject() -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" #ifdef WITH_BULLET # include "LinearMath/btIDebugDraw.h" @@ -56,38 +56,95 @@ // if there is a better way (without global), please do so! static PHY_IPhysicsEnvironment* g_CurrentActivePhysicsEnvironment = NULL; -static char PhysicsConstraints_module_documentation[] = -"This is the Python API for the Physics Constraints"; - - -static char gPySetGravity__doc__[] = "setGravity(float x,float y,float z)"; -static char gPySetDebugMode__doc__[] = "setDebugMode(int mode)"; - -static char gPySetNumIterations__doc__[] = "setNumIterations(int numiter) This sets the number of iterations for an iterative constraint solver"; -static char gPySetNumTimeSubSteps__doc__[] = "setNumTimeSubSteps(int numsubstep) This sets the number of substeps for each physics proceed. Tradeoff quality for performance."; - - -static char gPySetDeactivationTime__doc__[] = "setDeactivationTime(float time) This sets the time after which a resting rigidbody gets deactived"; -static char gPySetDeactivationLinearTreshold__doc__[] = "setDeactivationLinearTreshold(float linearTreshold)"; -static char gPySetDeactivationAngularTreshold__doc__[] = "setDeactivationAngularTreshold(float angularTreshold)"; -static char gPySetContactBreakingTreshold__doc__[] = "setContactBreakingTreshold(float breakingTreshold) Reasonable default is 0.02 (if units are meters)"; - -static char gPySetCcdMode__doc__[] = "setCcdMode(int ccdMode) Very experimental, not recommended"; -static char gPySetSorConstant__doc__[] = "setSorConstant(float sor) Very experimental, not recommended"; -static char gPySetSolverTau__doc__[] = "setTau(float tau) Very experimental, not recommended"; -static char gPySetSolverDamping__doc__[] = "setDamping(float damping) Very experimental, not recommended"; -static char gPySetLinearAirDamping__doc__[] = "setLinearAirDamping(float damping) Very experimental, not recommended"; -static char gPySetUseEpa__doc__[] = "setUseEpa(int epa) Very experimental, not recommended"; -static char gPySetSolverType__doc__[] = "setSolverType(int solverType) Very experimental, not recommended"; - - -static char gPyCreateConstraint__doc__[] = "createConstraint(ob1,ob2,float restLength,float restitution,float damping)"; -static char gPyGetVehicleConstraint__doc__[] = "getVehicleConstraint(int constraintId)"; -static char gPyGetCharacter__doc__[] = "getCharacter(KX_GameObject obj)"; -static char gPyRemoveConstraint__doc__[] = "removeConstraint(int constraintId)"; -static char gPyGetAppliedImpulse__doc__[] = "getAppliedImpulse(int constraintId)"; - +PyDoc_STRVAR(PhysicsConstraints_module_documentation, +"This is the Python API for the Physics Constraints" +); + +PyDoc_STRVAR(gPySetGravity__doc__, +"setGravity(float x,float y,float z)\n" +"" +); +PyDoc_STRVAR(gPySetDebugMode__doc__, +"setDebugMode(int mode)\n" +"" +); + +PyDoc_STRVAR(gPySetNumIterations__doc__, +"setNumIterations(int numiter)\n" +"This sets the number of iterations for an iterative constraint solver" +); +PyDoc_STRVAR(gPySetNumTimeSubSteps__doc__, +"setNumTimeSubSteps(int numsubstep)\n" +"This sets the number of substeps for each physics proceed. Tradeoff quality for performance." +); + +PyDoc_STRVAR(gPySetDeactivationTime__doc__, +"setDeactivationTime(float time)\n" +"This sets the time after which a resting rigidbody gets deactived" +); +PyDoc_STRVAR(gPySetDeactivationLinearTreshold__doc__, +"setDeactivationLinearTreshold(float linearTreshold)\n" +"" +); +PyDoc_STRVAR(gPySetDeactivationAngularTreshold__doc__, +"setDeactivationAngularTreshold(float angularTreshold)\n" +"" +); +PyDoc_STRVAR(gPySetContactBreakingTreshold__doc__, +"setContactBreakingTreshold(float breakingTreshold)\n" +"Reasonable default is 0.02 (if units are meters)" +); + +PyDoc_STRVAR(gPySetCcdMode__doc__, +"setCcdMode(int ccdMode)\n" +"Very experimental, not recommended" +); +PyDoc_STRVAR(gPySetSorConstant__doc__, +"setSorConstant(float sor)\n" +"Very experimental, not recommended" +); +PyDoc_STRVAR(gPySetSolverTau__doc__, +"setTau(float tau)\n" +"Very experimental, not recommended" +); +PyDoc_STRVAR(gPySetSolverDamping__doc__, +"setDamping(float damping)\n" +"Very experimental, not recommended" +); +PyDoc_STRVAR(gPySetLinearAirDamping__doc__, +"setLinearAirDamping(float damping)\n" +"Very experimental, not recommended" +); +PyDoc_STRVAR(gPySetUseEpa__doc__, +"setUseEpa(int epa)\n" +"Very experimental, not recommended" +); +PyDoc_STRVAR(gPySetSolverType__doc__, +"setSolverType(int solverType)\n" +"Very experimental, not recommended" +); + +PyDoc_STRVAR(gPyCreateConstraint__doc__, +"createConstraint(ob1,ob2,float restLength,float restitution,float damping)\n" +"" +); +PyDoc_STRVAR(gPyGetVehicleConstraint__doc__, +"getVehicleConstraint(int constraintId)\n" +"" +); +PyDoc_STRVAR(gPyGetCharacter__doc__, +"getCharacter(KX_GameObject obj)\n" +"" +); +PyDoc_STRVAR(gPyRemoveConstraint__doc__, +"removeConstraint(int constraintId)\n" +"" +); +PyDoc_STRVAR(gPyGetAppliedImpulse__doc__, +"getAppliedImpulse(int constraintId)\n" +"" +); @@ -438,113 +495,47 @@ static PyObject *gPyCreateConstraint(PyObject *self, PyObject *kwds) { /* FIXME - physicsid is a long being cast to a pointer, should at least use PyCapsule */ -#if defined(_WIN64) - __int64 physicsid=0,physicsid2 = 0; -#else - long physicsid=0,physicsid2 = 0; -#endif - int constrainttype=0, extrainfo=0; - int len = PyTuple_Size(args); - int success = 1; + unsigned long long physicsid = 0, physicsid2 = 0; + int constrainttype = 0; int flag = 0; + float pivotX = 0.0f, pivotY = 0.0f, pivotZ = 0.0f, axisX = 0.0f, axisY = 0.0f, axisZ = 0.0f; - float pivotX=1,pivotY=1,pivotZ=1,axisX=0,axisY=0,axisZ=1; - if (len == 3) - { -#if defined(_WIN64) - success = PyArg_ParseTuple(args,"LLi",&physicsid,&physicsid2,&constrainttype); -#else - success = PyArg_ParseTuple(args,"lli",&physicsid,&physicsid2,&constrainttype); -#endif - } - else if (len == 6) - { -#if defined(_WIN64) - success = PyArg_ParseTuple(args,"LLifff",&physicsid,&physicsid2,&constrainttype, - &pivotX,&pivotY,&pivotZ); -#else - success = PyArg_ParseTuple(args,"llifff",&physicsid,&physicsid2,&constrainttype, - &pivotX,&pivotY,&pivotZ); -#endif - } - else if (len == 9) - { -#if defined(_WIN64) - success = PyArg_ParseTuple(args,"LLiffffff",&physicsid,&physicsid2,&constrainttype, - &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ); -#else - success = PyArg_ParseTuple(args,"lliffffff",&physicsid,&physicsid2,&constrainttype, - &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ); -#endif - } - else if (len == 10) - { -#if defined(_WIN64) - success = PyArg_ParseTuple(args,"LLiffffffi",&physicsid,&physicsid2,&constrainttype, - &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ,&flag); -#else - success = PyArg_ParseTuple(args,"lliffffffi",&physicsid,&physicsid2,&constrainttype, - &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ,&flag); -#endif - } + static const char *kwlist[] = {"physicsid_1", "physicsid_2", "constraint_type", "pivot_x", "pivot_y", "pivot_z", + "axis_x", "axis_y", "axis_z", "flag", NULL}; - /* XXX extrainfo seems to be nothing implemented. right now it works as a pivot with [X,0,0] */ - else if (len == 4) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "KKi|ffffffi:createConstraint", (char **)kwlist, + &physicsid, &physicsid2, &constrainttype, + &pivotX, &pivotY, &pivotZ, &axisX, &axisY, &axisZ, &flag)) { -#if defined(_WIN64) - success = PyArg_ParseTuple(args,"LLii",&physicsid,&physicsid2,&constrainttype,&extrainfo); -#else - success = PyArg_ParseTuple(args,"llii",&physicsid,&physicsid2,&constrainttype,&extrainfo); -#endif - pivotX=extrainfo; + return NULL; } - if (success) - { - if (PHY_GetActiveEnvironment()) - { - - PHY_IPhysicsController* physctrl = (PHY_IPhysicsController*) physicsid; - PHY_IPhysicsController* physctrl2 = (PHY_IPhysicsController*) physicsid2; - if (physctrl) //TODO:check for existence of this pointer! - { - PHY_ConstraintType ct = (PHY_ConstraintType) constrainttype; - int constraintid =0; - - if (ct == PHY_GENERIC_6DOF_CONSTRAINT) - { - //convert from euler angle into axis - float radsPerDeg = 6.283185307179586232f / 360.f; - - //we need to pass a full constraint frame, not just axis - //localConstraintFrameBasis - MT_Matrix3x3 localCFrame(MT_Vector3(radsPerDeg*axisX,radsPerDeg*axisY,radsPerDeg*axisZ)); - MT_Vector3 axis0 = localCFrame.getColumn(0); - MT_Vector3 axis1 = localCFrame.getColumn(1); - MT_Vector3 axis2 = localCFrame.getColumn(2); - - constraintid = PHY_GetActiveEnvironment()->CreateConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype, - pivotX,pivotY,pivotZ, - (float)axis0.x(),(float)axis0.y(),(float)axis0.z(), - (float)axis1.x(),(float)axis1.y(),(float)axis1.z(), - (float)axis2.x(),(float)axis2.y(),(float)axis2.z(),flag); - } - else { - constraintid = PHY_GetActiveEnvironment()->CreateConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,pivotX,pivotY,pivotZ,axisX,axisY,axisZ,0); - } - - KX_ConstraintWrapper* wrap = new KX_ConstraintWrapper((enum PHY_ConstraintType)constrainttype,constraintid,PHY_GetActiveEnvironment()); - - return wrap->NewProxy(true); - } - - + if (PHY_GetActiveEnvironment()) { + PHY_IPhysicsController *physctrl = (PHY_IPhysicsController*)physicsid; + PHY_IPhysicsController *physctrl2 = (PHY_IPhysicsController*)physicsid2; + if (physctrl) { //TODO:check for existence of this pointer! + //convert from euler angle into axis + const float deg2rad = 0.017453292f; + + //we need to pass a full constraint frame, not just axis + //localConstraintFrameBasis + MT_Matrix3x3 localCFrame(MT_Vector3(deg2rad*axisX, deg2rad*axisY, deg2rad*axisZ)); + MT_Vector3 axis0 = localCFrame.getColumn(0); + MT_Vector3 axis1 = localCFrame.getColumn(1); + MT_Vector3 axis2 = localCFrame.getColumn(2); + + int constraintid = PHY_GetActiveEnvironment()->CreateConstraint( + physctrl, physctrl2, (enum PHY_ConstraintType)constrainttype, pivotX, pivotY, pivotZ, + (float)axis0.x(), (float)axis0.y(), (float)axis0.z(), + (float)axis1.x(), (float)axis1.y(), (float)axis1.z(), + (float)axis2.x(), (float)axis2.y(), (float)axis2.z(), flag); + + KX_ConstraintWrapper *wrap = new KX_ConstraintWrapper( + (enum PHY_ConstraintType)constrainttype, constraintid, PHY_GetActiveEnvironment()); + + return wrap->NewProxy(true); } } - else { - return NULL; - } - Py_RETURN_NONE; } @@ -592,7 +583,7 @@ static PyObject *gPyRemoveConstraint(PyObject *self, { if (PHY_GetActiveEnvironment()) { - PHY_GetActiveEnvironment()->RemoveConstraint(constraintid); + PHY_GetActiveEnvironment()->RemoveConstraintById(constraintid); } } else { @@ -657,7 +648,7 @@ static struct PyMethodDef physicsconstraints_methods[] = { {"createConstraint",(PyCFunction) gPyCreateConstraint, - METH_VARARGS, (const char *)gPyCreateConstraint__doc__}, + METH_VARARGS|METH_KEYWORDS, (const char *)gPyCreateConstraint__doc__}, {"getVehicleConstraint",(PyCFunction) gPyGetVehicleConstraint, METH_VARARGS, (const char *)gPyGetVehicleConstraint__doc__}, @@ -677,7 +668,7 @@ static struct PyMethodDef physicsconstraints_methods[] = { }; static struct PyModuleDef PhysicsConstraints_module_def = { - {}, /* m_base */ + PyModuleDef_HEAD_INIT, "PhysicsConstraints", /* m_name */ PhysicsConstraints_module_documentation, /* m_doc */ 0, /* m_size */ @@ -688,7 +679,7 @@ static struct PyModuleDef PhysicsConstraints_module_def = { 0, /* m_free */ }; -PyObject *initPythonConstraintBinding() +PyMODINIT_FUNC initConstraintPythonBinding() { PyObject *ErrorObject; @@ -696,19 +687,8 @@ PyObject *initPythonConstraintBinding() PyObject *d; PyObject *item; - /* Use existing module where possible - * be careful not to init any runtime vars after this */ - m = PyImport_ImportModule( "PhysicsConstraints" ); - if (m) { - Py_DECREF(m); - return m; - } - else { - PyErr_Clear(); - - m = PyModule_Create(&PhysicsConstraints_module_def); - PyDict_SetItemString(PySys_GetObject("modules"), PhysicsConstraints_module_def.m_name, m); - } + m = PyModule_Create(&PhysicsConstraints_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), PhysicsConstraints_module_def.m_name, m); // Add some symbolic constants to the module d = PyModule_GetDict(m); @@ -747,7 +727,7 @@ PyObject *initPythonConstraintBinding() Py_FatalError("can't initialize module PhysicsConstraints"); } - return d; + return m; } #if 0 diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.h b/source/gameengine/Ketsji/KX_PyConstraintBinding.h index b4a520ce71b..2bf9f7e197d 100644 --- a/source/gameengine/Ketsji/KX_PyConstraintBinding.h +++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.h @@ -36,7 +36,8 @@ #include <Python.h> -PyObject* initPythonConstraintBinding(); +PyMODINIT_FUNC initConstraintPythonBinding(); + void PHY_SetActiveEnvironment(class PHY_IPhysicsEnvironment* env); PHY_IPhysicsEnvironment* PHY_GetActiveEnvironment(); #endif /* WITH_PYTHON */ diff --git a/source/gameengine/Ketsji/KX_PyMath.cpp b/source/gameengine/Ketsji/KX_PyMath.cpp index 804e8de2ad1..ee05fd442ab 100644 --- a/source/gameengine/Ketsji/KX_PyMath.cpp +++ b/source/gameengine/Ketsji/KX_PyMath.cpp @@ -42,9 +42,9 @@ #include "MT_Matrix4x4.h" #include "MT_Point2.h" -#include "ListValue.h" +#include "EXP_ListValue.h" -#include "KX_Python.h" +#include "EXP_Python.h" #include "KX_PyMath.h" bool PyOrientationTo(PyObject *pyval, MT_Matrix3x3 &rot, const char *error_prefix) @@ -100,7 +100,7 @@ PyObject *PyObjectFrom(const MT_Matrix4x4 &mat) #ifdef USE_MATHUTILS float fmat[16]; mat.getValue(fmat); - return Matrix_CreatePyObject(fmat, 4, 4, Py_NEW, NULL); + return Matrix_CreatePyObject(fmat, 4, 4, NULL); #else PyObject *collist = PyList_New(4); PyObject *col; @@ -124,7 +124,7 @@ PyObject *PyObjectFrom(const MT_Matrix3x3 &mat) #ifdef USE_MATHUTILS float fmat[9]; mat.getValue3x3(fmat); - return Matrix_CreatePyObject(fmat, 3, 3, Py_NEW, NULL); + return Matrix_CreatePyObject(fmat, 3, 3, NULL); #else PyObject *collist = PyList_New(3); PyObject *col; @@ -148,7 +148,7 @@ PyObject *PyObjectFrom(const MT_Quaternion &qrot) /* NOTE, were re-ordering here for Mathutils compat */ float fvec[4]; qrot.getValue(fvec); - return Quaternion_CreatePyObject(fvec, Py_NEW, NULL); + return Quaternion_CreatePyObject(fvec, NULL); } #endif @@ -157,7 +157,7 @@ PyObject *PyObjectFrom(const MT_Tuple4 &vec) #ifdef USE_MATHUTILS float fvec[4]; vec.getValue(fvec); - return Vector_CreatePyObject(fvec, 4, Py_NEW, NULL); + return Vector_CreatePyObject(fvec, 4, NULL); #else PyObject *list = PyList_New(4); PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); @@ -173,7 +173,7 @@ PyObject *PyObjectFrom(const MT_Tuple3 &vec) #ifdef USE_MATHUTILS float fvec[3]; vec.getValue(fvec); - return Vector_CreatePyObject(fvec, 3, Py_NEW, NULL); + return Vector_CreatePyObject(fvec, 3, NULL); #else PyObject *list = PyList_New(3); PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); @@ -188,7 +188,7 @@ PyObject *PyObjectFrom(const MT_Tuple2 &vec) #ifdef USE_MATHUTILS float fvec[2]; vec.getValue(fvec); - return Vector_CreatePyObject(fvec, 2, Py_NEW, NULL); + return Vector_CreatePyObject(fvec, 2, NULL); #else PyObject *list = PyList_New(2); PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); @@ -197,4 +197,19 @@ PyObject *PyObjectFrom(const MT_Tuple2 &vec) #endif } +PyObject *PyColorFromVector(const MT_Vector3 &vec) +{ +#ifdef USE_MATHUTILS + float fvec[3]; + vec.getValue(fvec); + return Color_CreatePyObject(fvec, NULL); +#else + PyObject *list = PyList_New(3); + PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); + PyList_SET_ITEM(list, 1, PyFloat_FromDouble(vec[1])); + PyList_SET_ITEM(list, 2, PyFloat_FromDouble(vec[2])); + return list; +#endif +} + #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_PyMath.h b/source/gameengine/Ketsji/KX_PyMath.h index 159506946e8..917fd0fcda6 100644 --- a/source/gameengine/Ketsji/KX_PyMath.h +++ b/source/gameengine/Ketsji/KX_PyMath.h @@ -41,8 +41,8 @@ #include "MT_Matrix3x3.h" #include "MT_Matrix4x4.h" -#include "KX_Python.h" -#include "PyObjectPlus.h" +#include "EXP_Python.h" +#include "EXP_PyObjectPlus.h" #ifdef WITH_PYTHON #ifdef USE_MATHUTILS @@ -273,4 +273,9 @@ PyObject *PyObjectFrom(const MT_Tuple4 &pos); #endif +/** + * Converts an MT_Vector3 to a python color object. + */ +PyObject *PyColorFromVector(const MT_Vector3 &vec); + #endif /* WITH_PYTHON */ diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index da8a0c0844e..2fef74ca33d 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -30,7 +30,7 @@ * \ingroup ketsji */ -#include "GL/glew.h" +#include "glew-mx.h" #ifdef _MSC_VER # pragma warning (disable:4786) @@ -51,6 +51,8 @@ # include <Python.h> extern "C" { + # include "BLI_utildefines.h" + # include "python_utildefines.h" # include "bpy_internal_import.h" /* from the blender python api, but we want to import text too! */ # include "py_capi_utils.h" # include "mathutils.h" // 'mathutils' module copied here so the blenderlayer can use. @@ -59,7 +61,7 @@ extern "C" { # include "marshal.h" /* python header for loading/saving dicts */ } -#include "AUD_PyInit.h" +#include "../../../../intern/audaspace/intern/AUD_PyInit.h" #endif /* WITH_PYTHON */ @@ -110,8 +112,8 @@ extern "C" { #include "RAS_2DFilterManager.h" #include "MT_Vector3.h" #include "MT_Point3.h" -#include "ListValue.h" -#include "InputParser.h" +#include "EXP_ListValue.h" +#include "EXP_InputParser.h" #include "KX_Scene.h" #include "NG_NetworkScene.h" //Needed for sendMessage() @@ -121,7 +123,7 @@ extern "C" { #include "KX_PyMath.h" -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" #include "KX_PythonInitTypes.h" @@ -130,12 +132,17 @@ extern "C" { #include "DNA_scene_types.h" #include "PHY_IPhysicsEnvironment.h" + +extern "C" { #include "BKE_main.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_appdir.h" +#include "BKE_blender.h" #include "BLI_blenlib.h" #include "GPU_material.h" #include "MEM_guardedalloc.h" +} /* for converting new scenes */ #include "KX_BlenderSceneConverter.h" @@ -179,17 +186,17 @@ class KX_KetsjiEngine* KX_GetActiveEngine() } /* why is this in python? */ -void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color) +void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color) { if (gp_Rasterizer) - gp_Rasterizer->DrawDebugLine(from,to,color); + gp_Rasterizer->DrawDebugLine(gp_KetsjiScene, from, to, color); } void KX_RasterizerDrawDebugCircle(const MT_Vector3& center, const MT_Scalar radius, const MT_Vector3& color, const MT_Vector3& normal, int nsector) { if (gp_Rasterizer) - gp_Rasterizer->DrawDebugCircle(center, radius, color, normal, nsector); + gp_Rasterizer->DrawDebugCircle(gp_KetsjiScene, center, radius, color, normal, nsector); } #ifdef WITH_PYTHON @@ -214,13 +221,16 @@ static void KX_MACRO_addTypesToDict_fn(PyObject *dict, const char *name, long va // temporarily python stuff, will be put in another place later ! -#include "KX_Python.h" +#include "EXP_Python.h" #include "SCA_PythonController.h" // List of methods defined in the module static PyObject *ErrorObject; -static const char *gPyGetRandomFloat_doc="getRandomFloat returns a random floating point value in the range [0..1]"; +PyDoc_STRVAR(gPyGetRandomFloat_doc, +"getRandomFloat()\n" +"returns a random floating point value in the range [0..1]" +); static PyObject *gPyGetRandomFloat(PyObject *) { return PyFloat_FromDouble(MT_random()); @@ -238,15 +248,15 @@ static PyObject *gPySetGravity(PyObject *, PyObject *value) 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 current .blend or runtime\n\ -file to make a full path name.\n\ -The function also converts the directory separator to the local file system format."; - +PyDoc_STRVAR(gPyExpandPath_doc, +"expandPath(path)\n" +"Converts a blender internal path into a proper file system path.\n" +" path - the string path to convert.\n" +"Use / as directory separator in path\n" +"You can use '//' at the start of the string to define a relative path." +"Blender replaces that string by the directory of the current .blend or runtime file to make a full path name.\n" +"The function also converts the directory separator to the local file system format." +); static PyObject *gPyExpandPath(PyObject *, PyObject *args) { char expanded[FILE_MAX]; @@ -260,10 +270,10 @@ static PyObject *gPyExpandPath(PyObject *, PyObject *args) return PyC_UnicodeFromByte(expanded); } -static char gPyStartGame_doc[] = -"startGame(blend)\n\ -Loads the blend file"; - +PyDoc_STRVAR(gPyStartGame_doc, +"startGame(blend)\n" +"Loads the blend file" +); static PyObject *gPyStartGame(PyObject *, PyObject *args) { char* blendfile; @@ -277,10 +287,10 @@ static PyObject *gPyStartGame(PyObject *, PyObject *args) Py_RETURN_NONE; } -static char gPyEndGame_doc[] = -"endGame()\n\ -Ends the current game"; - +PyDoc_STRVAR(gPyEndGame_doc, +"endGame()\n" +"Ends the current game" +); static PyObject *gPyEndGame(PyObject *) { gp_KetsjiEngine->RequestExit(KX_EXIT_REQUEST_QUIT_GAME); @@ -290,10 +300,10 @@ static PyObject *gPyEndGame(PyObject *) Py_RETURN_NONE; } -static char gPyRestartGame_doc[] = -"restartGame()\n\ -Restarts the current game by reloading the .blend file"; - +PyDoc_STRVAR(gPyRestartGame_doc, +"restartGame()\n" +"Restarts the current game by reloading the .blend file" +); static PyObject *gPyRestartGame(PyObject *) { gp_KetsjiEngine->RequestExit(KX_EXIT_REQUEST_RESTART_GAME); @@ -302,10 +312,10 @@ static PyObject *gPyRestartGame(PyObject *) Py_RETURN_NONE; } -static char gPySaveGlobalDict_doc[] = - "saveGlobalDict()\n" - "Saves bge.logic.globalDict to a file"; - +PyDoc_STRVAR(gPySaveGlobalDict_doc, +"saveGlobalDict()\n" +"Saves bge.logic.globalDict to a file" +); static PyObject *gPySaveGlobalDict(PyObject *) { char marshal_path[512]; @@ -339,15 +349,15 @@ static PyObject *gPySaveGlobalDict(PyObject *) Py_RETURN_NONE; } -static char gPyLoadGlobalDict_doc[] = - "LoadGlobalDict()\n" - "Loads bge.logic.globalDict from a file"; - +PyDoc_STRVAR(gPyLoadGlobalDict_doc, +"LoadGlobalDict()\n" +"Loads bge.logic.globalDict from a file" +); static PyObject *gPyLoadGlobalDict(PyObject *) { char marshal_path[512]; char *marshal_buffer = NULL; - size_t marshal_length; + int marshal_length; FILE *fp = NULL; int result; @@ -358,7 +368,12 @@ static PyObject *gPyLoadGlobalDict(PyObject *) if (fp) { // obtain file size: fseek (fp, 0, SEEK_END); - marshal_length = (size_t)ftell(fp); + marshal_length = ftell(fp); + if (marshal_length == -1) { + printf("Warning: could not read position of '%s'\n", marshal_path); + fclose(fp); + Py_RETURN_NONE; + } rewind(fp); marshal_buffer = (char*)malloc (sizeof(char)*marshal_length); @@ -380,23 +395,23 @@ static PyObject *gPyLoadGlobalDict(PyObject *) Py_RETURN_NONE; } -static char gPyGetProfileInfo_doc[] = +PyDoc_STRVAR(gPyGetProfileInfo_doc, "getProfileInfo()\n" -"returns a dictionary with profiling information"; - +"returns a dictionary with profiling information" +); static PyObject *gPyGetProfileInfo(PyObject *) { return gp_KetsjiEngine->GetPyProfileDict(); } -static char gPySendMessage_doc[] = -"sendMessage(subject, [body, to, from])\n\ -sends a message in same manner as a message actuator\ -subject = Subject of the message\ -body = Message body\ -to = Name of object to send the message to\ -from = Name of object to send the string from"; - +PyDoc_STRVAR(gPySendMessage_doc, +"sendMessage(subject, [body, to, from])\n" +"sends a message in same manner as a message actuator" +" subject = Subject of the message" +" body = Message body" +" to = Name of object to send the message to" +" from = Name of object to send the string from" +); static PyObject *gPySendMessage(PyObject *, PyObject *args) { char* subject; @@ -511,6 +526,27 @@ static PyObject *gPyGetPhysicsTicRate(PyObject *) return PyFloat_FromDouble(PHY_GetActiveEnvironment()->GetFixedTimeStep()); } +static PyObject *gPySetAnimRecordFrame(PyObject *, PyObject *args) +{ + int anim_record_frame; + + if (!PyArg_ParseTuple(args, "i:setAnimRecordFrame", &anim_record_frame)) + return NULL; + + if (anim_record_frame < 0 && (U.flag & USER_NONEGFRAMES)) { + PyErr_Format(PyExc_ValueError, "Frame number must be non-negative (was %i).", anim_record_frame); + return NULL; + } + + gp_KetsjiEngine->setAnimRecordFrame(anim_record_frame); + Py_RETURN_NONE; +} + +static PyObject *gPyGetAnimRecordFrame(PyObject *) +{ + return PyLong_FromLong(gp_KetsjiEngine->getAnimRecordFrame()); +} + static PyObject *gPyGetAverageFrameRate(PyObject *) { return PyFloat_FromDouble(KX_KetsjiEngine::GetAverageFrameRate()); @@ -556,11 +592,12 @@ static PyObject *gPyGetBlendFileList(PyObject *, PyObject *args) return list; } -static char gPyAddScene_doc[] = -"addScene(name, [overlay])\n\ -adds a scene to the game engine\n\ -name = Name of the scene\n\ -overlay = Overlay or underlay"; +PyDoc_STRVAR(gPyAddScene_doc, +"addScene(name, [overlay])\n" +"Adds a scene to the game engine.\n" +" name = Name of the scene\n" +" overlay = Overlay or underlay" +); static PyObject *gPyAddScene(PyObject *, PyObject *args) { char* name; @@ -574,17 +611,19 @@ static PyObject *gPyAddScene(PyObject *, PyObject *args) Py_RETURN_NONE; } -static const char *gPyGetCurrentScene_doc = +PyDoc_STRVAR(gPyGetCurrentScene_doc, "getCurrentScene()\n" -"Gets a reference to the current scene.\n"; +"Gets a reference to the current scene." +); static PyObject *gPyGetCurrentScene(PyObject *self) { return gp_KetsjiScene->GetProxy(); } -static const char *gPyGetSceneList_doc = +PyDoc_STRVAR(gPyGetSceneList_doc, "getSceneList()\n" -"Return a list of converted scenes.\n"; +"Return a list of converted scenes." +); static PyObject *gPyGetSceneList(PyObject *self) { KX_KetsjiEngine* m_engine = KX_GetActiveEngine(); @@ -869,6 +908,8 @@ static struct PyMethodDef game_methods[] = { {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, (const char *)"Sets the logic tic rate"}, {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_NOARGS, (const char *)"Gets the physics tic rate"}, {"setPhysicsTicRate", (PyCFunction) gPySetPhysicsTicRate, METH_VARARGS, (const char *)"Sets the physics tic rate"}, + {"getAnimRecordFrame", (PyCFunction) gPyGetAnimRecordFrame, METH_NOARGS, (const char *)"Gets the current frame number used for animation recording"}, + {"setAnimRecordFrame", (PyCFunction) gPySetAnimRecordFrame, METH_VARARGS, (const char *)"Sets the current frame number used for animation recording"}, {"getExitKey", (PyCFunction) gPyGetExitKey, METH_NOARGS, (const char *)"Gets the key used to exit the game engine"}, {"setExitKey", (PyCFunction) gPySetExitKey, METH_VARARGS, (const char *)"Sets the key used to exit the game engine"}, {"getAverageFrameRate", (PyCFunction) gPyGetAverageFrameRate, METH_NOARGS, (const char *)"Gets the estimated average frame rate"}, @@ -1002,111 +1043,39 @@ static PyObject *gPyGetFocalLength(PyObject *, PyObject *, PyObject *) Py_RETURN_NONE; } -static PyObject *gPySetBackgroundColor(PyObject *, PyObject *value) +static PyObject *gPyGetStereoEye(PyObject *, PyObject *, PyObject *) { - - MT_Vector4 vec; - if (!PyVecTo(value, vec)) - return NULL; - - if (gp_Canvas) - { - gp_Rasterizer->SetBackColor((float)vec[0], (float)vec[1], (float)vec[2], (float)vec[3]); - } - - KX_WorldInfo *wi = gp_KetsjiScene->GetWorldInfo(); - if (wi->hasWorld()) - wi->setBackColor((float)vec[0], (float)vec[1], (float)vec[2]); + int flag = RAS_IRasterizer::RAS_STEREO_LEFTEYE; - Py_RETURN_NONE; -} - - - -static PyObject *gPySetMistColor(PyObject *, PyObject *value) -{ - - MT_Vector3 vec; - if (!PyVecTo(value, vec)) - return NULL; - if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistColor(color), Rasterizer not available"); + PyErr_SetString(PyExc_RuntimeError, "Rasterizer.getStereoEye(), Rasterizer not available"); return NULL; } - gp_Rasterizer->SetFogColor((float)vec[0], (float)vec[1], (float)vec[2]); - - Py_RETURN_NONE; -} -static PyObject *gPyDisableMist(PyObject *) -{ - - if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistColor(color), Rasterizer not available"); - return NULL; - } - gp_Rasterizer->DisableFog(); - - Py_RETURN_NONE; -} + if (gp_Rasterizer->Stereo()) + flag = gp_Rasterizer->GetEye(); -static PyObject *gPySetMistStart(PyObject *, PyObject *args) -{ - - float miststart; - if (!PyArg_ParseTuple(args,"f:setMistStart",&miststart)) - return NULL; - - if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistStart(float), Rasterizer not available"); - return NULL; - } - - gp_Rasterizer->SetFogStart(miststart); - - Py_RETURN_NONE; + return PyLong_FromLong(flag); } - - -static PyObject *gPySetMistEnd(PyObject *, PyObject *args) +static PyObject *gPySetBackgroundColor(PyObject *, PyObject *value) { - - float mistend; - if (!PyArg_ParseTuple(args,"f:setMistEnd",&mistend)) + MT_Vector4 vec; + if (!PyVecTo(value, vec)) return NULL; - - if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistEnd(float), Rasterizer not available"); + + KX_WorldInfo *wi = gp_KetsjiScene->GetWorldInfo(); + if (!wi->hasWorld()) { + PyErr_SetString(PyExc_RuntimeError, "bge.render.SetBackgroundColor(color), World not available"); return NULL; } - - gp_Rasterizer->SetFogEnd(mistend); - - Py_RETURN_NONE; -} + ShowDeprecationWarning("setBackgroundColor()", "KX_WorldInfo.background_color"); + wi->setBackColor((float)vec[0], (float)vec[1], (float)vec[2]); -static PyObject *gPySetAmbientColor(PyObject *, PyObject *value) -{ - - MT_Vector3 vec; - if (!PyVecTo(value, vec)) - return NULL; - - if (!gp_Rasterizer) { - PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setAmbientColor(color), Rasterizer not available"); - return NULL; - } - gp_Rasterizer->SetAmbientColor((float)vec[0], (float)vec[1], (float)vec[2]); - Py_RETURN_NONE; } - - - static PyObject *gPyMakeScreenshot(PyObject *, PyObject *args) { char* filename; @@ -1192,10 +1161,6 @@ static PyObject *gPySetGLSLMaterialSetting(PyObject *, else gs->glslflag |= flag; - /* temporarily store the glsl settings in the scene for the GLSL materials */ - GameData *gm= &(gp_KetsjiScene->GetBlenderScene()->gm); - gm->flag = gs->glslflag; - /* display lists and GLSL materials need to be remade */ if (sceneflag != gs->glslflag) { GPU_materials_free(); @@ -1203,11 +1168,14 @@ static PyObject *gPySetGLSLMaterialSetting(PyObject *, KX_SceneList *scenes = gp_KetsjiEngine->CurrentScenes(); KX_SceneList::iterator it; - for (it=scenes->begin(); it!=scenes->end(); it++) + for (it=scenes->begin(); it!=scenes->end(); it++) { + // temporarily store the glsl settings in the scene for the GLSL materials + (*it)->GetBlenderScene()->gm.flag = gs->glslflag; if ((*it)->GetBucketManager()) { (*it)->GetBucketManager()->ReleaseDisplayLists(); (*it)->GetBucketManager()->ReleaseMaterials(); } + } } } @@ -1320,7 +1288,7 @@ static PyObject *gPyDrawLine(PyObject *, PyObject *args) if (!PyVecTo(ob_color, color)) return NULL; - gp_Rasterizer->DrawDebugLine(from,to,color); + gp_Rasterizer->DrawDebugLine(gp_KetsjiScene, from, to, color); Py_RETURN_NONE; } @@ -1396,7 +1364,9 @@ static PyObject *gPySetVsync(PyObject *, PyObject *args) static PyObject *gPyGetVsync(PyObject *) { - return PyLong_FromLong(gp_Canvas->GetSwapInterval()); + int interval = 0; + gp_Canvas->GetSwapInterval(interval); + return PyLong_FromLong(interval); } static PyObject *gPyShowFramerate(PyObject *, PyObject *args) @@ -1463,6 +1433,24 @@ static PyObject *gPyClearDebugList(PyObject *) Py_RETURN_NONE; } +static PyObject *gPyGetDisplayDimensions(PyObject *) +{ + PyObject *result; + int width, height; + + gp_Canvas->GetDisplayDimensions(width, height); + + result = PyTuple_New(2); + PyTuple_SET_ITEMS(result, + PyLong_FromLong(width), + PyLong_FromLong(height)); + + return result; +} + +PyDoc_STRVAR(Rasterizer_module_documentation, +"This is the Python API for the game engine of Rasterizer" +); static struct PyMethodDef rasterizer_methods[] = { {"getWindowWidth",(PyCFunction) gPyGetWindowWidth, @@ -1478,11 +1466,6 @@ static struct PyMethodDef rasterizer_methods[] = { {"setMousePosition",(PyCFunction) gPySetMousePosition, METH_VARARGS, "setMousePosition(int x,int y)"}, {"setBackgroundColor",(PyCFunction)gPySetBackgroundColor,METH_O,"set Background Color (rgb)"}, - {"setAmbientColor",(PyCFunction)gPySetAmbientColor,METH_O,"set Ambient Color (rgb)"}, - {"disableMist",(PyCFunction)gPyDisableMist,METH_NOARGS,"turn off mist"}, - {"setMistColor",(PyCFunction)gPySetMistColor,METH_O,"set Mist Color (rgb)"}, - {"setMistStart",(PyCFunction)gPySetMistStart,METH_VARARGS,"set Mist Start(rgb)"}, - {"setMistEnd",(PyCFunction)gPySetMistEnd,METH_VARARGS,"set Mist End(rgb)"}, {"enableMotionBlur",(PyCFunction)gPyEnableMotionBlur,METH_VARARGS,"enable motion blur"}, {"disableMotionBlur",(PyCFunction)gPyDisableMotionBlur,METH_NOARGS,"disable motion blur"}, @@ -1490,6 +1473,7 @@ static struct PyMethodDef rasterizer_methods[] = { {"getEyeSeparation", (PyCFunction) gPyGetEyeSeparation, METH_NOARGS, "get the eye separation for stereo mode"}, {"setFocalLength", (PyCFunction) gPySetFocalLength, METH_VARARGS, "set the focal length for stereo mode"}, {"getFocalLength", (PyCFunction) gPyGetFocalLength, METH_VARARGS, "get the focal length for stereo mode"}, + {"getStereoEye", (PyCFunction) gPyGetStereoEye, METH_VARARGS, "get the current stereoscopy eye being rendered"}, {"setMaterialMode",(PyCFunction) gPySetMaterialType, METH_VARARGS, "set the material mode to use for OpenGL rendering"}, {"getMaterialMode",(PyCFunction) gPyGetMaterialType, @@ -1507,6 +1491,8 @@ static struct PyMethodDef rasterizer_methods[] = { {"setWindowSize", (PyCFunction) gPySetWindowSize, METH_VARARGS, ""}, {"setFullScreen", (PyCFunction) gPySetFullScreen, METH_O, ""}, {"getFullScreen", (PyCFunction) gPyGetFullScreen, METH_NOARGS, ""}, + {"getDisplayDimensions", (PyCFunction) gPyGetDisplayDimensions, METH_NOARGS, + "Get the actual dimensions, in pixels, of the physical display (e.g., the monitor)."}, {"setMipmapping", (PyCFunction) gPySetMipmapping, METH_VARARGS, ""}, {"getMipmapping", (PyCFunction) gPyGetMipmapping, METH_NOARGS, ""}, {"setVsync", (PyCFunction) gPySetVsync, METH_VARARGS, ""}, @@ -1519,15 +1505,11 @@ static struct PyMethodDef rasterizer_methods[] = { { NULL, (PyCFunction) NULL, 0, NULL } }; -// Initialization function for the module (*must* be called initGameLogic) -static char GameLogic_module_documentation[] = -"This is the Python API for the game engine of bge.logic" -; -static char Rasterizer_module_documentation[] = -"This is the Python API for the game engine of Rasterizer" -; +PyDoc_STRVAR(GameLogic_module_documentation, +"This is the Python API for the game engine of bge.logic" +); static struct PyModuleDef GameLogic_module_def = { {}, /* m_base */ @@ -1541,33 +1523,20 @@ static struct PyModuleDef GameLogic_module_def = { 0, /* m_free */ }; -PyObject *initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack to get gravity hook +PyMODINIT_FUNC initGameLogicPythonBinding() { PyObject *m; PyObject *d; PyObject *item; /* temp PyObject *storage */ - - gp_KetsjiEngine = engine; - gp_KetsjiScene = scene; gUseVisibilityTemp=false; - + PyObjectPlus::ClearDeprecationWarning(); /* Not that nice to call here but makes sure warnings are reset between loading scenes */ - - /* Use existing module where possible - * be careful not to init any runtime vars after this */ - m = PyImport_ImportModule( "GameLogic" ); - if (m) { - Py_DECREF(m); - return m; - } - else { - PyErr_Clear(); - // Create the module and add the functions - m = PyModule_Create(&GameLogic_module_def); - PyDict_SetItemString(PySys_GetObject("modules"), GameLogic_module_def.m_name, m); - } - + + m = PyModule_Create(&GameLogic_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), GameLogic_module_def.m_name, m); + + // Add some symbolic constants to the module d = PyModule_GetDict(m); @@ -1587,17 +1556,22 @@ PyObject *initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack PyObject* joylist = PyList_New(JOYINDEX_MAX); for (int i=0; i<JOYINDEX_MAX; ++i) { - SCA_Joystick* joy = SCA_Joystick::GetInstance(i); + SCA_Joystick *joy = SCA_Joystick::GetInstance(i); + PyObject *item; + if (joy && joy->Connected()) { gp_PythonJoysticks[i] = new SCA_PythonJoystick(joy); - PyObject* tmp = gp_PythonJoysticks[i]->NewProxy(true); - Py_INCREF(tmp); - PyList_SET_ITEM(joylist, i, tmp); - } else { - joy->ReleaseInstance(); - Py_INCREF(Py_None); - PyList_SET_ITEM(joylist, i, Py_None); + item = gp_PythonJoysticks[i]->NewProxy(true); } + else { + if (joy) { + joy->ReleaseInstance(); + } + item = Py_None; + } + + Py_INCREF(item); + PyList_SET_ITEM(joylist, i, item); } PyDict_SetItemString(d, "joysticks", joylist); @@ -2047,7 +2021,77 @@ void removeImportMain(struct Main *maggie) bpy_import_main_extra_remove(maggie); } -// Copied from bpy_interface.c + +PyDoc_STRVAR(BGE_module_documentation, + "This module contains submodules for the Blender Game Engine.\n" +); + +static struct PyModuleDef BGE_module_def = { + PyModuleDef_HEAD_INIT, + "bge", /* m_name */ + BGE_module_documentation, /* m_doc */ + 0, /* m_size */ + NULL, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +PyMODINIT_FUNC initBGE(void) +{ + PyObject *mod; + PyObject *submodule; + PyObject *sys_modules = PyThreadState_GET()->interp->modules; + const char *mod_full; + + mod = PyModule_Create(&BGE_module_def); + + /* skip "bge." */ +#define SUBMOD (mod_full + 4) + + mod_full = "bge.app"; + PyModule_AddObject(mod, SUBMOD, (submodule = initApplicationPythonBinding())); + PyDict_SetItemString(sys_modules, mod_full, submodule); + Py_INCREF(submodule); + + mod_full = "bge.constraints"; + PyModule_AddObject(mod, SUBMOD, (submodule = initConstraintPythonBinding())); + PyDict_SetItemString(sys_modules, mod_full, submodule); + Py_INCREF(submodule); + + mod_full = "bge.events"; + PyModule_AddObject(mod, SUBMOD, (submodule = initGameKeysPythonBinding())); + PyDict_SetItemString(sys_modules, mod_full, submodule); + Py_INCREF(submodule); + + mod_full = "bge.logic"; + PyModule_AddObject(mod, SUBMOD, (submodule = initGameLogicPythonBinding())); + PyDict_SetItemString(sys_modules, mod_full, submodule); + Py_INCREF(submodule); + + mod_full = "bge.render"; + PyModule_AddObject(mod, SUBMOD, (submodule = initRasterizerPythonBinding())); + PyDict_SetItemString(sys_modules, mod_full, submodule); + Py_INCREF(submodule); + + mod_full = "bge.texture"; + PyModule_AddObject(mod, SUBMOD, (submodule = initVideoTexturePythonBinding())); + PyDict_SetItemString(sys_modules, mod_full, submodule); + Py_INCREF(submodule); + + mod_full = "bge.types"; + PyModule_AddObject(mod, SUBMOD, (submodule = initGameTypesPythonBinding())); + PyDict_SetItemString(sys_modules, mod_full, submodule); + Py_INCREF(submodule); + +#undef SUBMOD + + return mod; +} + + +/* minimal required blender modules to run blenderplayer */ static struct _inittab bge_internal_modules[] = { {"mathutils", PyInit_mathutils}, {"bgl", BPyInit_bgl}, @@ -2060,7 +2104,7 @@ static struct _inittab bge_internal_modules[] = { * Python is not initialized. * see bpy_interface.c's BPY_python_start() which shares the same functionality in blender. */ -PyObject *initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level, Main *maggie, int argc, char** argv) +PyObject *initGamePlayerPythonScripting(Main *maggie, int argc, char** argv) { /* Yet another gotcha in the py api * Cant run PySys_SetArgv more than once because this adds the @@ -2069,16 +2113,22 @@ PyObject *initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur * somehow it remembers the sys.path - Campbell */ static bool first_time = true; - const char * const py_path_bundle = BLI_get_folder(BLENDER_SYSTEM_PYTHON, NULL); - -#if 0 // TODO - py3 - STR_String pname = progname; - Py_SetProgramName(pname.Ptr()); -#endif - + const char * const py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, NULL); + + /* not essential but nice to set our name */ + static wchar_t program_path_wchar[FILE_MAX]; /* python holds a reference */ + BLI_strncpy_wchar_from_utf8(program_path_wchar, BKE_appdir_program_path(), ARRAY_SIZE(program_path_wchar)); + Py_SetProgramName(program_path_wchar); + + /* Update, Py3.3 resolves attempting to parse non-existing header */ +#if 0 + /* Python 3.2 now looks for '2.xx/python/include/python3.2d/pyconfig.h' to + * parse from the 'sysconfig' module which is used by 'site', + * so for now disable site. alternatively we could copy the file. */ if (py_path_bundle != NULL) { - Py_NoSiteFlag = 1; + Py_NoSiteFlag = 1; /* inhibits the automatic importing of 'site' */ } +#endif Py_FrozenFlag = 1; @@ -2102,12 +2152,16 @@ PyObject *initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur PySys_SetObject("argv", py_argv); Py_DECREF(py_argv); } - + /* Initialize thread support (also acquires lock) */ PyEval_InitThreads(); bpy_import_init(PyEval_GetBuiltins()); + bpy_import_main_set(maggie); + + initPySysObjects(maggie); + /* mathutils types are used by the BGE even if we don't import them */ { PyObject *mod = PyImport_ImportModuleLevel("mathutils", NULL, NULL, NULL, 0); @@ -2122,12 +2176,8 @@ PyObject *initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur } #endif - initPyTypes(); - - bpy_import_main_set(maggie); - - initPySysObjects(maggie); - + PyDict_SetItemString(PyImport_GetModuleDict(), "bge", initBGE()); + first_time = false; PyObjectPlus::ClearDeprecationWarning(); @@ -2164,12 +2214,13 @@ void exitGamePlayerPythonScripting() /** * Python is already initialized. */ -PyObject *initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level, Main *maggie) +PyObject *initGamePythonScripting(Main *maggie) { -#if 0 // XXX TODO Py3 - STR_String pname = progname; - Py_SetProgramName(pname.Ptr()); -#endif + /* no need to Py_SetProgramName, it was already taken care of in BPY_python_start */ + + bpy_import_main_set(maggie); + + initPySysObjects(maggie); #ifdef WITH_AUDASPACE /* accessing a SoundActuator's sound results in a crash if aud is not initialized... */ @@ -2179,11 +2230,7 @@ PyObject *initGamePythonScripting(const STR_String& progname, TPythonSecurityLev } #endif - initPyTypes(); - - bpy_import_main_set(maggie); - - initPySysObjects(maggie); + PyDict_SetItemString(PyImport_GetModuleDict(), "bge", initBGE()); PyObjectPlus::NullDeprecationWarning(); @@ -2216,51 +2263,32 @@ void exitGamePythonScripting() void setupGamePython(KX_KetsjiEngine* ketsjiengine, KX_Scene *startscene, Main *blenderdata, PyObject *pyGlobalDict, PyObject **gameLogic, PyObject **gameLogic_keys, int argc, char** argv) { - PyObject *dictionaryobject; + PyObject *modules, *dictionaryobject; + + gp_Canvas = ketsjiengine->GetCanvas(); + gp_Rasterizer = ketsjiengine->GetRasterizer(); + gp_KetsjiEngine = ketsjiengine; + gp_KetsjiScene = startscene; if (argv) /* player only */ - dictionaryobject= initGamePlayerPythonScripting("Ketsji", psl_Lowest, blenderdata, argc, argv); + dictionaryobject= initGamePlayerPythonScripting(blenderdata, argc, argv); else - dictionaryobject= initGamePythonScripting("Ketsji", psl_Lowest, blenderdata); + dictionaryobject= initGamePythonScripting(blenderdata); ketsjiengine->SetPyNamespace(dictionaryobject); - initRasterizer(ketsjiengine->GetRasterizer(), ketsjiengine->GetCanvas()); - *gameLogic = initGameLogic(ketsjiengine, startscene); - /* is set in initGameLogic so only set here if we want it to persist between scenes */ + modules = PyImport_GetModuleDict(); + + *gameLogic = PyDict_GetItemString(modules, "GameLogic"); + /* is set in initGameLogicPythonBinding so only set here if we want it to persist between scenes */ if (pyGlobalDict) PyDict_SetItemString(PyModule_GetDict(*gameLogic), "globalDict", pyGlobalDict); // Same as importing the module. *gameLogic_keys = PyDict_Keys(PyModule_GetDict(*gameLogic)); - - initGameKeys(); - initPythonConstraintBinding(); - initVideoTexture(); - - /* could be done a lot more nicely, but for now a quick way to get bge.* working */ - PyRun_SimpleString("sys = __import__('sys');" - "bge = type(sys)('bge');" - "bge.__dict__.update({'logic':__import__('GameLogic'), " - "'render':__import__('Rasterizer'), " - "'events':__import__('GameKeys'), " - "'constraints':__import__('PhysicsConstraints'), " - "'physics':__import__('PhysicsConstraints')," - "'types':__import__('GameTypes'), " - "'texture':__import__('VideoTexture')});" - /* so we can do 'import bge.foo as bar' */ - "sys.modules.update({'bge': bge, " - "'bge.logic':bge.logic, " - "'bge.render':bge.render, " - "'bge.events':bge.events, " - "'bge.constraints':bge.constraints, " - "'bge.physics':bge.physics," - "'bge.types':bge.types, " - "'bge.texture':bge.texture})" - ); } static struct PyModuleDef Rasterizer_module_def = { - {}, /* m_base */ + PyModuleDef_HEAD_INIT, "Rasterizer", /* m_name */ Rasterizer_module_documentation, /* m_doc */ 0, /* m_size */ @@ -2271,29 +2299,14 @@ static struct PyModuleDef Rasterizer_module_def = { 0, /* m_free */ }; -PyObject *initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas) +PyMODINIT_FUNC initRasterizerPythonBinding() { - gp_Canvas = canvas; - gp_Rasterizer = rasty; - - PyObject *m; PyObject *d; - /* Use existing module where possible - * be careful not to init any runtime vars after this */ - m = PyImport_ImportModule( "Rasterizer" ); - if (m) { - Py_DECREF(m); - return m; - } - else { - PyErr_Clear(); + m = PyModule_Create(&Rasterizer_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), Rasterizer_module_def.m_name, m); - // Create the module and add the functions - m = PyModule_Create(&Rasterizer_module_def); - PyDict_SetItemString(PySys_GetObject("modules"), Rasterizer_module_def.m_name, m); - } // Add some symbolic constants to the module d = PyModule_GetDict(m); @@ -2314,6 +2327,10 @@ PyObject *initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas) KX_MACRO_addTypesToDict(d, VSYNC_ON, VSYNC_ON); KX_MACRO_addTypesToDict(d, VSYNC_ADAPTIVE, VSYNC_ADAPTIVE); + /* stereoscopy */ + KX_MACRO_addTypesToDict(d, LEFT_EYE, RAS_IRasterizer::RAS_STEREO_LEFTEYE); + KX_MACRO_addTypesToDict(d, RIGHT_EYE, RAS_IRasterizer::RAS_STEREO_RIGHTEYE); + // XXXX Add constants here // Check for errors @@ -2322,7 +2339,7 @@ PyObject *initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas) Py_FatalError("can't initialize module Rasterizer"); } - return d; + return m; } @@ -2331,13 +2348,14 @@ PyObject *initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas) /* GameKeys: symbolic constants for key mapping */ /* ------------------------------------------------------------------------- */ -static char GameKeys_module_documentation[] = +PyDoc_STRVAR(GameKeys_module_documentation, "This modules provides defines for key-codes" -; +); -static char gPyEventToString_doc[] = -"EventToString(event) - Take a valid event from the GameKeys module or Keyboard Sensor and return a name" -; +PyDoc_STRVAR(gPyEventToString_doc, +"EventToString(event)\n" +"Take a valid event from the GameKeys module or Keyboard Sensor and return a name" +); static PyObject *gPyEventToString(PyObject *, PyObject *value) { @@ -2365,9 +2383,11 @@ static PyObject *gPyEventToString(PyObject *, PyObject *value) return ret; } -static char gPyEventToCharacter_doc[] = -"EventToCharacter(event, is_shift) - Take a valid event from the GameKeys module or Keyboard Sensor and return a character" -; + +PyDoc_STRVAR(gPyEventToCharacter_doc, +"EventToCharacter(event, is_shift)\n" +"Take a valid event from the GameKeys module or Keyboard Sensor and return a character" +); static PyObject *gPyEventToCharacter(PyObject *, PyObject *args) { @@ -2393,7 +2413,7 @@ static struct PyMethodDef gamekeys_methods[] = { }; static struct PyModuleDef GameKeys_module_def = { - {}, /* m_base */ + PyModuleDef_HEAD_INIT, "GameKeys", /* m_name */ GameKeys_module_documentation, /* m_doc */ 0, /* m_size */ @@ -2404,24 +2424,13 @@ static struct PyModuleDef GameKeys_module_def = { 0, /* m_free */ }; -PyObject *initGameKeys() +PyMODINIT_FUNC initGameKeysPythonBinding() { PyObject *m; PyObject *d; - - /* Use existing module where possible */ - m = PyImport_ImportModule( "GameKeys" ); - if (m) { - Py_DECREF(m); - return m; - } - else { - PyErr_Clear(); - - // Create the module and add the functions - m = PyModule_Create(&GameKeys_module_def); - PyDict_SetItemString(PySys_GetObject("modules"), GameKeys_module_def.m_name, m); - } + + m = PyModule_Create(&GameKeys_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), GameKeys_module_def.m_name, m); // Add some symbolic constants to the module d = PyModule_GetDict(m); @@ -2566,9 +2575,80 @@ PyObject *initGameKeys() Py_FatalError("can't initialize module GameKeys"); } - return d; + return m; +} + + + +/* ------------------------------------------------------------------------- */ +/* Application: application values that remain unchanged during runtime */ +/* ------------------------------------------------------------------------- */ + +PyDoc_STRVAR(Application_module_documentation, + "This module contains application values that remain unchanged during runtime." + ); + +static struct PyModuleDef Application_module_def = { + PyModuleDef_HEAD_INIT, + "bge.app", /* m_name */ + Application_module_documentation, /* m_doc */ + 0, /* m_size */ + NULL, /* m_methods */ + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ +}; + +PyMODINIT_FUNC initApplicationPythonBinding() +{ + PyObject *m; + PyObject *d; + + m = PyModule_Create(&Application_module_def); + + // Add some symbolic constants to the module + d = PyModule_GetDict(m); + + PyDict_SetItemString(d, "version", Py_BuildValue("(iii)", + BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); + PyDict_SetItemString(d, "version_string", PyUnicode_FromFormat("%d.%02d (sub %d)", + BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); + PyDict_SetItemString(d, "version_char", PyUnicode_FromString( + STRINGIFY(BLENDER_VERSION_CHAR))); + + PyDict_SetItemString(d, "has_texture_ffmpeg", +#ifdef WITH_FFMPEG + Py_True +#else + Py_False +#endif + ); + PyDict_SetItemString(d, "has_joystick", +#ifdef WITH_SDL + Py_True +#else + Py_False +#endif + ); + PyDict_SetItemString(d, "has_physics", +#ifdef WITH_BULLET + Py_True +#else + Py_False +#endif + ); + + // Check for errors + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + + return m; } + // utility function for loading and saving the globalDict int saveGamePythonConfig( char **marshal_buffer) { diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h index 719a74ee219..6550934a916 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.h +++ b/source/gameengine/Ketsji/KX_PythonInit.h @@ -32,10 +32,13 @@ #ifndef __KX_PYTHONINIT_H__ #define __KX_PYTHONINIT_H__ -#include "KX_Python.h" +#include "EXP_Python.h" #include "STR_String.h" #include "MT_Vector3.h" +class KX_KetsjiEngine; +class KX_Scene; + typedef enum { psl_Lowest = 0, psl_Highest, @@ -44,13 +47,14 @@ typedef enum { extern bool gUseVisibilityTemp; #ifdef WITH_PYTHON -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, - struct Main *maggie, int argc, char **argv); -PyObject *initVideoTexture(void); -PyObject *initGamePythonScripting(const STR_String &progname, TPythonSecurityLevel level, struct Main *maggie); +PyMODINIT_FUNC initBGE(void); +PyMODINIT_FUNC initApplicationPythonBinding(void); +PyMODINIT_FUNC initGameLogicPythonBinding(void); +PyMODINIT_FUNC initGameKeysPythonBinding(void); +PyMODINIT_FUNC initRasterizerPythonBinding(void); +PyMODINIT_FUNC initVideoTexturePythonBinding(void); +PyObject *initGamePlayerPythonScripting(struct Main *maggie, int argc, char **argv); +PyObject *initGamePythonScripting(struct Main *maggie); void exitGamePlayerPythonScripting(); void exitGamePythonScripting(); @@ -69,9 +73,9 @@ void removeImportMain(struct Main *maggie); class KX_KetsjiEngine; class KX_Scene; -void KX_SetActiveScene(class KX_Scene *scene); -class KX_Scene *KX_GetActiveScene(); -class KX_KetsjiEngine *KX_GetActiveEngine(); +void KX_SetActiveScene(KX_Scene *scene); +KX_Scene *KX_GetActiveScene(); +KX_KetsjiEngine *KX_GetActiveEngine(); typedef int (*PyNextFrameFunc)(void *); diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp index 7d38ce58eee..ef6ad4712a5 100644 --- a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp +++ b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp @@ -40,6 +40,7 @@ #include "BL_ArmatureConstraint.h" #include "BL_ArmatureObject.h" #include "BL_ArmatureChannel.h" +#include "KX_WorldInfo.h" #include "KX_ArmatureSensor.h" #include "KX_BlenderMaterial.h" #include "KX_CameraActuator.h" @@ -163,21 +164,34 @@ static void PyType_Ready_ADD(PyObject *dict, PyTypeObject *tp, PyAttributeDef *a #define PyType_Ready_Attr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, NULL, i) #define PyType_Ready_AttrPtr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, n::AttributesPtr, i) -void initPyTypes(void) + + +PyDoc_STRVAR(GameTypes_module_documentation, +"This module provides access to the game engine data types." +); +static struct PyModuleDef GameTypes_module_def = { + PyModuleDef_HEAD_INIT, + "GameTypes", /* m_name */ + GameTypes_module_documentation, /* m_doc */ + 0, /* m_size */ + NULL, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + + +PyMODINIT_FUNC initGameTypesPythonBinding(void) { + PyObject *m; + PyObject *dict; -/* - * initPyObjectPlusType(BL_ActionActuator::Parents); - * ..... - */ + m = PyModule_Create(&GameTypes_module_def); + PyDict_SetItemString(PySys_GetObject("modules"), GameTypes_module_def.m_name, m); + + dict = PyModule_GetDict(m); - /* For now just do PyType_Ready */ - PyObject *mod = PyModule_New("GameTypes"); - PyObject *dict = PyModule_GetDict(mod); - PyDict_SetItemString(PySys_GetObject("modules"), "GameTypes", mod); - Py_DECREF(mod); - - for (int init_getset= 1; init_getset > -1; init_getset--) { /* run twice, once to init the getsets another to run PyType_Ready */ PyType_Ready_Attr(dict, BL_ActionActuator, init_getset); PyType_Ready_Attr(dict, BL_Shader, init_getset); @@ -218,6 +232,7 @@ void initPyTypes(void) PyType_Ready_Attr(dict, KX_SCA_EndObjectActuator, init_getset); PyType_Ready_Attr(dict, KX_SCA_ReplaceMeshActuator, init_getset); PyType_Ready_Attr(dict, KX_Scene, init_getset); + PyType_Ready_Attr(dict, KX_WorldInfo, init_getset); PyType_Ready_Attr(dict, KX_NavMeshObject, init_getset); PyType_Ready_Attr(dict, KX_SceneActuator, init_getset); PyType_Ready_Attr(dict, KX_SoundActuator, init_getset); @@ -266,7 +281,11 @@ void initPyTypes(void) /* Init mathutils callbacks */ KX_GameObject_Mathutils_Callback_Init(); KX_ObjectActuator_Mathutils_Callback_Init(); + KX_WorldInfo_Mathutils_Callback_Init(); + KX_BlenderMaterial_Mathutils_Callback_Init(); #endif + + return m; } #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.h b/source/gameengine/Ketsji/KX_PythonInitTypes.h index d8ee4f75fdd..cfc49a1dc93 100644 --- a/source/gameengine/Ketsji/KX_PythonInitTypes.h +++ b/source/gameengine/Ketsji/KX_PythonInitTypes.h @@ -33,7 +33,8 @@ #define __KX_PYTHON_INIT_TYPES__ #ifdef WITH_PYTHON -void initPyTypes(void); +#include <Python.h> +PyMODINIT_FUNC initGameTypesPythonBinding(void); #endif #endif /* __KX_PYTHON_INIT_TYPES__ */ diff --git a/source/gameengine/Ketsji/KX_PythonSeq.h b/source/gameengine/Ketsji/KX_PythonSeq.h index 568d59119c0..33b5335ddf4 100644 --- a/source/gameengine/Ketsji/KX_PythonSeq.h +++ b/source/gameengine/Ketsji/KX_PythonSeq.h @@ -35,7 +35,7 @@ #ifdef WITH_PYTHON -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" // ------------------------- enum KX_PYGENSEQ_TYPE { diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp index 0f47dfd922b..c97d233a67b 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.cpp +++ b/source/gameengine/Ketsji/KX_RaySensor.cpp @@ -46,6 +46,7 @@ #include "PHY_IPhysicsEnvironment.h" #include "PHY_IPhysicsController.h" #include "DNA_sensor_types.h" +#include "RAS_MeshObject.h" #include <stdio.h> @@ -111,6 +112,7 @@ bool KX_RaySensor::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void KX_GameObject* hitKXObj = client->m_gameobject; bool bFound = false; + bool hitMaterial = false; if (m_propertyname.Length() == 0) { @@ -118,15 +120,19 @@ bool KX_RaySensor::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void } else { - if (m_bFindMaterial) - { - if (client->m_auxilary_info) - { - bFound = (m_propertyname== ((char*)client->m_auxilary_info)); + if (m_bFindMaterial) { + for (unsigned int i = 0; i < hitKXObj->GetMeshCount(); ++i) { + RAS_MeshObject *meshObj = hitKXObj->GetMesh(i); + for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { + bFound = strcmp(m_propertyname.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; + if (bFound) { + hitMaterial = true; + break; + } + } } } - else - { + else { bFound = hitKXObj->GetProperty(m_propertyname) != NULL; } } @@ -143,7 +149,7 @@ bool KX_RaySensor::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void m_hitNormal[1] = result->m_hitNormal[1]; m_hitNormal[2] = result->m_hitNormal[2]; - m_hitMaterial = (client->m_auxilary_info ? (char*)client->m_auxilary_info : ""); + m_hitMaterial = hitMaterial; } // no multi-hit search yet return true; @@ -154,6 +160,8 @@ bool KX_RaySensor::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void */ bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo *client) { + KX_GameObject *hitKXObj = client->m_gameobject; + if (client->m_type > KX_ClientObjectInfo::ACTOR) { // Unknown type of object, skip it. @@ -163,16 +171,21 @@ bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo *client) } 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))) + if (m_bFindMaterial) { + bool found = false; + for (unsigned int i = 0; i < hitKXObj->GetMeshCount(); ++i) { + RAS_MeshObject *meshObj = hitKXObj->GetMesh(i); + for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { + found = strcmp(m_propertyname.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; + if (found) + break; + } + } + if (!found) return false; } - else - { - if (client->m_gameobject->GetProperty(m_propertyname) == NULL) + else { + if (hitKXObj->GetProperty(m_propertyname) == NULL) return false; } } diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp index f8f79269eaa..fdcfd22270b 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp @@ -38,7 +38,7 @@ #include "KX_SCA_AddObjectActuator.h" #include "SCA_IScene.h" #include "KX_GameObject.h" -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" /* ------------------------------------------------------------------------- */ /* Native functions */ diff --git a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp index e02eca3db63..96e1cc29de3 100644 --- a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp @@ -121,7 +121,9 @@ bool KX_SCA_DynamicActuator::Update() switch (m_dyn_operation) { case 0: - controller->RestoreDynamics(); + // Child objects must be static, so we block changing to dynamic + if (!obj->GetParent()) + controller->RestoreDynamics(); break; case 1: controller->SuspendDynamics(); diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp index b105256836b..6b6b090c1c4 100644 --- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp @@ -43,7 +43,7 @@ #include "KX_SCA_ReplaceMeshActuator.h" #include "KX_MeshProxy.h" -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" #ifdef WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index d0eab9de1c1..723736906a9 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -35,6 +35,8 @@ # pragma warning (disable:4786) #endif +#include <stdio.h> + #include "KX_Scene.h" #include "KX_PythonInit.h" #include "MT_assert.h" @@ -42,7 +44,7 @@ #include "KX_BlenderMaterial.h" #include "KX_FontObject.h" #include "RAS_IPolygonMaterial.h" -#include "ListValue.h" +#include "EXP_ListValue.h" #include "SCA_LogicManager.h" #include "SCA_TimeEventManager.h" //#include "SCA_AlwaysEventManager.h" @@ -66,7 +68,7 @@ #include "RAS_ICanvas.h" #include "RAS_BucketManager.h" -#include "FloatValue.h" +#include "EXP_FloatValue.h" #include "SCA_IController.h" #include "SCA_IActuator.h" #include "SG_Node.h" @@ -94,12 +96,14 @@ #include "KX_ObstacleSimulation.h" #ifdef WITH_BULLET -#include "KX_SoftBodyDeformer.h" +# include "KX_SoftBodyDeformer.h" #endif -#include "KX_Light.h" +#ifdef WITH_PYTHON +# include "EXP_PythonCallBack.h" +#endif -#include <stdio.h> +#include "KX_Light.h" #include "BLI_task.h" @@ -156,7 +160,9 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_networkDeviceInterface(ndi), m_active_camera(NULL), m_ueberExecutionPriority(0), - m_blenderScene(scene) + m_blenderScene(scene), + m_isActivedHysteresis(false), + m_lodHysteresisValue(0) { m_suspendedtime = 0.0; m_suspendeddelta = 0.0; @@ -218,7 +224,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_bucketmanager=new RAS_BucketManager(); - bool showObstacleSimulation = scene->gm.flag & GAME_SHOW_OBSTACLE_SIMULATION; + bool showObstacleSimulation = (scene->gm.flag & GAME_SHOW_OBSTACLE_SIMULATION) != 0; switch (scene->gm.obstacleSimulation) { case OBSTSIMULATION_TOI_rays: @@ -235,6 +241,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_attr_dict = NULL; m_draw_call_pre = NULL; m_draw_call_post = NULL; + m_draw_setup_call_pre = NULL; #endif } @@ -532,6 +539,8 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal m_objectlist->Add(newobj->AddRef()); if (newobj->GetGameObjectType()==SCA_IObject::OBJ_LIGHT) m_lightlist->Add(newobj->AddRef()); + else if (newobj->GetGameObjectType()==SCA_IObject::OBJ_TEXT) + AddFont((KX_FontObject*)newobj); newobj->AddMeshUser(); // logic cannot be replicated, until the whole hierarchy is replicated. @@ -575,6 +584,10 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal newctrl->SetNewClientInfo(newobj->getClientInfo()); newobj->SetPhysicsController(newctrl, newobj->IsDynamic()); newctrl->PostProcessReplica(motionstate, parentctrl); + + // Child objects must be static + if (parent) + newctrl->SuspendDynamics(); } return newobj; @@ -803,13 +816,6 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) // we can now add the graphic controller to the physic engine replica->ActivateGraphicController(true); - // set references for dupli-group - // groupobj holds a list of all objects, that belongs to this group - groupobj->AddInstanceObjects(replica); - - // every object gets the reference to its dupli-group object - replica->SetDupliGroupObject(groupobj); - // done with replica replica->Release(); } @@ -829,12 +835,6 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) (*git)->Relink(&m_map_gameobject_to_replica); // add the object in the layer of the parent (*git)->SetLayer(groupobj->GetLayer()); - // If the object was a light, we need to update it's RAS_LightObject as well - if ((*git)->GetGameObjectType()==SCA_IObject::OBJ_LIGHT) - { - KX_LightObject* lightobj = static_cast<KX_LightObject*>(*git); - lightobj->SetLayer(groupobj->GetLayer()); - } } // replicate crosslinks etc. between logic bricks @@ -846,9 +846,24 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) // now look if object in the hierarchy have dupli group and recurse for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) { + /* Replicate all constraints. */ + if ((*git)->GetPhysicsController()) { + (*git)->GetPhysicsController()->ReplicateConstraints((*git), m_logicHierarchicalGameObjects); + (*git)->ClearConstraints(); + } + if ((*git) != groupobj && (*git)->IsDupliGroup()) // can't instantiate group immediately as it destroys m_logicHierarchicalGameObjects duplilist.push_back((*git)); + + if ((*git)->GetBlenderGroupObject() == blgroupobj) { + // set references for dupli-group + // groupobj holds a list of all objects, that belongs to this group + groupobj->AddInstanceObjects((*git)); + + // every object gets the reference to its dupli-group object + (*git)->SetDupliGroupObject(groupobj); + } } for (git = duplilist.begin(); !(git == duplilist.end()); ++git) @@ -859,7 +874,7 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level) SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, - class CValue* parentobject, + class CValue* referenceobject, int lifespan) { @@ -867,19 +882,18 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, 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' KX_GameObject* originalobj = (KX_GameObject*) originalobject; - KX_GameObject* parentobj = (KX_GameObject*) parentobject; + KX_GameObject* referenceobj = (KX_GameObject*) referenceobject; m_ueberExecutionPriority++; // lets create a replica KX_GameObject* replica = (KX_GameObject*) AddNodeReplicaObject(NULL,originalobj); + // add a timebomb to this object + // lifespan of zero means 'this object lives forever' if (lifespan > 0) { - // add a timebomb to this object // for now, convert between so called frames and realtime m_tempObjectList->Add(replica->AddRef()); // this convert the life from frames to sort-of seconds, hard coded 0.02 that assumes we have 50 frames per second @@ -905,19 +919,20 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, replica->GetSGNode()->AddChild(childreplicanode); } - // At this stage all the objects in the hierarchy have been duplicated, - // we can update the scenegraph, we need it for the duplication of logic - MT_Point3 newpos = ((KX_GameObject*) parentobject)->NodeGetWorldPosition(); - replica->NodeSetLocalPosition(newpos); + if (referenceobj) { + // At this stage all the objects in the hierarchy have been duplicated, + // we can update the scenegraph, we need it for the duplication of logic + MT_Point3 newpos = referenceobj->NodeGetWorldPosition(); + replica->NodeSetLocalPosition(newpos); - MT_Matrix3x3 newori = ((KX_GameObject*) parentobject)->NodeGetWorldOrientation(); - replica->NodeSetLocalOrientation(newori); - - // get the rootnode's scale - MT_Vector3 newscale = parentobj->GetSGNode()->GetRootSGParent()->GetLocalScale(); + MT_Matrix3x3 newori = referenceobj->NodeGetWorldOrientation(); + replica->NodeSetLocalOrientation(newori); - // set the replica's relative scale with the rootnode's scale - replica->NodeSetRelativeScale(newscale); + // get the rootnode's scale + MT_Vector3 newscale = referenceobj->GetSGNode()->GetRootSGParent()->GetLocalScale(); + // set the replica's relative scale with the rootnode's scale + replica->NodeSetRelativeScale(newscale); + } replica->GetSGNode()->UpdateWorldData(0); replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox()); @@ -937,13 +952,13 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, { // 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()); - // If the object was a light, we need to update it's RAS_LightObject as well - if ((*git)->GetGameObjectType()==SCA_IObject::OBJ_LIGHT) - { - KX_LightObject* lightobj = static_cast<KX_LightObject*>(*git); - lightobj->SetLayer(parentobj->GetLayer()); + if (referenceobj) { + // add the object in the layer of the reference object + (*git)->SetLayer(referenceobj->GetLayer()); + } + else { + // We don't know what layer set, so we set all visible layers in the blender scene. + (*git)->SetLayer(m_blenderScene->lay); } } @@ -1078,6 +1093,16 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) group->RemoveInstanceObject(newobj); newobj->RemoveMeshes(); + + switch (newobj->GetGameObjectType()) { + case SCA_IObject::OBJ_CAMERA: + m_cameras.remove((KX_Camera *)newobj); + break; + case SCA_IObject::OBJ_TEXT: + m_fonts.remove((KX_FontObject *)newobj); + break; + } + ret = 1; if (newobj->GetGameObjectType()==SCA_IObject::OBJ_LIGHT && m_lightlist->RemoveValue(newobj)) ret = newobj->Release(); @@ -1093,7 +1118,10 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) ret = newobj->Release(); if (m_animatedlist->RemoveValue(newobj)) ret = newobj->Release(); - + + /* Warning 'newobj' maye be freed now, only compare, don't access */ + + if (newobj == m_active_camera) { //no AddRef done on m_active_camera so no Release @@ -1101,12 +1129,6 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) m_active_camera = NULL; } - // in case this is a camera - m_cameras.remove((KX_Camera*)newobj); - - // in case this is a font - m_fonts.remove((KX_FontObject*)newobj); - /* currently does nothing, keep in case we need to Unregister something */ #if 0 if (m_sceneConverter) @@ -1502,6 +1524,15 @@ void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int bool dbvt_culling = false; if (m_dbvt_culling) { + /* Reset KX_GameObject m_bCulled to true before doing culling + * since DBVT culling will only set it to false. + * This is similar to what RAS_BucketManager does for RAS_MeshSlot culling. + */ + for (int i = 0; i < m_objectlist->GetCount(); i++) { + KX_GameObject *gameobj = static_cast<KX_GameObject*>(m_objectlist->GetValue(i)); + gameobj->SetCulled(true); + } + // test culling through Bullet MT_Vector4 planes[6]; // get the clip planes @@ -1531,9 +1562,6 @@ void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam, layer); } } - - // Now that we know visible meshes, update LoDs - UpdateObjectLods(); } // logic stuff @@ -1642,20 +1670,6 @@ static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(t void KX_Scene::UpdateAnimations(double curtime) { - KX_KetsjiEngine *engine = KX_GetActiveEngine(); - - if (engine->GetRestrictAnimationFPS()) - { - // Handle the animations independently of the logic time step - double anim_timestep = 1.0 / GetAnimationFPS(); - if (curtime - m_previousAnimTime < anim_timestep) - return; - - // Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep) - // printf("Anim fps: %f\n", 1.0/(m_clockTime - m_previousAnimTime)); - m_previousAnimTime = curtime; - } - TaskPool *pool = BLI_task_pool_create(KX_GetActiveEngine()->GetTaskScheduler(), &curtime); for (int i=0; i<m_animatedlist->GetCount(); ++i) { @@ -1755,6 +1769,10 @@ void KX_Scene::RenderFonts() void KX_Scene::UpdateObjectLods(void) { KX_GameObject* gameobj; + + if (!this->m_active_camera) + return; + MT_Vector3 cam_pos = this->m_active_camera->NodeGetWorldPosition(); for (int i = 0; i < this->GetObjectList()->GetCount(); i++) { @@ -1765,6 +1783,26 @@ void KX_Scene::UpdateObjectLods(void) } } +void KX_Scene::SetLodHysteresis(bool active) +{ + m_isActivedHysteresis = active; +} + +bool KX_Scene::IsActivedLodHysteresis(void) +{ + return m_isActivedHysteresis; +} + +void KX_Scene::SetLodHysteresisValue(int hysteresisvalue) +{ + m_lodHysteresisValue = hysteresisvalue; +} + +int KX_Scene::GetLodHysteresisValue(void) +{ + return m_lodHysteresisValue; +} + void KX_Scene::UpdateObjectActivity(void) { if (m_activity_culling) { @@ -1881,15 +1919,6 @@ static void MergeScene_LogicBrick(SCA_ILogicBrick* brick, KX_Scene *from, KX_Sce brick->Replace_IScene(to); brick->Replace_NetworkScene(to->GetNetworkScene()); - /* near sensors have physics controllers */ - KX_TouchSensor *touch_sensor = dynamic_cast<class KX_TouchSensor *>(brick); - if (touch_sensor) { - KX_TouchEventManager *tmgr = (KX_TouchEventManager*)from->GetLogicManager()->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR); - touch_sensor->UnregisterSumo(tmgr); - touch_sensor->GetPhysicsController()->SetPhysicsEnvironment(to->GetPhysicsEnvironment()); - touch_sensor->RegisterSumo(tmgr); - } - // If we end up replacing a KX_TouchEventManager, we need to make sure // physics controllers are properly in place. In other words, do this // after merging physics controllers! @@ -1948,17 +1977,6 @@ static void MergeScene_GameObject(KX_GameObject* gameobj, KX_Scene *to, KX_Scene { SCA_IController *cont= *itc; MergeScene_LogicBrick(cont, from, to); - - vector<SCA_ISensor*> linkedsensors = cont->GetLinkedSensors(); - vector<SCA_IActuator*> linkedactuators = cont->GetLinkedActuators(); - - for (vector<SCA_IActuator*>::iterator ita = linkedactuators.begin();!(ita==linkedactuators.end());++ita) { - MergeScene_LogicBrick(*ita, from, to); - } - - for (vector<SCA_ISensor*>::iterator its = linkedsensors.begin();!(its==linkedsensors.end());++its) { - MergeScene_LogicBrick(*its, from, to); - } } } @@ -1993,12 +2011,20 @@ static void MergeScene_GameObject(KX_GameObject* gameobj, KX_Scene *to, KX_Scene if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_CAMERA) to->AddCamera((KX_Camera*)gameobj); + // All armatures should be in the animated object list to be umpdated. + if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) + to->AddAnimatedObject(gameobj); + /* Add the object to the scene's logic manager */ to->GetLogicManager()->RegisterGameObjectName(gameobj->GetName(), gameobj); to->GetLogicManager()->RegisterGameObj(gameobj->GetBlenderObject(), gameobj); - for (int i=0; i<gameobj->GetMeshCount(); ++i) - to->GetLogicManager()->RegisterGameMeshName(gameobj->GetMesh(i)->GetName(), gameobj->GetBlenderObject()); + for (int i = 0; i < gameobj->GetMeshCount(); ++i) { + RAS_MeshObject *meshobj = gameobj->GetMesh(i); + // Register the mesh object by name and blender object. + to->GetLogicManager()->RegisterGameMeshName(meshobj->GetName(), gameobj->GetBlenderObject()); + to->GetLogicManager()->RegisterMeshName(meshobj->GetName(), meshobj); + } } bool KX_Scene::MergeScene(KX_Scene *other) @@ -2042,6 +2068,28 @@ bool KX_Scene::MergeScene(KX_Scene *other) MergeScene_GameObject(gameobj, this, other); } + if (env) { + env->MergeEnvironment(env_other); + CListValue *otherObjects = other->GetObjectList(); + + // List of all physics objects to merge (needed by ReplicateConstraints). + std::vector<KX_GameObject *> physicsObjects; + for (unsigned int i = 0; i < otherObjects->GetCount(); ++i) { + KX_GameObject *gameobj = (KX_GameObject *)otherObjects->GetValue(i); + if (gameobj->GetPhysicsController()) { + physicsObjects.push_back(gameobj); + } + } + + for (unsigned int i = 0; i < physicsObjects.size(); ++i) { + KX_GameObject *gameobj = physicsObjects[i]; + // Replicate all constraints in the right physics environment. + gameobj->GetPhysicsController()->ReplicateConstraints(gameobj, physicsObjects); + gameobj->ClearConstraints(); + } + } + + GetTempObjectList()->MergeList(other->GetTempObjectList()); other->GetTempObjectList()->ReleaseAndRemoveAll(); @@ -2057,9 +2105,6 @@ bool KX_Scene::MergeScene(KX_Scene *other) GetLightList()->MergeList(other->GetLightList()); other->GetLightList()->ReleaseAndRemoveAll(); - if (env) - env->MergeEnvironment(env_other); - /* move materials across, assume they both use the same scene-converters * Do this after lights are merged so materials can use the lights in shaders */ @@ -2112,30 +2157,10 @@ void KX_Scene::Render2DFilters(RAS_ICanvas* canvas) void KX_Scene::RunDrawingCallbacks(PyObject *cb_list) { - Py_ssize_t len; - - if (cb_list && (len=PyList_GET_SIZE(cb_list))) - { - PyObject *args = PyTuple_New(0); // save python creating each call - PyObject *func; - PyObject *ret; - - // Iterate the list and run the callbacks - for (Py_ssize_t pos=0; pos < len; pos++) - { - func= PyList_GET_ITEM(cb_list, pos); - ret= PyObject_Call(func, args, NULL); - if (ret==NULL) { - PyErr_Print(); - PyErr_Clear(); - } - else { - Py_DECREF(ret); - } - } + if (!cb_list || PyList_GET_SIZE(cb_list) == 0) + return; - Py_DECREF(args); - } + RunPythonCallBackList(cb_list, NULL, 0, 0); } //---------------------------------------------------------------------------- @@ -2321,6 +2346,19 @@ PyObject *KX_Scene::pyattr_get_lights(void *self_v, const KX_PYATTRIBUTE_DEF *at return self->GetLightList()->GetProxy(); } +PyObject *KX_Scene::pyattr_get_world(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene* self = static_cast<KX_Scene*>(self_v); + KX_WorldInfo *world = self->GetWorldInfo(); + + if (world->GetName() != "") { + return world->GetProxy(); + } + else { + Py_RETURN_NONE; + } +} + PyObject *KX_Scene::pyattr_get_cameras(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { /* With refcounts in this case... @@ -2385,6 +2423,17 @@ PyObject *KX_Scene::pyattr_get_drawing_callback_post(void *self_v, const KX_PYAT return self->m_draw_call_post; } +PyObject *KX_Scene::pyattr_get_drawing_setup_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene* self = static_cast<KX_Scene*>(self_v); + + if (self->m_draw_setup_call_pre == NULL) + self->m_draw_setup_call_pre = PyList_New(0); + + Py_INCREF(self->m_draw_setup_call_pre); + return self->m_draw_setup_call_pre; +} + int KX_Scene::pyattr_set_drawing_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_Scene* self = static_cast<KX_Scene*>(self_v); @@ -2419,6 +2468,22 @@ int KX_Scene::pyattr_set_drawing_callback_post(void *self_v, const KX_PYATTRIBUT return PY_SET_ATTR_SUCCESS; } +int KX_Scene::pyattr_set_drawing_setup_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Scene* self = static_cast<KX_Scene*>(self_v); + + if (!PyList_CheckExact(value)) { + PyErr_SetString(PyExc_ValueError, "Expected a list"); + return PY_SET_ATTR_FAIL; + } + + Py_XDECREF(self->m_draw_setup_call_pre); + Py_INCREF(value); + + self->m_draw_setup_call_pre = value; + return PY_SET_ATTR_SUCCESS; +} + PyObject *KX_Scene::pyattr_get_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_Scene* self = static_cast<KX_Scene*>(self_v); @@ -2444,9 +2509,11 @@ PyAttributeDef KX_Scene::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("objectsInactive", KX_Scene, pyattr_get_objects_inactive), KX_PYATTRIBUTE_RO_FUNCTION("lights", KX_Scene, pyattr_get_lights), KX_PYATTRIBUTE_RO_FUNCTION("cameras", KX_Scene, pyattr_get_cameras), + KX_PYATTRIBUTE_RO_FUNCTION("world", KX_Scene, pyattr_get_world), KX_PYATTRIBUTE_RW_FUNCTION("active_camera", KX_Scene, pyattr_get_active_camera, pyattr_set_active_camera), KX_PYATTRIBUTE_RW_FUNCTION("pre_draw", KX_Scene, pyattr_get_drawing_callback_pre, pyattr_set_drawing_callback_pre), KX_PYATTRIBUTE_RW_FUNCTION("post_draw", KX_Scene, pyattr_get_drawing_callback_post, pyattr_set_drawing_callback_post), + KX_PYATTRIBUTE_RW_FUNCTION("pre_draw_setup", KX_Scene, pyattr_get_drawing_setup_callback_pre, pyattr_set_drawing_setup_callback_pre), KX_PYATTRIBUTE_RW_FUNCTION("gravity", KX_Scene, pyattr_get_gravity, pyattr_set_gravity), KX_PYATTRIBUTE_BOOL_RO("suspended", KX_Scene, m_suspend), KX_PYATTRIBUTE_BOOL_RO("activity_culling", KX_Scene, m_activity_culling), @@ -2459,23 +2526,23 @@ KX_PYMETHODDEF_DOC(KX_Scene, addObject, "addObject(object, other, time=0)\n" "Returns the added object.\n") { - PyObject *pyob, *pyother; - KX_GameObject *ob, *other; + PyObject *pyob, *pyreference = Py_None; + KX_GameObject *ob, *reference; int time = 0; - if (!PyArg_ParseTuple(args, "OO|i:addObject", &pyob, &pyother, &time)) + if (!PyArg_ParseTuple(args, "O|Oi:addObject", &pyob, &pyreference, &time)) return NULL; - if ( !ConvertPythonToGameObject(pyob, &ob, false, "scene.addObject(object, other, time): KX_Scene (first argument)") || - !ConvertPythonToGameObject(pyother, &other, false, "scene.addObject(object, other, time): KX_Scene (second argument)") ) + if (!ConvertPythonToGameObject(pyob, &ob, false, "scene.addObject(object, reference, time): KX_Scene (first argument)") || + !ConvertPythonToGameObject(pyreference, &reference, true, "scene.addObject(object, reference, time): KX_Scene (second argument)")) return NULL; if (!m_inactivelist->SearchValue(ob)) { - PyErr_Format(PyExc_ValueError, "scene.addObject(object, other, time): KX_Scene (first argument): object must be in an inactive layer"); + PyErr_Format(PyExc_ValueError, "scene.addObject(object, reference, time): KX_Scene (first argument): object must be in an inactive layer"); return NULL; } - SCA_IObject* replica = AddReplicaObject((SCA_IObject*)ob, other, time); + SCA_IObject *replica = AddReplicaObject((SCA_IObject*)ob, reference, time); // release here because AddReplicaObject AddRef's // the object is added to the scene so we don't want python to own a reference diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index c5840c28041..4f7ad98f30d 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -49,7 +49,7 @@ #include "RAS_Rect.h" -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" #include "RAS_2DFilterManager.h" /** @@ -107,6 +107,7 @@ class KX_Scene : public PyObjectPlus, public SCA_IScene PyObject* m_attr_dict; PyObject* m_draw_call_pre; PyObject* m_draw_call_post; + PyObject* m_draw_setup_call_pre; #endif struct CullingInfo { @@ -289,14 +290,18 @@ protected: double m_suspendedtime; double m_suspendeddelta; - double m_previousAnimTime; //the last time animations were updated - struct Scene* m_blenderScene; RAS_2DFilterManager m_filtermanager; KX_ObstacleSimulation* m_obstacleSimulation; + /** + * LOD Hysteresis settings + */ + bool m_isActivedHysteresis; + int m_lodHysteresisValue; + public: KX_Scene(class SCA_IInputDevice* keyboarddevice, class SCA_IInputDevice* mousedevice, @@ -548,6 +553,12 @@ public: // Update the mesh for objects based on level of detail settings void UpdateObjectLods(void); + + // LoD Hysteresis functions + void SetLodHysteresis(bool active); + bool IsActivedLodHysteresis(); + void SetLodHysteresisValue(int hysteresisvalue); + int GetLodHysteresisValue(); // Update the activity box settings for objects in this scene, if needed. void UpdateObjectActivity(void); @@ -614,12 +625,15 @@ public: static PyObject* pyattr_get_objects_inactive(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_lights(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_cameras(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_world(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_active_camera(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_drawing_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_drawing_callback_pre(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_drawing_callback_post(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_drawing_callback_post(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_drawing_setup_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_drawing_setup_callback_pre(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_gravity(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); @@ -636,6 +650,7 @@ public: PyObject *GetPreDrawCB() { return m_draw_call_pre; } PyObject *GetPostDrawCB() { return m_draw_call_post; } + PyObject *GetPreDrawSetupCB() { return m_draw_setup_call_pre; } #endif /** diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index 4e5cd0ac5e1..02b1071e267 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -37,10 +37,14 @@ #include "KX_SoundActuator.h" #ifdef WITH_AUDASPACE -# include "AUD_C-API.h" -# include "AUD_PingPongFactory.h" -# include "AUD_IDevice.h" -# include "AUD_I3DHandle.h" +# ifdef WITH_SYSTEM_AUDASPACE +typedef float sample_t; +# include AUD_PYTHON_H +# endif +# include AUD_SOUND_H +# include AUD_SPECIAL_H +# include AUD_DEVICE_H +# include AUD_HANDLE_H #endif #include "KX_GameObject.h" @@ -53,7 +57,7 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, - boost::shared_ptr<AUD_IFactory> sound, + AUD_Sound* sound, float volume, float pitch, bool is3d, @@ -61,7 +65,8 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, KX_SOUNDACT_TYPE type)//, : SCA_IActuator(gameobj, KX_ACT_SOUND) { - m_sound = sound; + m_sound = AUD_Sound_copy(sound); + m_handle = NULL; m_volume = volume; m_pitch = pitch; m_is3d = is3d; @@ -74,20 +79,30 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, KX_SoundActuator::~KX_SoundActuator() { - if (m_handle.get()) - m_handle->stop(); + if(m_handle) + { + AUD_Handle_stop(m_handle); + } + + if(m_sound) + { + AUD_Sound_free(m_sound); + } } void KX_SoundActuator::play() { - if (m_handle.get()) - m_handle->stop(); + if(m_handle) + { + AUD_Handle_stop(m_handle); + m_handle = NULL; + } - if (!m_sound.get()) + if (!m_sound) return; // this is the sound that will be played and not deleted afterwards - boost::shared_ptr<AUD_IFactory> sound = m_sound; + AUD_Sound* sound = m_sound; bool loop = false; @@ -95,7 +110,7 @@ void KX_SoundActuator::play() { case KX_SOUNDACT_LOOPBIDIRECTIONAL: case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: - sound = boost::shared_ptr<AUD_IFactory>(new AUD_PingPongFactory(sound)); + sound = AUD_Sound_pingpong(sound); // fall through case KX_SOUNDACT_LOOPEND: case KX_SOUNDACT_LOOPSTOP: @@ -107,36 +122,33 @@ void KX_SoundActuator::play() break; } - try - { - m_handle = AUD_getDevice()->play(sound); - } - catch(AUD_Exception&) - { - // cannot play back, ignore - return; - } + AUD_Device* device = AUD_Device_getCurrent(); + m_handle = AUD_Device_play(device, sound, false); + AUD_Device_free(device); - boost::shared_ptr<AUD_I3DHandle> handle3d = boost::dynamic_pointer_cast<AUD_I3DHandle>(m_handle); + // in case of pingpong, we have to free the sound + if(sound != m_sound) + AUD_Sound_free(sound); - if (m_is3d && handle3d.get()) + if (m_handle != NULL) { - handle3d->setRelative(true); - handle3d->setVolumeMaximum(m_3d.max_gain); - handle3d->setVolumeMinimum(m_3d.min_gain); - handle3d->setDistanceReference(m_3d.reference_distance); - handle3d->setDistanceMaximum(m_3d.max_distance); - handle3d->setAttenuation(m_3d.rolloff_factor); - handle3d->setConeAngleInner(m_3d.cone_inner_angle); - handle3d->setConeAngleOuter(m_3d.cone_outer_angle); - handle3d->setConeVolumeOuter(m_3d.cone_outer_gain); - } + if (m_is3d) + { + AUD_Handle_setRelative(m_handle, true); + AUD_Handle_setVolumeMaximum(m_handle, m_3d.max_gain); + AUD_Handle_setVolumeMinimum(m_handle, m_3d.min_gain); + AUD_Handle_setDistanceReference(m_handle, m_3d.reference_distance); + AUD_Handle_setDistanceMaximum(m_handle, m_3d.max_distance); + AUD_Handle_setAttenuation(m_handle, m_3d.rolloff_factor); + AUD_Handle_setConeAngleInner(m_handle, m_3d.cone_inner_angle); + AUD_Handle_setConeAngleOuter(m_handle, m_3d.cone_outer_angle); + AUD_Handle_setConeVolumeOuter(m_handle, m_3d.cone_outer_gain); + } - if (m_handle.get()) { if (loop) - m_handle->setLoopCount(-1); - m_handle->setPitch(m_pitch); - m_handle->setVolume(m_volume); + AUD_Handle_setLoopCount(m_handle, -1); + AUD_Handle_setPitch(m_handle, m_pitch); + AUD_Handle_setVolume(m_handle, m_volume); } m_isplaying = true; @@ -152,7 +164,8 @@ CValue* KX_SoundActuator::GetReplica() void KX_SoundActuator::ProcessReplica() { SCA_IActuator::ProcessReplica(); - m_handle = boost::shared_ptr<AUD_IHandle>(); + m_handle = NULL; + m_sound = AUD_Sound_copy(m_sound); } bool KX_SoundActuator::Update(double curtime, bool frame) @@ -167,11 +180,11 @@ bool KX_SoundActuator::Update(double curtime, bool frame) RemoveAllEvents(); - if (!m_sound.get()) + if (!m_sound) return false; // actual audio device playing state - bool isplaying = m_handle.get() ? (m_handle->getStatus() == AUD_STATUS_PLAYING) : false; + bool isplaying = m_handle ? (AUD_Handle_getStatus(m_handle) == AUD_STATUS_PLAYING) : false; if (bNegativeEvent) { @@ -185,9 +198,11 @@ bool KX_SoundActuator::Update(double curtime, bool frame) case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: { // stop immediately - if (m_handle.get()) - m_handle->stop(); - m_handle = boost::shared_ptr<AUD_IHandle>(); + if (m_handle) + { + AUD_Handle_stop(m_handle); + m_handle = NULL; + } break; } case KX_SOUNDACT_PLAYEND: @@ -199,8 +214,8 @@ bool KX_SoundActuator::Update(double curtime, bool frame) case KX_SOUNDACT_LOOPBIDIRECTIONAL: { // stop the looping so that the sound stops when it finished - if (m_handle.get()) - m_handle->setLoopCount(0); + if (m_handle) + AUD_Handle_setLoopCount(m_handle, 0); break; } default: @@ -227,13 +242,11 @@ bool KX_SoundActuator::Update(double curtime, bool frame) play(); } // verify that the sound is still playing - isplaying = m_handle.get() ? (m_handle->getStatus() == AUD_STATUS_PLAYING) : false; + isplaying = m_handle ? (AUD_Handle_getStatus(m_handle) == AUD_STATUS_PLAYING) : false; if (isplaying) { - boost::shared_ptr<AUD_I3DHandle> handle3d = boost::dynamic_pointer_cast<AUD_I3DHandle>(m_handle); - - if (m_is3d && handle3d.get()) + if (m_is3d) { KX_Camera* cam = KX_GetActiveScene()->GetActiveCamera(); if (cam) @@ -241,20 +254,19 @@ bool KX_SoundActuator::Update(double curtime, bool frame) KX_GameObject* obj = (KX_GameObject*)this->GetParent(); MT_Point3 p; MT_Matrix3x3 Mo; - AUD_Vector3 v; - float q[4]; + float data[4]; Mo = cam->NodeGetWorldOrientation().inverse(); p = (obj->NodeGetWorldPosition() - cam->NodeGetWorldPosition()); p = Mo * p; - p.getValue(v.get()); - handle3d->setSourceLocation(v); + p.getValue(data); + AUD_Handle_setLocation(m_handle, data); p = (obj->GetLinearVelocity() - cam->GetLinearVelocity()); p = Mo * p; - p.getValue(v.get()); - handle3d->setSourceVelocity(v); - (Mo * obj->NodeGetWorldOrientation()).getRotation().getValue(q); - handle3d->setSourceOrientation(AUD_Quaternion(q[3], q[0], q[1], q[2])); + p.getValue(data); + AUD_Handle_setVelocity(m_handle, data); + (Mo * obj->NodeGetWorldOrientation()).getRotation().getValue(data); + AUD_Handle_setOrientation(m_handle, data); } } result = true; @@ -329,11 +341,11 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, startSound, "startSound()\n" "\tStarts the sound.\n") { - switch (m_handle.get() ? m_handle->getStatus() : AUD_STATUS_INVALID) { + switch (m_handle ? AUD_Handle_getStatus(m_handle) : AUD_STATUS_INVALID) { case AUD_STATUS_PLAYING: break; case AUD_STATUS_PAUSED: - m_handle->resume(); + AUD_Handle_resume(m_handle); break; default: play(); @@ -345,8 +357,8 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, pauseSound, "pauseSound()\n" "\tPauses the sound.\n") { - if (m_handle.get()) - m_handle->pause(); + if (m_handle) + AUD_Handle_pause(m_handle); Py_RETURN_NONE; } @@ -354,9 +366,11 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, stopSound, "stopSound()\n" "\tStops the sound.\n") { - if (m_handle.get()) - m_handle->stop(); - m_handle = boost::shared_ptr<AUD_IHandle>(); + if (m_handle) + { + AUD_Handle_stop(m_handle); + m_handle = NULL; + } Py_RETURN_NONE; } @@ -404,8 +418,8 @@ PyObject *KX_SoundActuator::pyattr_get_audposition(void *self, const struct KX_P KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); float position = 0.0; - if (actuator->m_handle.get()) - position = actuator->m_handle->getPosition(); + if (actuator->m_handle) + position = AUD_Handle_getPosition(actuator->m_handle); PyObject *result = PyFloat_FromDouble(position); @@ -435,8 +449,8 @@ PyObject *KX_SoundActuator::pyattr_get_pitch(void *self, const struct KX_PYATTRI PyObject *KX_SoundActuator::pyattr_get_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) { KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); - if (actuator->m_sound.get()) - return (PyObject *)AUD_getPythonFactory(&actuator->m_sound); + if (actuator->m_sound) + return (PyObject *)AUD_getPythonSound(actuator->m_sound); else Py_RETURN_NONE; } @@ -450,50 +464,49 @@ int KX_SoundActuator::pyattr_set_3d_property(void *self, const struct KX_PYATTRI if (!PyArg_Parse(value, "f", &prop_value)) return PY_SET_ATTR_FAIL; - boost::shared_ptr<AUD_I3DHandle> handle3d = boost::dynamic_pointer_cast<AUD_I3DHandle>(actuator->m_handle); // if sound is working and 3D, set the new setting if (!actuator->m_is3d) return PY_SET_ATTR_FAIL; if (!strcmp(prop, "volume_maximum")) { actuator->m_3d.max_gain = prop_value; - if (handle3d.get()) - handle3d->setVolumeMaximum(prop_value); + if (actuator->m_handle) + AUD_Handle_setVolumeMaximum(actuator->m_handle, prop_value); } else if (!strcmp(prop, "volume_minimum")) { actuator->m_3d.min_gain = prop_value; - if (handle3d.get()) - handle3d->setVolumeMinimum(prop_value); + if (actuator->m_handle) + AUD_Handle_setVolumeMinimum(actuator->m_handle, prop_value); } else if (!strcmp(prop, "distance_reference")) { actuator->m_3d.reference_distance = prop_value; - if (handle3d.get()) - handle3d->setDistanceReference(prop_value); + if (actuator->m_handle) + AUD_Handle_setDistanceReference(actuator->m_handle, prop_value); } else if (!strcmp(prop, "distance_maximum")) { actuator->m_3d.max_distance = prop_value; - if (handle3d.get()) - handle3d->setDistanceMaximum(prop_value); + if (actuator->m_handle) + AUD_Handle_setDistanceMaximum(actuator->m_handle, prop_value); } else if (!strcmp(prop, "attenuation")) { actuator->m_3d.rolloff_factor = prop_value; - if (handle3d.get()) - handle3d->setAttenuation(prop_value); + if (actuator->m_handle) + AUD_Handle_setAttenuation(actuator->m_handle, prop_value); } else if (!!strcmp(prop, "cone_angle_inner")) { actuator->m_3d.cone_inner_angle = prop_value; - if (handle3d.get()) - handle3d->setConeAngleInner(prop_value); + if (actuator->m_handle) + AUD_Handle_setConeAngleInner(actuator->m_handle, prop_value); } else if (!strcmp(prop, "cone_angle_outer")) { actuator->m_3d.cone_outer_angle = prop_value; - if (handle3d.get()) - handle3d->setConeAngleOuter(prop_value); + if (actuator->m_handle) + AUD_Handle_setConeAngleOuter(actuator->m_handle, prop_value); } else if (!strcmp(prop, "cone_volume_outer")) { actuator->m_3d.cone_outer_gain = prop_value; - if (handle3d.get()) - handle3d->setConeVolumeOuter(prop_value); + if (actuator->m_handle) + AUD_Handle_setConeVolumeOuter(actuator->m_handle, prop_value); } else { return PY_SET_ATTR_FAIL; @@ -510,8 +523,8 @@ int KX_SoundActuator::pyattr_set_audposition(void *self, const struct KX_PYATTRI if (!PyArg_Parse(value, "f", &position)) return PY_SET_ATTR_FAIL; - if (actuator->m_handle.get()) - actuator->m_handle->seek(position); + if (actuator->m_handle) + AUD_Handle_setPosition(actuator->m_handle, position); return PY_SET_ATTR_SUCCESS; } @@ -523,8 +536,8 @@ int KX_SoundActuator::pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DE return PY_SET_ATTR_FAIL; actuator->m_volume = gain; - if (actuator->m_handle.get()) - actuator->m_handle->setVolume(gain); + if (actuator->m_handle) + AUD_Handle_setVolume(actuator->m_handle, gain); return PY_SET_ATTR_SUCCESS; } @@ -537,8 +550,8 @@ int KX_SoundActuator::pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_D return PY_SET_ATTR_FAIL; actuator->m_pitch = pitch; - if (actuator->m_handle.get()) - actuator->m_handle->setPitch(pitch); + if (actuator->m_handle) + AUD_Handle_setPitch(actuator->m_handle, pitch); return PY_SET_ATTR_SUCCESS; } @@ -550,11 +563,12 @@ int KX_SoundActuator::pyattr_set_sound(void *self, const struct KX_PYATTRIBUTE_D if (!PyArg_Parse(value, "O", &sound)) return PY_SET_ATTR_FAIL; - boost::shared_ptr<AUD_IFactory>* snd = reinterpret_cast<boost::shared_ptr<AUD_IFactory>*>(AUD_getPythonSound((void *)sound)); + AUD_Sound *snd = AUD_getSoundFromPython(sound); + if (snd) { - actuator->m_sound = *snd; - delete snd; + AUD_Sound_free(actuator->m_sound); + actuator->m_sound = snd; return PY_SET_ATTR_SUCCESS; } diff --git a/source/gameengine/Ketsji/KX_SoundActuator.h b/source/gameengine/Ketsji/KX_SoundActuator.h index 68eff56797b..5ec2fda722f 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.h +++ b/source/gameengine/Ketsji/KX_SoundActuator.h @@ -35,10 +35,8 @@ #include "SCA_IActuator.h" #ifdef WITH_AUDASPACE -# include "AUD_C-API.h" -# include "AUD_IFactory.h" -# include "AUD_IHandle.h" -# include <boost/shared_ptr.hpp> +# include AUD_SOUND_H +# include AUD_HANDLE_H #endif #include "BKE_sound.h" @@ -58,12 +56,12 @@ class KX_SoundActuator : public SCA_IActuator { Py_Header bool m_isplaying; - boost::shared_ptr<AUD_IFactory> m_sound; + AUD_Sound* m_sound; float m_volume; float m_pitch; bool m_is3d; KX_3DSoundSettings m_3d; - boost::shared_ptr<AUD_IHandle> m_handle; + AUD_Handle* m_handle; void play(); @@ -84,7 +82,7 @@ public: KX_SOUNDACT_TYPE m_type; KX_SoundActuator(SCA_IObject* gameobj, - boost::shared_ptr<AUD_IFactory> sound, + AUD_Sound *sound, float volume, float pitch, bool is3d, diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.cpp b/source/gameengine/Ketsji/KX_SteeringActuator.cpp index ff192299702..cd2cd2bae0b 100644 --- a/source/gameengine/Ketsji/KX_SteeringActuator.cpp +++ b/source/gameengine/Ketsji/KX_SteeringActuator.cpp @@ -41,7 +41,7 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj, +KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj, int mode, KX_GameObject *target, KX_GameObject *navmesh, @@ -54,7 +54,8 @@ KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj, KX_ObstacleSimulation* simulation, short facingmode, bool normalup, - bool enableVisualization) + bool enableVisualization, + bool lockzvel) : SCA_IActuator(gameobj, KX_ACT_STEERING), m_target(target), m_mode(mode), @@ -72,6 +73,7 @@ KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj, m_normalUp(normalup), m_pathLen(0), m_pathUpdatePeriod(pathUpdatePeriod), + m_lockzvel(lockzvel), m_wayPointIdx(-1), m_steerVec(MT_Vector3(0, 0, 0)) { @@ -266,14 +268,14 @@ bool KX_SteeringActuator::Update(double curtime, bool frame) m_steerVec.z() = 0; if (!m_steerVec.fuzzyZero()) m_steerVec.normalize(); - MT_Vector3 newvel = m_velocity*m_steerVec; + MT_Vector3 newvel = m_velocity * m_steerVec; //adjust velocity to avoid obstacles if (m_simulation && m_obstacle /*&& !newvel.fuzzyZero()*/) { if (m_enableVisualization) KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(1.0, 0.0, 0.0)); - m_simulation->AdjustObstacleVelocity(m_obstacle, m_mode!=KX_STEERING_PATHFOLLOWING ? m_navmesh : NULL, + m_simulation->AdjustObstacleVelocity(m_obstacle, m_mode!=KX_STEERING_PATHFOLLOWING ? m_navmesh : NULL, newvel, m_acceleration*delta, m_turnspeed/180.0f*M_PI*delta); if (m_enableVisualization) KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(0.0, 1.0, 0.0)); @@ -285,7 +287,12 @@ bool KX_SteeringActuator::Update(double curtime, bool frame) //temporary solution: set 2D steering velocity directly to obj //correct way is to apply physical force MT_Vector3 curvel = obj->GetLinearVelocity(); - newvel.z() = curvel.z(); + + if (m_lockzvel) + newvel.z() = 0.0f; + else + newvel.z() = curvel.z(); + obj->setLinearVelocity(newvel, false); } else @@ -554,6 +561,7 @@ PyAttributeDef KX_SteeringActuator::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("steeringVec", KX_SteeringActuator, pyattr_get_steeringVec), KX_PYATTRIBUTE_SHORT_RW("facingMode", 0, 6, true, KX_SteeringActuator, m_facingMode), KX_PYATTRIBUTE_INT_RW("pathUpdatePeriod", -1, 100000, true, KX_SteeringActuator, m_pathUpdatePeriod), + KX_PYATTRIBUTE_BOOL_RW("lockZVelocity", KX_SteeringActuator, m_lockzvel), { NULL } //Sentinel }; @@ -602,8 +610,7 @@ int KX_SteeringActuator::pyattr_set_navmesh(void *self, const struct KX_PYATTRIB if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_SteeringActuator")) return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error - if (dynamic_cast<KX_NavMeshObject *>(gameobj) == NULL) - { + if (dynamic_cast<KX_NavMeshObject *>(gameobj) == NULL) { PyErr_Format(PyExc_TypeError, "KX_NavMeshObject is expected"); return PY_SET_ATTR_FAIL; } diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.h b/source/gameengine/Ketsji/KX_SteeringActuator.h index 1e8ac9a54f0..3273471c166 100644 --- a/source/gameengine/Ketsji/KX_SteeringActuator.h +++ b/source/gameengine/Ketsji/KX_SteeringActuator.h @@ -62,6 +62,7 @@ class KX_SteeringActuator : public SCA_IActuator int m_pathLen; int m_pathUpdatePeriod; double m_pathUpdateTime; + bool m_lockzvel; int m_wayPointIdx; MT_Matrix3x3 m_parentlocalmat; MT_Vector3 m_steerVec; @@ -89,7 +90,8 @@ public: KX_ObstacleSimulation* simulation, short facingmode, bool normalup, - bool enableVisualization); + bool enableVisualization, + bool lockzvel); virtual ~KX_SteeringActuator(); virtual bool Update(double curtime, bool frame); diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp index 7ec379eec26..eb774960d41 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp +++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp @@ -60,7 +60,7 @@ bool KX_TouchEventManager::NewHandleCollision(void* object1, void* object2, cons PHY_IPhysicsController* obj1 = static_cast<PHY_IPhysicsController*>(object1); PHY_IPhysicsController* obj2 = static_cast<PHY_IPhysicsController*>(object2); - m_newCollisions.insert(std::pair<PHY_IPhysicsController*, PHY_IPhysicsController*>(obj1, obj2)); + m_newCollisions.insert(NewCollision(obj1, obj2, coll_data)); return false; } @@ -209,9 +209,11 @@ void KX_TouchEventManager::NextFrame() } } // Run python callbacks - kxObj1->RunCollisionCallbacks(kxObj2); - kxObj2->RunCollisionCallbacks(kxObj1); + PHY_CollData *colldata = cit->colldata; + kxObj1->RunCollisionCallbacks(kxObj2, colldata->m_point1, colldata->m_normal); + kxObj2->RunCollisionCallbacks(kxObj1, colldata->m_point2, -colldata->m_normal); + delete cit->colldata; } m_newCollisions.clear(); @@ -219,3 +221,19 @@ void KX_TouchEventManager::NextFrame() for (it.begin();!it.end();++it) (*it)->Activate(m_logicmgr); } + + +KX_TouchEventManager::NewCollision::NewCollision(PHY_IPhysicsController *first, + PHY_IPhysicsController *second, + const PHY_CollData *colldata) + : first(first), second(second), colldata(new PHY_CollData(*colldata)) +{} + +KX_TouchEventManager::NewCollision::NewCollision(const NewCollision &to_copy) + : first(to_copy.first), second(to_copy.second), colldata(to_copy.colldata) +{} + +bool KX_TouchEventManager::NewCollision::operator<(const NewCollision &other) const +{ + return first < other.first || second < other.second || colldata < other.colldata; +} diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.h b/source/gameengine/Ketsji/KX_TouchEventManager.h index bd4903c1545..d9c6fdad307 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.h +++ b/source/gameengine/Ketsji/KX_TouchEventManager.h @@ -45,7 +45,29 @@ class PHY_IPhysicsEnvironment; class KX_TouchEventManager : public SCA_EventManager { - typedef std::pair<PHY_IPhysicsController*, PHY_IPhysicsController*> NewCollision; + /** + * Contains two colliding objects and the first contact point. + */ + class NewCollision { + public: + PHY_IPhysicsController *first; + PHY_IPhysicsController *second; + PHY_CollData *colldata; + + /** + * Creates a copy of the given PHY_CollData; freeing that copy should be done by the owner of + * the NewCollision object. + * + * This allows us to efficiently store NewCollision objects in a std::set without creating more + * copies of colldata, as the NewCollision copy constructor reuses the pointer and doesn't clone + * it again. */ + NewCollision(PHY_IPhysicsController *first, + PHY_IPhysicsController *second, + const PHY_CollData *colldata); + NewCollision(const NewCollision &to_copy); + bool operator<(const NewCollision &other) const; + }; + PHY_IPhysicsEnvironment* m_physEnv; std::set<NewCollision> m_newCollisions; diff --git a/source/gameengine/Ketsji/KX_TouchSensor.cpp b/source/gameengine/Ketsji/KX_TouchSensor.cpp index 5cb1d5f3620..593d3e844e8 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.cpp +++ b/source/gameengine/Ketsji/KX_TouchSensor.cpp @@ -41,6 +41,8 @@ #include "PHY_IPhysicsController.h" +#include "RAS_MeshObject.h" + #include <iostream> #include "PHY_IPhysicsEnvironment.h" @@ -219,14 +221,17 @@ bool KX_TouchSensor::BroadPhaseSensorFilterCollision(void*obj1,void*obj2) bool found = m_touchedpropname.IsEmpty(); if (!found) { - if (m_bFindMaterial) - { - if (client_info->m_auxilary_info) - { - found = (!strcmp(m_touchedpropname.Ptr(), (char*)client_info->m_auxilary_info)); + if (m_bFindMaterial) { + for (unsigned int i = 0; i < otherobj->GetMeshCount(); ++i) { + RAS_MeshObject *meshObj = otherobj->GetMesh(i); + for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { + found = strcmp(m_touchedpropname.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; + if (found) + break; + } } - } else - { + } + else { found = (otherobj->GetProperty(m_touchedpropname) != NULL); } } @@ -255,16 +260,22 @@ bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_Coll { bool found = m_touchedpropname.IsEmpty(); + bool hitMaterial = false; if (!found) { - if (m_bFindMaterial) - { - if (client_info->m_auxilary_info) - { - found = (!strcmp(m_touchedpropname.Ptr(), (char*)client_info->m_auxilary_info)); + if (m_bFindMaterial) { + for (unsigned int i = 0; i < gameobj->GetMeshCount(); ++i) { + RAS_MeshObject *meshObj = gameobj->GetMesh(i); + for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { + found = strcmp(m_touchedpropname.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; + if (found) { + hitMaterial = true; + break; + } + } } - } else - { + } + else { found = (gameobj->GetProperty(m_touchedpropname) != NULL); } } @@ -278,7 +289,7 @@ bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_Coll } m_bTriggered = true; m_hitObject = gameobj; - m_hitMaterial = (client_info->m_auxilary_info ? (char*)client_info->m_auxilary_info : ""); + m_hitMaterial = hitMaterial; //printf("KX_TouchSensor::HandleCollision\n"); } diff --git a/source/gameengine/Ketsji/KX_TouchSensor.h b/source/gameengine/Ketsji/KX_TouchSensor.h index 0edca44296a..e1b5725a32b 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.h +++ b/source/gameengine/Ketsji/KX_TouchSensor.h @@ -34,7 +34,7 @@ #define __KX_TOUCHSENSOR_H__ #include "SCA_ISensor.h" -#include "ListValue.h" +#include "EXP_ListValue.h" struct PHY_CollData; diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp index 75baf5fac1d..3ed8eba759f 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp +++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp @@ -44,7 +44,7 @@ #include <iostream> #include "KX_GameObject.h" -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" /* ------------------------------------------------------------------------- */ /* Native functions */ diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp index 535ed5ed39a..ee791a44782 100644 --- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp +++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp @@ -22,7 +22,7 @@ * \ingroup ketsji */ -#include "PyObjectPlus.h" +#include "EXP_PyObjectPlus.h" #include "KX_VehicleWrapper.h" #include "PHY_IPhysicsEnvironment.h" @@ -53,6 +53,23 @@ KX_VehicleWrapper::~KX_VehicleWrapper() #ifdef WITH_PYTHON + +static bool raise_exc_wheel(PHY_IVehicle *vehicle, int i, const char *method) +{ + if (i < 0 || i >= vehicle->GetNumWheels()) { + PyErr_Format(PyExc_ValueError, + "%s(...): wheel index %d out of range (0 to %d).", method, i, vehicle->GetNumWheels() - 1); + return true; + } + else { + return false; + } +} + +#define WHEEL_INDEX_CHECK_OR_RETURN(i, method) \ + if (raise_exc_wheel(m_vehicle, i, method)) {return NULL;} (void)0 + + PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args) { @@ -67,22 +84,36 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args) KX_GameObject *gameOb; if (!ConvertPythonToGameObject(wheelGameObject, &gameOb, false, "vehicle.addWheel(...): KX_VehicleWrapper (first argument)")) return NULL; - if (gameOb->GetSGNode()) { - PHY_IMotionState* motionState = new KX_MotionState(gameOb->GetSGNode()); - - /* TODO - no error checking here! - bad juju */ MT_Vector3 attachPos,attachDir,attachAxle; - PyVecTo(pylistPos,attachPos); - PyVecTo(pylistDir,attachDir); - PyVecTo(pylistAxleDir,attachAxle); + if(!PyVecTo(pylistPos,attachPos)) { + PyErr_SetString(PyExc_AttributeError, + "addWheel(...) Unable to add wheel. attachPos must be a vector with 3 elements."); + return NULL; + } + if(!PyVecTo(pylistDir,attachDir)) { + PyErr_SetString(PyExc_AttributeError, + "addWheel(...) Unable to add wheel. downDir must be a vector with 3 elements."); + return NULL; + } + if(!PyVecTo(pylistAxleDir,attachAxle)) { + PyErr_SetString(PyExc_AttributeError, + "addWheel(...) Unable to add wheel. axleDir must be a vector with 3 elements."); + return NULL; + } //someone reverse some conventions inside Bullet (axle winding) attachAxle = -attachAxle; - printf("attempt for addWheel: suspensionRestLength%f wheelRadius %f, hasSteering:%d\n",suspensionRestLength,wheelRadius,hasSteering); + if(wheelRadius<=0) { + PyErr_SetString(PyExc_AttributeError, + "addWheel(...) Unable to add wheel. wheelRadius must be positive."); + return NULL; + } + + PHY_IMotionState *motionState = new KX_MotionState(gameOb->GetSGNode()); m_vehicle->AddWheel(motionState,attachPos,attachDir,attachAxle,suspensionRestLength,wheelRadius,hasSteering); } @@ -93,8 +124,6 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args) } - - PyObject *KX_VehicleWrapper::PyGetWheelPosition(PyObject *args) { @@ -103,6 +132,8 @@ PyObject *KX_VehicleWrapper::PyGetWheelPosition(PyObject *args) if (PyArg_ParseTuple(args,"i:getWheelPosition",&wheelIndex)) { float position[3]; + WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "getWheelPosition"); + m_vehicle->GetWheelPosition(wheelIndex,position[0],position[1],position[2]); MT_Vector3 pos(position[0],position[1],position[2]); return PyObjectFrom(pos); @@ -115,6 +146,8 @@ PyObject *KX_VehicleWrapper::PyGetWheelRotation(PyObject *args) int wheelIndex; if (PyArg_ParseTuple(args,"i:getWheelRotation",&wheelIndex)) { + WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "getWheelRotation"); + return PyFloat_FromDouble(m_vehicle->GetWheelRotation(wheelIndex)); } return NULL; @@ -126,6 +159,8 @@ PyObject *KX_VehicleWrapper::PyGetWheelOrientationQuaternion(PyObject *args) if (PyArg_ParseTuple(args,"i:getWheelOrientationQuaternion",&wheelIndex)) { float orn[4]; + WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "getWheelOrientationQuaternion"); + m_vehicle->GetWheelOrientationQuaternion(wheelIndex,orn[0],orn[1],orn[2],orn[3]); MT_Quaternion quatorn(orn[0],orn[1],orn[2],orn[3]); MT_Matrix3x3 ornmat(quatorn); @@ -148,7 +183,6 @@ PyObject *KX_VehicleWrapper::PyGetConstraintId(PyObject *args) } - PyObject *KX_VehicleWrapper::PyApplyEngineForce(PyObject *args) { float force; @@ -156,6 +190,8 @@ PyObject *KX_VehicleWrapper::PyApplyEngineForce(PyObject *args) if (PyArg_ParseTuple(args,"fi:applyEngineForce",&force,&wheelIndex)) { + WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "applyEngineForce"); + force *= -1.f;//someone reverse some conventions inside Bullet (axle winding) m_vehicle->ApplyEngineForce(force,wheelIndex); } @@ -172,6 +208,8 @@ PyObject *KX_VehicleWrapper::PySetTyreFriction(PyObject *args) if (PyArg_ParseTuple(args,"fi:setTyreFriction",&wheelFriction,&wheelIndex)) { + WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setTyreFriction"); + m_vehicle->SetWheelFriction(wheelFriction,wheelIndex); } else { @@ -187,6 +225,8 @@ PyObject *KX_VehicleWrapper::PySetSuspensionStiffness(PyObject *args) if (PyArg_ParseTuple(args,"fi:setSuspensionStiffness",&suspensionStiffness,&wheelIndex)) { + WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setSuspensionStiffness"); + m_vehicle->SetSuspensionStiffness(suspensionStiffness,wheelIndex); } else { @@ -202,6 +242,8 @@ PyObject *KX_VehicleWrapper::PySetSuspensionDamping(PyObject *args) if (PyArg_ParseTuple(args,"fi:setSuspensionDamping",&suspensionDamping,&wheelIndex)) { + WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setSuspensionDamping"); + m_vehicle->SetSuspensionDamping(suspensionDamping,wheelIndex); } else { return NULL; @@ -216,6 +258,8 @@ PyObject *KX_VehicleWrapper::PySetSuspensionCompression(PyObject *args) if (PyArg_ParseTuple(args,"fi:setSuspensionCompression",&suspensionCompression,&wheelIndex)) { + WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setSuspensionCompression"); + m_vehicle->SetSuspensionCompression(suspensionCompression,wheelIndex); } else { return NULL; @@ -230,6 +274,8 @@ PyObject *KX_VehicleWrapper::PySetRollInfluence(PyObject *args) if (PyArg_ParseTuple(args,"fi:setRollInfluence",&rollInfluence,&wheelIndex)) { + WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setRollInfluence"); + m_vehicle->SetRollInfluence(rollInfluence,wheelIndex); } else { @@ -246,6 +292,8 @@ PyObject *KX_VehicleWrapper::PyApplyBraking(PyObject *args) if (PyArg_ParseTuple(args,"fi:applyBraking",&braking,&wheelIndex)) { + WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "applyBraking"); + m_vehicle->ApplyBraking(braking,wheelIndex); } else { @@ -255,8 +303,6 @@ PyObject *KX_VehicleWrapper::PyApplyBraking(PyObject *args) } - - PyObject *KX_VehicleWrapper::PySetSteeringValue(PyObject *args) { float steeringValue; @@ -264,6 +310,8 @@ PyObject *KX_VehicleWrapper::PySetSteeringValue(PyObject *args) if (PyArg_ParseTuple(args,"fi:setSteeringValue",&steeringValue,&wheelIndex)) { + WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setSteeringValue"); + m_vehicle->SetSteeringValue(steeringValue,wheelIndex); } else { @@ -316,17 +364,11 @@ PyMethodDef KX_VehicleWrapper::Methods[] = { {"setSteeringValue",(PyCFunction) KX_VehicleWrapper::sPySetSteeringValue, METH_VARARGS}, {"applyEngineForce",(PyCFunction) KX_VehicleWrapper::sPyApplyEngineForce, METH_VARARGS}, {"applyBraking",(PyCFunction) KX_VehicleWrapper::sPyApplyBraking, METH_VARARGS}, - {"setTyreFriction",(PyCFunction) KX_VehicleWrapper::sPySetTyreFriction, METH_VARARGS}, - {"setSuspensionStiffness",(PyCFunction) KX_VehicleWrapper::sPySetSuspensionStiffness, METH_VARARGS}, - {"setSuspensionDamping",(PyCFunction) KX_VehicleWrapper::sPySetSuspensionDamping, METH_VARARGS}, - {"setSuspensionCompression",(PyCFunction) KX_VehicleWrapper::sPySetSuspensionCompression, METH_VARARGS}, - {"setRollInfluence",(PyCFunction) KX_VehicleWrapper::sPySetRollInfluence, METH_VARARGS}, - {NULL,NULL} //Sentinel }; diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.h b/source/gameengine/Ketsji/KX_VehicleWrapper.h index c38f57d8b9f..22b9591f48b 100644 --- a/source/gameengine/Ketsji/KX_VehicleWrapper.h +++ b/source/gameengine/Ketsji/KX_VehicleWrapper.h @@ -6,7 +6,7 @@ #ifndef __KX_VEHICLEWRAPPER_H__ #define __KX_VEHICLEWRAPPER_H__ -#include "Value.h" +#include "EXP_Value.h" class PHY_IVehicle; class PHY_IMotionState; diff --git a/source/gameengine/Ketsji/KX_WorldInfo.cpp b/source/gameengine/Ketsji/KX_WorldInfo.cpp index 444d6b0771b..111d81cad2e 100644 --- a/source/gameengine/Ketsji/KX_WorldInfo.cpp +++ b/source/gameengine/Ketsji/KX_WorldInfo.cpp @@ -31,8 +31,464 @@ #include "KX_WorldInfo.h" +#include "KX_PythonInit.h" +#include "KX_PyMath.h" +#include "RAS_IRasterizer.h" +#include "GPU_material.h" + +/* This little block needed for linking to Blender... */ +#ifdef WIN32 +#include "BLI_winstuff.h" +#endif + +/* This list includes only data type definitions */ +#include "DNA_scene_types.h" +#include "DNA_world_types.h" + +#include "BLI_math.h" + +#include "BKE_global.h" +#include "BKE_scene.h" +/* end of blender include block */ + + +KX_WorldInfo::KX_WorldInfo(Scene *blenderscene, World *blenderworld) +{ + if (blenderworld) { + m_name = blenderworld->id.name + 2; + m_do_color_management = BKE_scene_check_color_management_enabled(blenderscene); + m_hasworld = true; + m_hasmist = ((blenderworld->mode) & WO_MIST ? true : false); + m_misttype = blenderworld->mistype; + m_miststart = blenderworld->miststa; + m_mistdistance = blenderworld->mistdist; + m_mistintensity = blenderworld->misi; + setMistColor(blenderworld->horr, blenderworld->horg, blenderworld->horb); + setBackColor(blenderworld->horr, blenderworld->horg, blenderworld->horb); + setAmbientColor(blenderworld->ambr, blenderworld->ambg, blenderworld->ambb); + } + else { + m_hasworld = false; + } +} KX_WorldInfo::~KX_WorldInfo() { } +const STR_String& KX_WorldInfo::GetName() +{ + return m_name; +} + +bool KX_WorldInfo::hasWorld() +{ + return m_hasworld; +} + +void KX_WorldInfo::setBackColor(float r, float g, float b) +{ + m_backgroundcolor[0] = r; + m_backgroundcolor[1] = g; + m_backgroundcolor[2] = b; + + if (m_do_color_management) { + linearrgb_to_srgb_v3_v3(m_con_backgroundcolor, m_backgroundcolor); + } + else { + copy_v3_v3(m_con_backgroundcolor, m_backgroundcolor); + } +} + +const float *KX_WorldInfo::getBackColorConverted() const +{ + return m_con_backgroundcolor; +} + +void KX_WorldInfo::setMistType(short type) +{ + m_misttype = type; +} + +void KX_WorldInfo::setUseMist(bool enable) +{ + m_hasmist = enable; +} + +void KX_WorldInfo::setMistStart(float d) +{ + m_miststart = d; +} + +void KX_WorldInfo::setMistDistance(float d) +{ + m_mistdistance = d; +} + +void KX_WorldInfo::setMistIntensity(float intensity) +{ + m_mistintensity = intensity; +} +void KX_WorldInfo::setMistColor(float r, float g, float b) +{ + m_mistcolor[0] = r; + m_mistcolor[1] = g; + m_mistcolor[2] = b; + + if (m_do_color_management) { + linearrgb_to_srgb_v3_v3(m_con_mistcolor, m_mistcolor); + } + else { + copy_v3_v3(m_con_mistcolor, m_mistcolor); + } +} + +void KX_WorldInfo::setAmbientColor(float r, float g, float b) +{ + m_ambientcolor[0] = r; + m_ambientcolor[1] = g; + m_ambientcolor[2] = b; + + if (m_do_color_management) { + linearrgb_to_srgb_v3_v3(m_con_ambientcolor, m_ambientcolor); + } + else { + copy_v3_v3(m_con_ambientcolor, m_ambientcolor); + } +} + +void KX_WorldInfo::UpdateBackGround() +{ + if (m_hasworld) { + RAS_IRasterizer *m_rasterizer = KX_GetActiveEngine()->GetRasterizer(); + + if (m_rasterizer->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID) { + m_rasterizer->SetBackColor(m_con_backgroundcolor); + GPU_horizon_update_color(m_backgroundcolor); + } + } +} + +void KX_WorldInfo::UpdateWorldSettings() +{ + if (m_hasworld) { + RAS_IRasterizer *m_rasterizer = KX_GetActiveEngine()->GetRasterizer(); + + if (m_rasterizer->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID) { + m_rasterizer->SetAmbientColor(m_con_ambientcolor); + GPU_ambient_update_color(m_ambientcolor); + + if (m_hasmist) { + m_rasterizer->SetFog(m_misttype, m_miststart, m_mistdistance, m_mistintensity, m_con_mistcolor); + GPU_mist_update_values(m_misttype, m_miststart, m_mistdistance, m_mistintensity, m_mistcolor); + m_rasterizer->EnableFog(true); + GPU_mist_update_enable(true); + } + else { + m_rasterizer->EnableFog(false); + GPU_mist_update_enable(false); + } + } + } +} + +#ifdef WITH_PYTHON + +/* ------------------------------------------------------------------------- + * Python functions + * ------------------------------------------------------------------------- */ +PyObject *KX_WorldInfo::py_repr(void) +{ + return PyUnicode_From_STR_String(GetName()); +} + +/* ------------------------------------------------------------------------- + * Python Integration Hooks + * ------------------------------------------------------------------------- */ +PyTypeObject KX_WorldInfo::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "KX_WorldInfo", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &PyObjectPlus::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyMethodDef KX_WorldInfo::Methods[] = { + {NULL,NULL} /* Sentinel */ +}; + +PyAttributeDef KX_WorldInfo::Attributes[] = { + KX_PYATTRIBUTE_BOOL_RW("mistEnable", KX_WorldInfo, m_hasmist), + KX_PYATTRIBUTE_FLOAT_RW("mistStart", 0.0f, 10000.0f, KX_WorldInfo, m_miststart), + KX_PYATTRIBUTE_FLOAT_RW("mistDistance", 0.001f, 10000.0f, KX_WorldInfo, m_mistdistance), + KX_PYATTRIBUTE_FLOAT_RW("mistIntensity", 0.0f, 1.0f, KX_WorldInfo, m_mistintensity), + KX_PYATTRIBUTE_SHORT_RW("mistType", 0, 2, true, KX_WorldInfo, m_misttype), + KX_PYATTRIBUTE_RO_FUNCTION("KX_MIST_QUADRATIC", KX_WorldInfo, pyattr_get_mist_typeconst), + KX_PYATTRIBUTE_RO_FUNCTION("KX_MIST_LINEAR", KX_WorldInfo, pyattr_get_mist_typeconst), + KX_PYATTRIBUTE_RO_FUNCTION("KX_MIST_INV_QUADRATIC", KX_WorldInfo, pyattr_get_mist_typeconst), + KX_PYATTRIBUTE_RW_FUNCTION("mistColor", KX_WorldInfo, pyattr_get_mist_color, pyattr_set_mist_color), + KX_PYATTRIBUTE_RW_FUNCTION("backgroundColor", KX_WorldInfo, pyattr_get_back_color, pyattr_set_back_color), + KX_PYATTRIBUTE_RW_FUNCTION("ambientColor", KX_WorldInfo, pyattr_get_ambient_color, pyattr_set_ambient_color), + { NULL } /* Sentinel */ +}; + +/* Attribute get/set functions */ + +#ifdef USE_MATHUTILS + +/*----------------------mathutils callbacks ----------------------------*/ + +/* subtype */ +#define MATHUTILS_VEC_CB_MIST_COLOR 1 +#define MATHUTILS_VEC_CB_BACK_COLOR 2 +#define MATHUTILS_VEC_CB_AMBIENT_COLOR 3 + +static unsigned char mathutils_world_vector_cb_index = -1; /* index for our callbacks */ + +static int mathutils_world_generic_check(BaseMathObject *bmo) +{ + KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user); + if (self == NULL) + return -1; + + return 0; +} + +static int mathutils_world_vector_get(BaseMathObject *bmo, int subtype) +{ + KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user); + if (self == NULL) + return -1; + + switch (subtype) { + case MATHUTILS_VEC_CB_MIST_COLOR: + copy_v3_v3(bmo->data, self->m_mistcolor); + break; + case MATHUTILS_VEC_CB_BACK_COLOR: + copy_v3_v3(bmo->data, self->m_backgroundcolor); + break; + case MATHUTILS_VEC_CB_AMBIENT_COLOR: + copy_v3_v3(bmo->data, self->m_ambientcolor); + break; + default: + return -1; + } + return 0; +} + +static int mathutils_world_vector_set(BaseMathObject *bmo, int subtype) +{ + KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user); + + if (self == NULL) + return -1; + + switch (subtype) { + case MATHUTILS_VEC_CB_MIST_COLOR: + self->setMistColor(bmo->data[0], bmo->data[1], bmo->data[2]); + break; + case MATHUTILS_VEC_CB_BACK_COLOR: + self->setBackColor(bmo->data[0], bmo->data[1], bmo->data[2]); + break; + case MATHUTILS_VEC_CB_AMBIENT_COLOR: + self->setAmbientColor(bmo->data[0], bmo->data[1], bmo->data[2]); + break; + default: + return -1; + } + return 0; +} + +static int mathutils_world_vector_get_index(BaseMathObject *bmo, int subtype, int index) +{ + KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user); + + if (self == NULL) + return -1; + + switch (subtype) { + case MATHUTILS_VEC_CB_MIST_COLOR: + { + const float *color = self->m_mistcolor; + bmo->data[index] = color[index]; + } + break; + case MATHUTILS_VEC_CB_BACK_COLOR: + { + const float *color = self->m_backgroundcolor; + bmo->data[index] = color[index]; + } + break; + case MATHUTILS_VEC_CB_AMBIENT_COLOR: + { + const float *color = self->m_ambientcolor; + bmo->data[index] = color[index]; + } + break; + default: + return -1; + } + return 0; +} + +static int mathutils_world_vector_set_index(BaseMathObject *bmo, int subtype, int index) +{ + KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user); + + if (self == NULL) + return -1; + + float color[4]; + switch (subtype) { + case MATHUTILS_VEC_CB_MIST_COLOR: + copy_v3_v3(color, self->m_mistcolor); + color[index] = bmo->data[index]; + self->setMistColor(color[0], color[1], color[2]); + break; + case MATHUTILS_VEC_CB_BACK_COLOR: + copy_v3_v3(color, self->m_backgroundcolor); + color[index] = bmo->data[index]; + self->setBackColor(color[0], color[1], color[2]); + break; + case MATHUTILS_VEC_CB_AMBIENT_COLOR: + copy_v3_v3(color, self->m_ambientcolor); + color[index] = bmo->data[index]; + self->setAmbientColor(color[0], color[1], color[2]); + break; + default: + return -1; + } + return 0; +} + +static Mathutils_Callback mathutils_world_vector_cb = { + mathutils_world_generic_check, + mathutils_world_vector_get, + mathutils_world_vector_set, + mathutils_world_vector_get_index, + mathutils_world_vector_set_index +}; + +void KX_WorldInfo_Mathutils_Callback_Init() +{ + // register mathutils callbacks, ok to run more than once. + mathutils_world_vector_cb_index = Mathutils_RegisterCallback(&mathutils_world_vector_cb); +} +#endif // USE_MATHUTILS + + +PyObject *KX_WorldInfo::pyattr_get_mist_typeconst(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + PyObject *retvalue; + + const char* type = attrdef->m_name; + + if (!strcmp(type, "KX_MIST_QUADRATIC")) { + retvalue = PyLong_FromLong(KX_MIST_QUADRATIC); + } + else if (!strcmp(type, "KX_MIST_LINEAR")) { + retvalue = PyLong_FromLong(KX_MIST_LINEAR); + } + else if (!strcmp(type, "KX_MIST_INV_QUADRATIC")) { + retvalue = PyLong_FromLong(KX_MIST_INV_QUADRATIC); + } + else { + /* should never happen */ + PyErr_SetString(PyExc_TypeError, "invalid mist type"); + retvalue = NULL; + } + + return retvalue; +} + +PyObject *KX_WorldInfo::pyattr_get_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ +#ifdef USE_MATHUTILS + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_MIST_COLOR); +#else + KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v); + return PyObjectFrom(MT_Vector3(self->m_mistcolor)); +#endif +} + +int KX_WorldInfo::pyattr_set_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v); + + MT_Vector3 color; + if (PyVecTo(value, color)) + { + self->setMistColor(color[0], color[1], color[2]); + return PY_SET_ATTR_SUCCESS; + } + return PY_SET_ATTR_FAIL; +} + +PyObject *KX_WorldInfo::pyattr_get_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + +#ifdef USE_MATHUTILS + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_BACK_COLOR); +#else + KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v); + return PyObjectFrom(MT_Vector3(self->m_backgroundcolor)); +#endif +} + +int KX_WorldInfo::pyattr_set_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v); + + MT_Vector3 color; + if (PyVecTo(value, color)) + { + self->setBackColor(color[0], color[1], color[2]); + return PY_SET_ATTR_SUCCESS; + } + return PY_SET_ATTR_FAIL; +} + +PyObject *KX_WorldInfo::pyattr_get_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ +#ifdef USE_MATHUTILS + return Vector_CreatePyObject_cb( + BGE_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_AMBIENT_COLOR); +#else + KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v); + return PyObjectFrom(MT_Vector3(self->m_ambientcolor)); +#endif +} + +int KX_WorldInfo::pyattr_set_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v); + + MT_Vector3 color; + if (PyVecTo(value, color)) + { + self->setAmbientColor(color[0], color[1], color[2]); + return PY_SET_ATTR_SUCCESS; + } + return PY_SET_ATTR_FAIL; +} + +#endif /* WITH_PYTHON */ diff --git a/source/gameengine/Ketsji/KX_WorldInfo.h b/source/gameengine/Ketsji/KX_WorldInfo.h index 90b16fe1242..b155faf2837 100644 --- a/source/gameengine/Ketsji/KX_WorldInfo.h +++ b/source/gameengine/Ketsji/KX_WorldInfo.h @@ -33,44 +33,72 @@ #define __KX_WORLDINFO_H__ #include "MT_Scalar.h" +#include "KX_KetsjiEngine.h" +#include "EXP_PyObjectPlus.h" -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" +#ifdef USE_MATHUTILS +void KX_WorldInfo_Mathutils_Callback_Init(void); #endif -class MT_CmMatrix4x4; +struct Scene; +struct World; -class KX_WorldInfo +class KX_WorldInfo : public PyObjectPlus { -public: - KX_WorldInfo() {} - virtual ~KX_WorldInfo(); + Py_Header - virtual bool hasWorld() = 0; - virtual bool hasMist() = 0; - virtual float getBackColorRed() = 0; - virtual float getBackColorGreen() = 0; - virtual float getBackColorBlue() = 0; - virtual float getMistStart() = 0; - virtual float getMistDistance() = 0; - virtual float getMistColorRed() = 0; - virtual float getMistColorGreen() = 0; - virtual float getMistColorBlue() = 0; + STR_String m_name; + bool m_do_color_management; + bool m_hasworld; + bool m_hasmist; + short m_misttype; + float m_miststart; + float m_mistdistance; + float m_mistintensity; + float m_mistcolor[3]; + float m_backgroundcolor[3]; + float m_ambientcolor[3]; + float m_con_mistcolor[3]; + float m_con_backgroundcolor[3]; + float m_con_ambientcolor[3]; - virtual float getAmbientColorRed() = 0; - virtual float getAmbientColorGreen() = 0; - virtual float getAmbientColorBlue() = 0; +public: + /** + * Mist options + */ + enum MistType { + KX_MIST_QUADRATIC, + KX_MIST_LINEAR, + KX_MIST_INV_QUADRATIC, + }; - virtual void setBackColor(float, float, float) = 0; - virtual void setMistStart(float) = 0; - virtual void setMistDistance(float) = 0; - virtual void setMistColorRed(float) = 0; - virtual void setMistColorGreen(float) = 0; - virtual void setMistColorBlue(float) = 0; + KX_WorldInfo(Scene *blenderscene, World *blenderworld); + ~KX_WorldInfo(); + const STR_String &GetName(); + bool hasWorld(); + void setUseMist(bool enable); + void setMistType(short type); + void setMistStart(float d); + void setMistDistance(float d); + void setMistIntensity(float intensity); + void setMistColor(float r, float g, float b); + void setBackColor(float r, float g, float b); + const float *getBackColorConverted() const; + void setAmbientColor(float r, float g, float b); + void UpdateBackGround(); + void UpdateWorldSettings(); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_WorldInfo") +#ifdef WITH_PYTHON + /* attributes */ + static PyObject *pyattr_get_mist_typeconst(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + virtual PyObject *py_repr(void); #endif }; diff --git a/source/gameengine/Ketsji/KX_WorldIpoController.cpp b/source/gameengine/Ketsji/KX_WorldIpoController.cpp index 7f83a155643..1123e07ebcc 100644 --- a/source/gameengine/Ketsji/KX_WorldIpoController.cpp +++ b/source/gameengine/Ketsji/KX_WorldIpoController.cpp @@ -33,6 +33,8 @@ #include "KX_WorldIpoController.h" #include "KX_ScalarInterpolator.h" #include "KX_WorldInfo.h" +#include "KX_PythonInit.h" +#include "KX_Scene.h" #if defined(_WIN64) typedef unsigned __int64 uint_ptr; @@ -42,31 +44,36 @@ typedef unsigned long uint_ptr; bool KX_WorldIpoController::Update(double currentTime) { - if (m_modified) - { + if (m_modified) { T_InterpolatorList::iterator i; for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - (*i)->Execute(m_ipotime);//currentTime); + (*i)->Execute(m_ipotime); } - /* TODO, this will crash! */ - KX_WorldInfo *world = NULL; + KX_WorldInfo *world = KX_GetActiveScene()->GetWorldInfo(); if (m_modify_mist_start) { world->setMistStart(m_mist_start); } - if (m_modify_mist_color) { - world->setMistColorRed(m_mist_rgb[0]); - world->setMistColorGreen(m_mist_rgb[1]); - world->setMistColorBlue(m_mist_rgb[2]); - } - if (m_modify_mist_dist) { world->setMistDistance(m_mist_dist); } - m_modified=false; + if (m_modify_mist_intensity) { + world->setMistIntensity(m_mist_intensity); + } + + if (m_modify_horizon_color) { + world->setBackColor(m_hori_rgb[0], m_hori_rgb[1], m_hori_rgb[2]); + world->setMistColor(m_hori_rgb[0], m_hori_rgb[1], m_hori_rgb[2]); + } + + if (m_modify_ambient_color) { + world->setAmbientColor(m_ambi_rgb[0], m_ambi_rgb[1], m_ambi_rgb[2]); + } + + m_modified = false; } return false; } diff --git a/source/gameengine/Ketsji/KX_WorldIpoController.h b/source/gameengine/Ketsji/KX_WorldIpoController.h index 63983b3129b..704f421573e 100644 --- a/source/gameengine/Ketsji/KX_WorldIpoController.h +++ b/source/gameengine/Ketsji/KX_WorldIpoController.h @@ -39,24 +39,30 @@ class KX_WorldIpoController : public SG_Controller { public: - MT_Scalar m_mist_rgb[3]; MT_Scalar m_mist_start; MT_Scalar m_mist_dist; + MT_Scalar m_mist_intensity; + MT_Scalar m_hori_rgb[3]; + MT_Scalar m_ambi_rgb[3]; private: T_InterpolatorList m_interpolators; - unsigned short m_modify_mist_color : 1; unsigned short m_modify_mist_start : 1; unsigned short m_modify_mist_dist : 1; + unsigned short m_modify_mist_intensity : 1; + unsigned short m_modify_horizon_color : 1; + unsigned short m_modify_ambient_color : 1; bool m_modified; double m_ipotime; public: KX_WorldIpoController() : - m_modify_mist_color(false), m_modify_mist_start(false), m_modify_mist_dist(false), + m_modify_mist_intensity(false), + m_modify_horizon_color(false), + m_modify_ambient_color(false), m_modified(true), m_ipotime(0.0) {} @@ -76,14 +82,22 @@ public: m_modify_mist_start = modify; } - void SetModifyMistColor(bool modify) { - m_modify_mist_color = modify; - } - void SetModifyMistDist(bool modify) { m_modify_mist_dist = modify; } + void SetModifyMistIntensity(bool modify) { + m_modify_mist_intensity = modify; + } + + void SetModifyHorizonColor(bool modify) { + m_modify_horizon_color = modify; + } + + void SetModifyAmbientColor(bool modify) { + m_modify_ambient_color = modify; + } + void SetOption( int option, diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript index db5474cf2d7..d8dfd3d9bca 100644 --- a/source/gameengine/Ketsji/SConscript +++ b/source/gameengine/Ketsji/SConscript @@ -30,7 +30,8 @@ import sys Import ('env') sources = env.Glob('*.cpp') -defs = [ 'GLEW_STATIC' ] +defs = [] +defs += env['BF_GL_DEFINITIONS'] incs = [ '.', @@ -38,9 +39,8 @@ incs = [ '#intern/guardedalloc', '#intern/string', '#source/blender', - '#extern/glew/include', - '#intern/audaspace/FX', - '#intern/audaspace/intern', + env['BF_GLEW_INC'], + '#/intern/glew-mx', '#intern/moto/include', '#source/blender/blenfont', '#source/blender/blenkernel', @@ -85,6 +85,11 @@ if env['WITH_BF_PYTHON']: incs += ' ' + env['BF_PYTHON_INC'] defs.append('WITH_PYTHON') +if env['WITH_BF_AUDASPACE']: + defs += env['BF_AUDASPACE_DEF'] + incs += ' ' + env['BF_AUDASPACE_C_INC'] + incs += ' ' + env['BF_AUDASPACE_PY_INC'] + if env['WITH_BF_FFMPEG']: defs.append('WITH_FFMPEG') |