Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2008-11-13 00:16:53 +0300
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2008-11-13 00:16:53 +0300
commitbdfe7d89e2f1292644577972c716931b4ce3c6c3 (patch)
treed00eb50b749cb001e2b08272c91791e66740b05d /source/gameengine/Ketsji
parent78a1c27c4a6abe0ed31ca93ad21910f3df04da56 (diff)
parent7e4db234cee71ead34ee81a12e27da4bd548eb4b (diff)
Merge of trunk into blender 2.5:
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r12987:17416 Issues: * GHOST/X11 had conflicting changes. Some code was added in 2.5, which was later added in trunk also, but reverted partially, specifically revision 16683. I have left out this reversion in the 2.5 branch since I think it is needed there. http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16683 * Scons had various conflicting changes, I decided to go with trunk version for everything except priorities and some library renaming. * In creator.c, there were various fixes and fixes for fixes related to the -w -W and -p options. In 2.5 -w and -W is not coded yet, and -p is done differently. Since this is changed so much, and I don't think those fixes would be needed in 2.5, I've left them out. * Also in creator.c: there was code for a python bugfix where the screen was not initialized when running with -P. The code that initializes the screen there I had to disable, that can't work in 2.5 anymore but left it commented as a reminder. Further I had to disable some new function calls. using src/ and python/, as was done already in this branch, disabled function calls: * bpath.c: error reporting * BME_conversions.c: editmesh conversion functions. * SHD_dynamic: disabled almost completely, there is no python/. * KX_PythonInit.cpp and Ketsji/ build files: Mathutils is not there, disabled. * text.c: clipboard copy call. * object.c: OB_SUPPORT_MATERIAL. * DerivedMesh.c and subsurf_ccg, stipple_quarttone. Still to be done: * Go over files and functions that were moved to a different location but could still use changes that were done in trunk.
Diffstat (limited to 'source/gameengine/Ketsji')
-rw-r--r--source/gameengine/Ketsji/BL_BlenderShader.cpp170
-rw-r--r--source/gameengine/Ketsji/BL_BlenderShader.h53
-rw-r--r--source/gameengine/Ketsji/BL_Material.cpp7
-rw-r--r--source/gameengine/Ketsji/BL_Material.h19
-rw-r--r--source/gameengine/Ketsji/BL_Shader.cpp395
-rw-r--r--source/gameengine/Ketsji/BL_Shader.h6
-rw-r--r--source/gameengine/Ketsji/BL_Texture.cpp108
-rw-r--r--source/gameengine/Ketsji/BL_Texture.h8
-rw-r--r--source/gameengine/Ketsji/CMakeLists.txt18
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp17
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h3
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp14
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp100
-rw-r--r--source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h11
-rw-r--r--source/gameengine/Ketsji/KX_BlenderMaterial.cpp476
-rw-r--r--source/gameengine/Ketsji/KX_BlenderMaterial.h32
-rw-r--r--source/gameengine/Ketsji/KX_BulletPhysicsController.cpp98
-rw-r--r--source/gameengine/Ketsji/KX_BulletPhysicsController.h14
-rw-r--r--source/gameengine/Ketsji/KX_Camera.cpp48
-rw-r--r--source/gameengine/Ketsji/KX_Camera.h23
-rw-r--r--source/gameengine/Ketsji/KX_CameraActuator.cpp164
-rw-r--r--source/gameengine/Ketsji/KX_CameraActuator.h12
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintActuator.cpp805
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintActuator.h85
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintWrapper.cpp4
-rw-r--r--source/gameengine/Ketsji/KX_ConvertPhysicsObject.h42
-rw-r--r--source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp695
-rw-r--r--source/gameengine/Ketsji/KX_GameActuator.cpp74
-rw-r--r--source/gameengine/Ketsji/KX_GameActuator.h2
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.cpp1414
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.h341
-rw-r--r--source/gameengine/Ketsji/KX_IPO_SGController.cpp232
-rw-r--r--source/gameengine/Ketsji/KX_IPO_SGController.h47
-rw-r--r--source/gameengine/Ketsji/KX_IPhysicsController.h10
-rw-r--r--source/gameengine/Ketsji/KX_ISceneConverter.h9
-rw-r--r--source/gameengine/Ketsji/KX_IpoActuator.cpp327
-rw-r--r--source/gameengine/Ketsji/KX_IpoActuator.h26
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.cpp340
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.h34
-rw-r--r--source/gameengine/Ketsji/KX_Light.cpp98
-rw-r--r--source/gameengine/Ketsji/KX_Light.h23
-rw-r--r--source/gameengine/Ketsji/KX_MaterialIpoController.cpp11
-rw-r--r--source/gameengine/Ketsji/KX_MaterialIpoController.h8
-rw-r--r--source/gameengine/Ketsji/KX_MeshProxy.cpp60
-rw-r--r--source/gameengine/Ketsji/KX_MeshProxy.h2
-rw-r--r--source/gameengine/Ketsji/KX_MouseFocusSensor.cpp81
-rw-r--r--source/gameengine/Ketsji/KX_MouseFocusSensor.h17
-rw-r--r--source/gameengine/Ketsji/KX_NearSensor.cpp97
-rw-r--r--source/gameengine/Ketsji/KX_NearSensor.h3
-rw-r--r--source/gameengine/Ketsji/KX_ObjectActuator.cpp364
-rw-r--r--source/gameengine/Ketsji/KX_ObjectActuator.h59
-rw-r--r--source/gameengine/Ketsji/KX_OdePhysicsController.cpp10
-rw-r--r--source/gameengine/Ketsji/KX_OdePhysicsController.h6
-rw-r--r--source/gameengine/Ketsji/KX_ParentActuator.cpp221
-rw-r--r--source/gameengine/Ketsji/KX_ParentActuator.h89
-rw-r--r--source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp22
-rw-r--r--source/gameengine/Ketsji/KX_PolyProxy.cpp265
-rw-r--r--source/gameengine/Ketsji/KX_PolyProxy.h71
-rw-r--r--source/gameengine/Ketsji/KX_PolygonMaterial.cpp60
-rw-r--r--source/gameengine/Ketsji/KX_PolygonMaterial.h5
-rw-r--r--source/gameengine/Ketsji/KX_PyConstraintBinding.cpp141
-rw-r--r--source/gameengine/Ketsji/KX_PyMath.h23
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.cpp1063
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.h17
-rw-r--r--source/gameengine/Ketsji/KX_RadarSensor.cpp55
-rw-r--r--source/gameengine/Ketsji/KX_RayCast.cpp80
-rw-r--r--source/gameengine/Ketsji/KX_RayCast.h60
-rw-r--r--source/gameengine/Ketsji/KX_RayEventManager.cpp9
-rw-r--r--source/gameengine/Ketsji/KX_RayEventManager.h1
-rw-r--r--source/gameengine/Ketsji/KX_RaySensor.cpp96
-rw-r--r--source/gameengine/Ketsji/KX_RaySensor.h9
-rw-r--r--source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp243
-rw-r--r--source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h47
-rw-r--r--source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp206
-rw-r--r--source/gameengine/Ketsji/KX_SCA_DynamicActuator.h76
-rw-r--r--source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp43
-rw-r--r--source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h2
-rw-r--r--source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_SG_NodeRelationships.h21
-rw-r--r--source/gameengine/Ketsji/KX_Scene.cpp660
-rw-r--r--source/gameengine/Ketsji/KX_Scene.h66
-rw-r--r--source/gameengine/Ketsji/KX_SceneActuator.cpp78
-rw-r--r--source/gameengine/Ketsji/KX_SceneActuator.h3
-rw-r--r--source/gameengine/Ketsji/KX_SoundActuator.cpp125
-rw-r--r--source/gameengine/Ketsji/KX_StateActuator.cpp207
-rw-r--r--source/gameengine/Ketsji/KX_StateActuator.h83
-rw-r--r--source/gameengine/Ketsji/KX_SumoPhysicsController.cpp10
-rw-r--r--source/gameengine/Ketsji/KX_SumoPhysicsController.h7
-rw-r--r--source/gameengine/Ketsji/KX_TouchEventManager.cpp70
-rw-r--r--source/gameengine/Ketsji/KX_TouchEventManager.h9
-rw-r--r--source/gameengine/Ketsji/KX_TouchSensor.cpp85
-rw-r--r--source/gameengine/Ketsji/KX_TouchSensor.h11
-rw-r--r--source/gameengine/Ketsji/KX_TrackToActuator.cpp185
-rw-r--r--source/gameengine/Ketsji/KX_TrackToActuator.h7
-rw-r--r--source/gameengine/Ketsji/KX_VehicleWrapper.cpp105
-rw-r--r--source/gameengine/Ketsji/KX_VertexProxy.cpp14
-rw-r--r--source/gameengine/Ketsji/KX_VisibilityActuator.cpp14
-rw-r--r--source/gameengine/Ketsji/KX_VisibilityActuator.h2
-rw-r--r--source/gameengine/Ketsji/Makefile7
-rw-r--r--source/gameengine/Ketsji/SConscript23
100 files changed, 8746 insertions, 3074 deletions
diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp
new file mode 100644
index 00000000000..8ec463be6ff
--- /dev/null
+++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp
@@ -0,0 +1,170 @@
+
+#include "DNA_customdata_types.h"
+#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BL_BlenderShader.h"
+#include "BL_Material.h"
+
+#include "GPU_extensions.h"
+#include "GPU_material.h"
+
+#include "RAS_BucketManager.h"
+#include "RAS_MeshObject.h"
+#include "RAS_IRasterizer.h"
+
+BL_BlenderShader::BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer)
+:
+ mScene(scene),
+ mMat(ma),
+ mLightLayer(lightlayer)
+{
+ mBlenderScene = scene->GetBlenderScene();
+ mBlendMode = GPU_BLEND_SOLID;
+
+ if(mMat)
+ GPU_material_from_blender(mBlenderScene, mMat);
+}
+
+BL_BlenderShader::~BL_BlenderShader()
+{
+ if(mMat && GPU_material_from_blender(mBlenderScene, mMat))
+ GPU_material_unbind(GPU_material_from_blender(mBlenderScene, mMat));
+}
+
+bool BL_BlenderShader::Ok()
+{
+ return VerifyShader();
+}
+
+bool BL_BlenderShader::VerifyShader()
+{
+ if(mMat)
+ return (GPU_material_from_blender(mBlenderScene, mMat) != 0);
+ else
+ return false;
+}
+
+void BL_BlenderShader::SetProg(bool enable, double time)
+{
+ if(VerifyShader()) {
+ if(enable)
+ GPU_material_bind(GPU_material_from_blender(mBlenderScene, mMat), mLightLayer, ~0, time);
+ else
+ GPU_material_unbind(GPU_material_from_blender(mBlenderScene, mMat));
+ }
+}
+
+int BL_BlenderShader::GetAttribNum()
+{
+ GPUVertexAttribs attribs;
+ int i, enabled = 0;
+
+ if(!VerifyShader())
+ return enabled;
+
+ GPU_material_vertex_attributes(GPU_material_from_blender(mBlenderScene, mMat), &attribs);
+
+ for(i = 0; i < attribs.totlayer; i++)
+ if(attribs.layer[i].glindex+1 > enabled)
+ enabled= attribs.layer[i].glindex+1;
+
+ if(enabled > BL_MAX_ATTRIB)
+ enabled = BL_MAX_ATTRIB;
+
+ return enabled;
+}
+
+void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat)
+{
+ GPUVertexAttribs attribs;
+ GPUMaterial *gpumat;
+ int i, attrib_num;
+
+ ras->SetAttribNum(0);
+
+ if(!VerifyShader())
+ return;
+
+ gpumat = GPU_material_from_blender(mBlenderScene, mMat);
+
+ if(ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) {
+ GPU_material_vertex_attributes(gpumat, &attribs);
+ attrib_num = GetAttribNum();
+
+ ras->SetTexCoordNum(0);
+ ras->SetAttribNum(attrib_num);
+ for(i=0; i<attrib_num; i++)
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, i);
+
+ for(i = 0; i < attribs.totlayer; i++) {
+ if(attribs.layer[i].glindex > attrib_num)
+ continue;
+
+ if(attribs.layer[i].type == CD_MTFACE) {
+ if(!mat->uvName.IsEmpty() && strcmp(mat->uvName.ReadPtr(), attribs.layer[i].name) == 0)
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_UV1, attribs.layer[i].glindex);
+ else if(!mat->uv2Name.IsEmpty() && strcmp(mat->uv2Name.ReadPtr(), attribs.layer[i].name) == 0)
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_UV2, attribs.layer[i].glindex);
+ else
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_UV1, attribs.layer[i].glindex);
+ }
+ else if(attribs.layer[i].type == CD_TANGENT)
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT, attribs.layer[i].glindex);
+ else if(attribs.layer[i].type == CD_ORCO)
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_ORCO, attribs.layer[i].glindex);
+ else if(attribs.layer[i].type == CD_NORMAL)
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_NORM, attribs.layer[i].glindex);
+ else if(attribs.layer[i].type == CD_MCOL)
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_VCOL, attribs.layer[i].glindex);
+ else
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, attribs.layer[i].glindex);
+ }
+ }
+}
+
+void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty )
+{
+ float obmat[4][4], viewmat[4][4], viewinvmat[4][4], obcol[4];
+ GPUMaterial *gpumat;
+
+ gpumat = GPU_material_from_blender(mBlenderScene, mMat);
+
+ if(!gpumat || !GPU_material_bound(gpumat))
+ return;
+
+ MT_Matrix4x4 model;
+ model.setValue(ms.m_OpenGLMatrix);
+ const MT_Matrix4x4& view = rasty->GetViewMatrix();
+ const MT_Matrix4x4& viewinv = rasty->GetViewInvMatrix();
+
+ // note: getValue gives back column major as needed by OpenGL
+ model.getValue((float*)obmat);
+ view.getValue((float*)viewmat);
+ viewinv.getValue((float*)viewinvmat);
+
+ if(ms.m_bObjectColor)
+ ms.m_RGBAcolor.getValue((float*)obcol);
+ else
+ obcol[0]= obcol[1]= obcol[2]= obcol[3]= 1.0f;
+
+ GPU_material_bind_uniforms(gpumat, obmat, viewmat, viewinvmat, obcol);
+
+ mBlendMode = GPU_material_blend_mode(gpumat, obcol);
+}
+
+int BL_BlenderShader::GetBlendMode()
+{
+ return mBlendMode;
+}
+
+bool BL_BlenderShader::Equals(BL_BlenderShader *blshader)
+{
+ /* to avoid unneeded state switches */
+ return (blshader && mMat == blshader->mMat && mLightLayer == blshader->mLightLayer);
+}
+
+// eof
diff --git a/source/gameengine/Ketsji/BL_BlenderShader.h b/source/gameengine/Ketsji/BL_BlenderShader.h
new file mode 100644
index 00000000000..5c1f59f94ad
--- /dev/null
+++ b/source/gameengine/Ketsji/BL_BlenderShader.h
@@ -0,0 +1,53 @@
+
+#ifndef __BL_GPUSHADER_H__
+#define __BL_GPUSHADER_H__
+
+#include "GPU_material.h"
+
+#include "MT_Matrix4x4.h"
+#include "MT_Matrix3x3.h"
+#include "MT_Tuple2.h"
+#include "MT_Tuple3.h"
+#include "MT_Tuple4.h"
+
+#include "RAS_IPolygonMaterial.h"
+
+#include "KX_Scene.h"
+
+struct Material;
+struct Scene;
+class BL_Material;
+
+#define BL_MAX_ATTRIB 16
+
+/**
+ * BL_BlenderShader
+ * Blender GPU shader material
+ */
+class BL_BlenderShader
+{
+private:
+ KX_Scene *mScene;
+ struct Scene *mBlenderScene;
+ struct Material *mMat;
+ int mLightLayer;
+ int mBlendMode;
+
+ bool VerifyShader();
+
+public:
+ BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer);
+ virtual ~BL_BlenderShader();
+
+ bool Ok();
+ void SetProg(bool enable, double time=0.0);
+
+ int GetAttribNum();
+ void SetAttribs(class RAS_IRasterizer* ras, const BL_Material *mat);
+ void Update(const class RAS_MeshSlot & ms, class RAS_IRasterizer* rasty);
+ int GetBlendMode();
+
+ bool Equals(BL_BlenderShader *blshader);
+};
+
+#endif//__BL_GPUSHADER_H__
diff --git a/source/gameengine/Ketsji/BL_Material.cpp b/source/gameengine/Ketsji/BL_Material.cpp
index 7ed2da590a9..7e3d6984f19 100644
--- a/source/gameengine/Ketsji/BL_Material.cpp
+++ b/source/gameengine/Ketsji/BL_Material.cpp
@@ -34,6 +34,7 @@ BL_Material::BL_Material()
rgb[3] = 0;
IdMode = 0;
ras_mode = 0;
+ glslmat = 0;
tile = 0;
matname = "NoMaterial";
matcolor[0] = 0.5f;
@@ -104,7 +105,8 @@ void BL_Material::GetConversionRGB(unsigned int *nrgb) {
*nrgb = rgb[3];
}
-void BL_Material::SetConversionUV(MT_Point2 *nuv) {
+void BL_Material::SetConversionUV(const STR_String& name, MT_Point2 *nuv) {
+ uvName = name;
uv[0] = *nuv++;
uv[1] = *nuv++;
uv[2] = *nuv++;
@@ -117,7 +119,8 @@ void BL_Material::GetConversionUV(MT_Point2 *nuv){
*nuv++ = uv[2];
*nuv = uv[3];
}
-void BL_Material::SetConversionUV2(MT_Point2 *nuv) {
+void BL_Material::SetConversionUV2(const STR_String& name, MT_Point2 *nuv) {
+ uv2Name = name;
uv2[0] = *nuv++;
uv2[1] = *nuv++;
uv2[2] = *nuv++;
diff --git a/source/gameengine/Ketsji/BL_Material.h b/source/gameengine/Ketsji/BL_Material.h
index 8be91316237..0eaa234566c 100644
--- a/source/gameengine/Ketsji/BL_Material.h
+++ b/source/gameengine/Ketsji/BL_Material.h
@@ -18,9 +18,9 @@ struct EnvMap;
this will default to users available units
to build with more available, just increment this value
although the more you add the slower the search time will be.
- we will go for three, which should be enough
+ we will go for eight, which should be enough
*/
-#define MAXTEX 3//match in RAS_TexVert & RAS_OpenGLRasterizer
+#define MAXTEX 8 //match in RAS_TexVert & RAS_OpenGLRasterizer
// different mapping modes
class BL_Mapping
@@ -47,6 +47,7 @@ public:
int IdMode;
unsigned int ras_mode;
+ bool glslmat;
STR_String texname[MAXTEX];
unsigned int flag[MAXTEX];
@@ -82,13 +83,16 @@ public:
MT_Point2 uv[4];
MT_Point2 uv2[4];
+ STR_String uvName;
+ STR_String uv2Name;
+
void SetConversionRGB(unsigned int *rgb);
void GetConversionRGB(unsigned int *rgb);
- void SetConversionUV(MT_Point2 *uv);
+ void SetConversionUV(const STR_String& name, MT_Point2 *uv);
void GetConversionUV(MT_Point2 *uv);
- void SetConversionUV2(MT_Point2 *uv);
+ void SetConversionUV2(const STR_String& name, MT_Point2 *uv);
void GetConversionUV2(MT_Point2 *uv);
void SetSharedMaterial(bool v);
@@ -125,8 +129,7 @@ enum BL_flag
TEXALPHA=8, // use alpha combiner functions
TEXNEG=16, // negate blending
HASIPO=32,
- USENEGALPHA=64,
- ALPHA_TEST=128
+ USENEGALPHA=64
};
// BL_Material::ras_mode
@@ -135,8 +138,8 @@ enum BL_ras_mode
POLY_VIS=1,
COLLIDER=2,
ZSORT=4,
- TRANSP=8,
- TRIANGLE=16,
+ ALPHA=8,
+ // TRIANGLE=16,
USE_LIGHT=32,
WIRE=64
};
diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp
index 3b74b74727a..80892764089 100644
--- a/source/gameengine/Ketsji/BL_Shader.cpp
+++ b/source/gameengine/Ketsji/BL_Shader.cpp
@@ -1,20 +1,5 @@
-
-#ifdef WIN32
-#include <windows.h>
-#endif // WIN32
-#ifdef __APPLE__
-#define GL_GLEXT_LEGACY 1
-#include <OpenGL/gl.h>
-#include <OpenGL/glu.h>
-#else
-#include <GL/gl.h>
-#if defined(__sun__) && !defined(__sparc__)
-#include <mesa/glu.h>
-#else
-#include <GL/glu.h>
-#endif
-#endif
+#include "GL/glew.h"
#include <iostream>
#include "BL_Shader.h"
@@ -30,7 +15,6 @@
#include "RAS_MeshObject.h"
#include "RAS_IRasterizer.h"
-//using namespace bgl;
#define spit(x) std::cout << x << std::endl;
#define SORT_UNIFORMS 1
@@ -45,7 +29,7 @@ BL_Uniform::BL_Uniform(int data_size)
mDataLen(data_size)
{
#ifdef SORT_UNIFORMS
- MT_assert(mDataLen <= UNIFORM_MAX_LEN);
+ MT_assert((int)mDataLen <= UNIFORM_MAX_LEN);
mData = (void*)MEM_mallocN(mDataLen, "shader-uniform-alloc");
#endif
}
@@ -62,7 +46,6 @@ BL_Uniform::~BL_Uniform()
void BL_Uniform::Apply(class BL_Shader *shader)
{
-#ifdef GL_ARB_shader_objects
#ifdef SORT_UNIFORMS
MT_assert(mType > UNI_NONE && mType < UNI_MAX && mData);
@@ -73,48 +56,47 @@ void BL_Uniform::Apply(class BL_Shader *shader)
{
case UNI_FLOAT: {
float *f = (float*)mData;
- bgl::blUniform1fARB(mLoc,(GLfloat)*f);
+ glUniform1fARB(mLoc,(GLfloat)*f);
}break;
case UNI_INT: {
int *f = (int*)mData;
- bgl::blUniform1iARB(mLoc, (GLint)*f);
+ glUniform1iARB(mLoc, (GLint)*f);
}break;
case UNI_FLOAT2: {
float *f = (float*)mData;
- bgl::blUniform2fvARB(mLoc,1, (GLfloat*)f);
+ glUniform2fvARB(mLoc,1, (GLfloat*)f);
}break;
case UNI_FLOAT3: {
float *f = (float*)mData;
- bgl::blUniform3fvARB(mLoc,1,(GLfloat*)f);
+ glUniform3fvARB(mLoc,1,(GLfloat*)f);
}break;
case UNI_FLOAT4: {
float *f = (float*)mData;
- bgl::blUniform4fvARB(mLoc,1,(GLfloat*)f);
+ glUniform4fvARB(mLoc,1,(GLfloat*)f);
}break;
case UNI_INT2: {
int *f = (int*)mData;
- bgl::blUniform2ivARB(mLoc,1,(GLint*)f);
+ glUniform2ivARB(mLoc,1,(GLint*)f);
}break;
case UNI_INT3: {
int *f = (int*)mData;
- bgl::blUniform3ivARB(mLoc,1,(GLint*)f);
+ glUniform3ivARB(mLoc,1,(GLint*)f);
}break;
case UNI_INT4: {
int *f = (int*)mData;
- bgl::blUniform4ivARB(mLoc,1,(GLint*)f);
+ glUniform4ivARB(mLoc,1,(GLint*)f);
}break;
case UNI_MAT4: {
float *f = (float*)mData;
- bgl::blUniformMatrix4fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f);
+ glUniformMatrix4fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f);
}break;
case UNI_MAT3: {
float *f = (float*)mData;
- bgl::blUniformMatrix3fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f);
+ glUniformMatrix3fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f);
}break;
}
mDirty = false;
#endif
-#endif
}
void BL_Uniform::SetData(int location, int type,bool transpose)
@@ -143,17 +125,14 @@ BL_Shader::BL_Shader(PyTypeObject *T)
mError(0),
mDirty(true)
{
- // if !RAS_EXT_support._ARB_shader_objects this class will not be used
+ // if !GLEW_ARB_shader_objects this class will not be used
//for (int i=0; i<MAXTEX; i++) {
// mSampler[i] = BL_Sampler();
//}
}
-using namespace bgl;
-
BL_Shader::~BL_Shader()
{
-#ifdef GL_ARB_shader_objects
//for (int i=0; i<MAXTEX; i++){
// if(mSampler[i].mOwn) {
// if(mSampler[i].mTexture)
@@ -163,14 +142,13 @@ BL_Shader::~BL_Shader()
ClearUniforms();
if( mShader ) {
- bgl::blDeleteObjectARB(mShader);
+ glDeleteObjectARB(mShader);
mShader = 0;
}
vertProg = 0;
fragProg = 0;
mOk = 0;
- bgl::blUseProgramObjectARB(0);
-#endif//GL_ARB_shader_objects
+ glUseProgramObjectARB(0);
}
void BL_Shader::ClearUniforms()
@@ -265,8 +243,6 @@ void BL_Shader::UnloadShader()
bool BL_Shader::LinkProgram()
{
-#ifdef GL_ARB_shader_objects
-
int vertlen = 0, fraglen=0, proglen=0;
int vertstatus=0, fragstatus=0, progstatus=0;
unsigned int tmpVert=0, tmpFrag=0, tmpProg=0;
@@ -280,25 +256,25 @@ bool BL_Shader::LinkProgram()
spit("Invalid GLSL sources");
return false;
}
- if( !RAS_EXT_support._ARB_fragment_shader) {
+ if( !GLEW_ARB_fragment_shader) {
spit("Fragment shaders not supported");
return false;
}
- if( !RAS_EXT_support._ARB_vertex_shader) {
+ if( !GLEW_ARB_vertex_shader) {
spit("Vertex shaders not supported");
return false;
}
// -- vertex shader ------------------
- tmpVert = bgl::blCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
- bgl::blShaderSourceARB(tmpVert, 1, (const char**)&vertProg, 0);
- bgl::blCompileShaderARB(tmpVert);
- bgl::blGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB,(GLint*) &vertlen);
+ tmpVert = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
+ glShaderSourceARB(tmpVert, 1, (const char**)&vertProg, 0);
+ glCompileShaderARB(tmpVert);
+ glGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB,(GLint*) &vertlen);
// print info if any
if( vertlen > 0 && vertlen < MAX_LOG_LEN){
logInf = (char*)MEM_mallocN(vertlen, "vert-log");
- bgl::blGetInfoLogARB(tmpVert, vertlen, (GLsizei*)&char_len, logInf);
+ glGetInfoLogARB(tmpVert, vertlen, (GLsizei*)&char_len, logInf);
if(char_len >0) {
spit("---- Vertex Shader Error ----");
spit(logInf);
@@ -307,20 +283,20 @@ bool BL_Shader::LinkProgram()
logInf=0;
}
// check for compile errors
- bgl::blGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB,(GLint*)&vertstatus);
+ glGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB,(GLint*)&vertstatus);
if(!vertstatus) {
spit("---- Vertex shader failed to compile ----");
goto programError;
}
// -- fragment shader ----------------
- tmpFrag = bgl::blCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
- bgl::blShaderSourceARB(tmpFrag, 1,(const char**)&fragProg, 0);
- bgl::blCompileShaderARB(tmpFrag);
- bgl::blGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &fraglen);
+ tmpFrag = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+ glShaderSourceARB(tmpFrag, 1,(const char**)&fragProg, 0);
+ glCompileShaderARB(tmpFrag);
+ glGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &fraglen);
if(fraglen >0 && fraglen < MAX_LOG_LEN){
logInf = (char*)MEM_mallocN(fraglen, "frag-log");
- bgl::blGetInfoLogARB(tmpFrag, fraglen,(GLsizei*) &char_len, logInf);
+ glGetInfoLogARB(tmpFrag, fraglen,(GLsizei*) &char_len, logInf);
if(char_len >0) {
spit("---- Fragment Shader Error ----");
spit(logInf);
@@ -329,7 +305,7 @@ bool BL_Shader::LinkProgram()
logInf=0;
}
- bgl::blGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*) &fragstatus);
+ glGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*) &fragstatus);
if(!fragstatus){
spit("---- Fragment shader failed to compile ----");
goto programError;
@@ -338,17 +314,17 @@ bool BL_Shader::LinkProgram()
// -- program ------------------------
// set compiled vert/frag shader & link
- tmpProg = bgl::blCreateProgramObjectARB();
- bgl::blAttachObjectARB(tmpProg, tmpVert);
- bgl::blAttachObjectARB(tmpProg, tmpFrag);
- bgl::blLinkProgramARB(tmpProg);
- bgl::blGetObjectParameterivARB(tmpProg, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &proglen);
- bgl::blGetObjectParameterivARB(tmpProg, GL_OBJECT_LINK_STATUS_ARB, (GLint*) &progstatus);
+ tmpProg = glCreateProgramObjectARB();
+ glAttachObjectARB(tmpProg, tmpVert);
+ glAttachObjectARB(tmpProg, tmpFrag);
+ glLinkProgramARB(tmpProg);
+ glGetObjectParameterivARB(tmpProg, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &proglen);
+ glGetObjectParameterivARB(tmpProg, GL_OBJECT_LINK_STATUS_ARB, (GLint*) &progstatus);
if(proglen > 0 && proglen < MAX_LOG_LEN) {
logInf = (char*)MEM_mallocN(proglen, "prog-log");
- bgl::blGetInfoLogARB(tmpProg, proglen, (GLsizei*)&char_len, logInf);
+ glGetInfoLogARB(tmpProg, proglen, (GLsizei*)&char_len, logInf);
if(char_len >0) {
spit("---- GLSL Program ----");
spit(logInf);
@@ -364,24 +340,24 @@ bool BL_Shader::LinkProgram()
// set
mShader = tmpProg;
- bgl::blDeleteObjectARB(tmpVert);
- bgl::blDeleteObjectARB(tmpFrag);
+ glDeleteObjectARB(tmpVert);
+ glDeleteObjectARB(tmpFrag);
mOk = 1;
mError = 0;
return true;
programError:
if(tmpVert) {
- bgl::blDeleteObjectARB(tmpVert);
+ glDeleteObjectARB(tmpVert);
tmpVert=0;
}
if(tmpFrag) {
- bgl::blDeleteObjectARB(tmpFrag);
+ glDeleteObjectARB(tmpFrag);
tmpFrag=0;
}
if(tmpProg) {
- bgl::blDeleteObjectARB(tmpProg);
+ glDeleteObjectARB(tmpProg);
tmpProg=0;
}
@@ -389,9 +365,6 @@ programError:
mUse = 0;
mError = 1;
return false;
-#else
- return false;
-#endif//GL_ARB_shader_objects
}
const char *BL_Shader::GetVertPtr()
@@ -427,15 +400,13 @@ unsigned int BL_Shader::GetProg()
void BL_Shader::SetSampler(int loc, int unit)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
- bgl::blUniform1iARB(loc, unit);
+ glUniform1iARB(loc, unit);
}
-#endif
}
//
//void BL_Shader::InitializeSampler(int unit, BL_Texture* texture)
@@ -448,37 +419,33 @@ void BL_Shader::SetSampler(int loc, int unit)
void BL_Shader::SetProg(bool enable)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
if( mShader != 0 && mOk && enable) {
- bgl::blUseProgramObjectARB(mShader);
+ glUseProgramObjectARB(mShader);
}
else {
- bgl::blUseProgramObjectARB(0);
+ glUseProgramObjectARB(0);
}
}
-#endif
}
-void BL_Shader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty )
+void BL_Shader::Update( const RAS_MeshSlot & ms, RAS_IRasterizer* rasty )
{
-#ifdef GL_ARB_shader_objects
if(!Ok() || !mPreDef.size())
return;
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
MT_Matrix4x4 model;
model.setValue(ms.m_OpenGLMatrix);
- MT_Matrix4x4 view;
- rasty->GetViewMatrix(view);
+ const MT_Matrix4x4& view = rasty->GetViewMatrix();
if(mAttr==SHD_TANGENT)
ms.m_mesh->SetMeshModified(true);
@@ -557,13 +524,15 @@ void BL_Shader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty )
}
case VIEWMATRIX_INVERSE:
{
- view.invert();
+ MT_Matrix4x4 viewinv = view;
+ viewinv.invert();
SetUniform(uni->mLoc, view);
break;
}
case VIEWMATRIX_INVERSETRANSPOSE:
{
- view.invert();
+ MT_Matrix4x4 viewinv = view;
+ viewinv.invert();
SetUniform(uni->mLoc, view, true);
break;
}
@@ -577,210 +546,186 @@ void BL_Shader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty )
}
}
}
-#endif
}
int BL_Shader::GetAttribLocation(const STR_String& name)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
- return bgl::blGetAttribLocationARB(mShader, name.ReadPtr());
+ return glGetAttribLocationARB(mShader, name.ReadPtr());
}
-#endif
+
return -1;
}
void BL_Shader::BindAttribute(const STR_String& attr, int loc)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
- bgl::blBindAttribLocationARB(mShader, loc, attr.ReadPtr());
+ glBindAttribLocationARB(mShader, loc, attr.ReadPtr());
}
-#endif
}
int BL_Shader::GetUniformLocation(const STR_String& name)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
MT_assert(mShader!=0);
- int location = bgl::blGetUniformLocationARB(mShader, name.ReadPtr());
+ int location = glGetUniformLocationARB(mShader, name.ReadPtr());
if(location == -1)
spit("Invalid uniform value: " << name.ReadPtr() << ".");
return location;
}
-#endif
+
return -1;
}
void BL_Shader::SetUniform(int uniform, const MT_Tuple2& vec)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
float value[2];
vec.getValue(value);
- bgl::blUniform2fvARB(uniform, 1, value);
+ glUniform2fvARB(uniform, 1, value);
}
-#endif
}
void BL_Shader::SetUniform(int uniform, const MT_Tuple3& vec)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
float value[3];
vec.getValue(value);
- bgl::blUniform3fvARB(uniform, 1, value);
+ glUniform3fvARB(uniform, 1, value);
}
-#endif
}
void BL_Shader::SetUniform(int uniform, const MT_Tuple4& vec)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
float value[4];
vec.getValue(value);
- bgl::blUniform4fvARB(uniform, 1, value);
+ glUniform4fvARB(uniform, 1, value);
}
-#endif
}
void BL_Shader::SetUniform(int uniform, const unsigned int& val)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
- bgl::blUniform1iARB(uniform, val);
+ glUniform1iARB(uniform, val);
}
-#endif
}
void BL_Shader::SetUniform(int uniform, const int val)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
- bgl::blUniform1iARB(uniform, val);
+ glUniform1iARB(uniform, val);
}
-#endif
}
void BL_Shader::SetUniform(int uniform, const float& val)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
- bgl::blUniform1fARB(uniform, val);
+ glUniform1fARB(uniform, val);
}
-#endif
}
void BL_Shader::SetUniform(int uniform, const MT_Matrix4x4& vec, bool transpose)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
float value[16];
+ // note: getValue gives back column major as needed by OpenGL
vec.getValue(value);
- bgl::blUniformMatrix4fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value);
+ glUniformMatrix4fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value);
}
-#endif
}
void BL_Shader::SetUniform(int uniform, const MT_Matrix3x3& vec, bool transpose)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
float value[9];
value[0] = (float)vec[0][0]; value[1] = (float)vec[1][0]; value[2] = (float)vec[2][0];
value[3] = (float)vec[0][1]; value[4] = (float)vec[1][1]; value[5] = (float)vec[2][1];
value[6] = (float)vec[0][2]; value[7] = (float)vec[1][2]; value[7] = (float)vec[2][2];
- bgl::blUniformMatrix3fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value);
+ glUniformMatrix3fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value);
}
-#endif
}
void BL_Shader::SetUniform(int uniform, const float* val, int len)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
if(len == 2)
- bgl::blUniform2fvARB(uniform, 1,(GLfloat*)val);
+ glUniform2fvARB(uniform, 1,(GLfloat*)val);
else if (len == 3)
- bgl::blUniform3fvARB(uniform, 1,(GLfloat*)val);
+ glUniform3fvARB(uniform, 1,(GLfloat*)val);
else if (len == 4)
- bgl::blUniform4fvARB(uniform, 1,(GLfloat*)val);
+ glUniform4fvARB(uniform, 1,(GLfloat*)val);
else
MT_assert(0);
}
-#endif
}
void BL_Shader::SetUniform(int uniform, const int* val, int len)
{
-#ifdef GL_ARB_shader_objects
- if( RAS_EXT_support._ARB_fragment_shader &&
- RAS_EXT_support._ARB_vertex_shader &&
- RAS_EXT_support._ARB_shader_objects
+ if( GLEW_ARB_fragment_shader &&
+ GLEW_ARB_vertex_shader &&
+ GLEW_ARB_shader_objects
)
{
if(len == 2)
- bgl::blUniform2ivARB(uniform, 1, (GLint*)val);
+ glUniform2ivARB(uniform, 1, (GLint*)val);
else if (len == 3)
- bgl::blUniform3ivARB(uniform, 1, (GLint*)val);
+ glUniform3ivARB(uniform, 1, (GLint*)val);
else if (len == 4)
- bgl::blUniform4ivARB(uniform, 1, (GLint*)val);
+ glUniform4ivARB(uniform, 1, (GLint*)val);
else
MT_assert(0);
}
-#endif
}
@@ -848,7 +793,6 @@ PyParentObject BL_Shader::Parents[] = {
KX_PYMETHODDEF_DOC( BL_Shader, setSource," setSource(vertexProgram, fragmentProgram)" )
{
-#ifdef GL_ARB_shader_objects
if(mShader !=0 && mOk )
{
// already set...
@@ -861,7 +805,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setSource," setSource(vertexProgram, fragmentProg
vertProg = v;
fragProg = f;
if( LinkProgram() ) {
- bgl::blUseProgramObjectARB( mShader );
+ glUseProgramObjectARB( mShader );
mUse = apply!=0;
Py_Return;
}
@@ -871,23 +815,18 @@ KX_PYMETHODDEF_DOC( BL_Shader, setSource," setSource(vertexProgram, fragmentProg
Py_Return;
}
return NULL;
-#else
- Py_Return;
-#endif
}
KX_PYMETHODDEF_DOC( BL_Shader, delSource, "delSource( )" )
{
-#ifdef GL_ARB_shader_objects
ClearUniforms();
- bgl::blUseProgramObjectARB(0);
+ glUseProgramObjectARB(0);
- bgl::blDeleteObjectARB(mShader);
+ glDeleteObjectARB(mShader);
mShader = 0;
mOk = 0;
mUse = 0;
-#endif
Py_Return;
}
@@ -908,25 +847,23 @@ KX_PYMETHODDEF_DOC( BL_Shader, getFragmentProg ,"getFragmentProg( )" )
KX_PYMETHODDEF_DOC( BL_Shader, validate, "validate()")
{
-#ifdef GL_ARB_shader_objects
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
if(mShader==0) {
PyErr_Format(PyExc_TypeError, "invalid shader object");
return NULL;
}
int stat = 0;
- bgl::blValidateProgramARB(mShader);
- bgl::blGetObjectParameterivARB(mShader, GL_OBJECT_VALIDATE_STATUS_ARB,(GLint*) &stat);
+ glValidateProgramARB(mShader);
+ glGetObjectParameterivARB(mShader, GL_OBJECT_VALIDATE_STATUS_ARB,(GLint*) &stat);
if(stat > 0 && stat < MAX_LOG_LEN) {
int char_len=0;
char *logInf = (char*)MEM_mallocN(stat, "validate-log");
- bgl::blGetInfoLogARB(mShader, stat,(GLsizei*) &char_len, logInf);
+ glGetInfoLogARB(mShader, stat,(GLsizei*) &char_len, logInf);
if(char_len >0) {
spit("---- GLSL Validation ----");
spit(logInf);
@@ -934,7 +871,6 @@ KX_PYMETHODDEF_DOC( BL_Shader, validate, "validate()")
MEM_freeN(logInf);
logInf=0;
}
-#endif//GL_ARB_shader_objects
Py_Return;
}
@@ -942,11 +878,10 @@ KX_PYMETHODDEF_DOC( BL_Shader, validate, "validate()")
KX_PYMETHODDEF_DOC( BL_Shader, setSampler, "setSampler(name, index)" )
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- char *uniform="";
+ const char *uniform="";
int index=-1;
if(PyArg_ParseTuple(args, "si", &uniform, &index))
{
@@ -965,7 +900,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setSampler, "setSampler(name, index)" )
//else
// spit("Invalid texture sample index: " << index);
}
- Py_Return;
+ Py_RETURN_NONE;
}
return NULL;
}
@@ -984,11 +919,10 @@ KX_PYMETHODDEF_DOC( BL_Shader, setNumberOfPasses, "setNumberOfPasses( max-pass )
KX_PYMETHODDEF_DOC( BL_Shader, setUniform1f, "setUniform1f(name, fx)" )
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- char *uniform="";
+ const char *uniform="";
float value=0;
if(PyArg_ParseTuple(args, "sf", &uniform, &value ))
{
@@ -1010,10 +944,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1f, "setUniform1f(name, fx)" )
KX_PYMETHODDEF_DOC( BL_Shader, setUniform2f , "setUniform2f(name, fx, fy)")
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- char *uniform="";
+ const char *uniform="";
float array[2]={ 0,0 };
if(PyArg_ParseTuple(args, "sff", &uniform, &array[0],&array[1] ))
{
@@ -1035,10 +968,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2f , "setUniform2f(name, fx, fy)")
KX_PYMETHODDEF_DOC( BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ")
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- char *uniform="";
+ const char *uniform="";
float array[3]={0,0,0};
if(PyArg_ParseTuple(args, "sfff", &uniform, &array[0],&array[1],&array[2]))
{
@@ -1061,10 +993,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ")
KX_PYMETHODDEF_DOC( BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ")
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- char *uniform="";
+ const char *uniform="";
float array[4]={0,0,0,0};
if(PyArg_ParseTuple(args, "sffff", &uniform, &array[0],&array[1],&array[2], &array[3]))
{
@@ -1086,10 +1017,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) "
KX_PYMETHODDEF_DOC( BL_Shader, setUniform1i, "setUniform1i(name, ix)" )
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- char *uniform="";
+ const char *uniform="";
int value=0;
if(PyArg_ParseTuple(args, "si", &uniform, &value ))
{
@@ -1111,10 +1041,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1i, "setUniform1i(name, ix)" )
KX_PYMETHODDEF_DOC( BL_Shader, setUniform2i , "setUniform2i(name, ix, iy)")
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- char *uniform="";
+ const char *uniform="";
int array[2]={ 0,0 };
if(PyArg_ParseTuple(args, "sii", &uniform, &array[0],&array[1] ))
{
@@ -1136,11 +1065,10 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2i , "setUniform2i(name, ix, iy)")
KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ")
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- char *uniform="";
+ const char *uniform="";
int array[3]={0,0,0};
if(PyArg_ParseTuple(args, "siii", &uniform, &array[0],&array[1],&array[2]))
{
@@ -1161,10 +1089,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ")
KX_PYMETHODDEF_DOC( BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) ")
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- char *uniform="";
+ const char *uniform="";
int array[4]={0,0,0, 0};
if(PyArg_ParseTuple(args, "siiii", &uniform, &array[0],&array[1],&array[2], &array[3] ))
{
@@ -1185,10 +1112,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) "
KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv , "setUniformfv( float (list2 or list3 or list4) )")
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- char*uniform = "";
+ const char *uniform = "";
PyObject *listPtr =0;
float array_data[4] = {0.f,0.f,0.f,0.f};
@@ -1255,10 +1181,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv , "setUniformfv( float (list2 or lis
KX_PYMETHODDEF_DOC( BL_Shader, setUniformiv, "setUniformiv( int (list2 or list3 or list4) )")
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- char*uniform = "";
+ const char *uniform = "";
PyObject *listPtr =0;
int array_data[4] = {0,0,0,0};
@@ -1328,8 +1253,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix4,
"setUniformMatrix4(uniform-name, mat-4x4, transpose(row-major=true, col-major=false)" )
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
float matr[16] = {
@@ -1339,7 +1263,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix4,
0,0,0,1
};
- char *uniform="";
+ const char *uniform="";
PyObject *matrix=0;
int transp=1; // MT_ is row major so transpose by default....
if(PyArg_ParseTuple(args, "sO|i",&uniform, &matrix,&transp))
@@ -1371,8 +1295,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix3,
"setUniformMatrix3(uniform-name, list[3x3], transpose(row-major=true, col-major=false)" )
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
float matr[9] = {
@@ -1381,7 +1304,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix3,
0,0,1,
};
- char *uniform="";
+ const char *uniform="";
PyObject *matrix=0;
int transp=1; // MT_ is row major so transpose by default....
if(PyArg_ParseTuple(args, "sO|i",&uniform, &matrix,&transp))
@@ -1411,10 +1334,8 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix3,
KX_PYMETHODDEF_DOC( BL_Shader, setAttrib, "setAttrib(enum)" )
{
-#ifdef GL_ARB_shader_objects
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
int attr=0;
if(PyArg_ParseTuple(args, "i", &attr )) {
@@ -1423,23 +1344,21 @@ KX_PYMETHODDEF_DOC( BL_Shader, setAttrib, "setAttrib(enum)" )
return NULL;
}
mAttr=SHD_TANGENT;
- bgl::blUseProgramObjectARB(mShader);
- bgl::blBindAttribLocationARB(mShader, mAttr, "Tangent");
+ glUseProgramObjectARB(mShader);
+ glBindAttribLocationARB(mShader, mAttr, "Tangent");
Py_Return;
}
return NULL;
-#endif
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniformDef, "setUniformDef(name, enum)" )
{
if(mError) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- char *uniform="";
+ const char *uniform="";
int nloc=0;
if(PyArg_ParseTuple(args, "si",&uniform, &nloc))
{
diff --git a/source/gameengine/Ketsji/BL_Shader.h b/source/gameengine/Ketsji/BL_Shader.h
index 8f303454087..18ca8f8b4f8 100644
--- a/source/gameengine/Ketsji/BL_Shader.h
+++ b/source/gameengine/Ketsji/BL_Shader.h
@@ -102,8 +102,8 @@ private:
bool mUse; // ...
//BL_Sampler mSampler[MAXTEX]; // Number of samplers
int mAttr; // Tangent attribute
- char* vertProg; // Vertex program string
- char* fragProg; // Fragment program string
+ const char* vertProg; // Vertex program string
+ const char* fragProg; // Fragment program string
bool mError; // ...
bool mDirty; //
@@ -177,7 +177,7 @@ public:
void UnloadShader();
// Update predefined uniforms each render call
- void Update(const class KX_MeshSlot & ms, class RAS_IRasterizer* rasty);
+ void Update(const class RAS_MeshSlot & ms, class RAS_IRasterizer* rasty);
//// Set sampler units (copied)
//void InitializeSampler(int unit, BL_Texture* texture );
diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp
index 53e1af46e4e..f0ef84032f7 100644
--- a/source/gameengine/Ketsji/BL_Texture.cpp
+++ b/source/gameengine/Ketsji/BL_Texture.cpp
@@ -1,22 +1,10 @@
// ------------------------------------
-#ifdef WIN32
-#include <windows.h>
-#endif // WIN32
-#ifdef __APPLE__
-#define GL_GLEXT_LEGACY 1
-#include <OpenGL/gl.h>
-#include <OpenGL/glu.h>
-#else
-#include <GL/gl.h>
-#if defined(__sun__) && !defined(__sparc__)
-#include <mesa/glu.h>
-#else
-#include <GL/glu.h>
-#endif
-#endif
+
+#include "GL/glew.h"
#include <iostream>
#include <map>
+#include <stdlib.h>
#include "BL_Material.h"
#include "BL_Texture.h"
@@ -29,15 +17,11 @@
#include "BLI_blenlib.h"
#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
-#include "RAS_OpenGLRasterizer/ARB_multitexture.h"
#include "RAS_ICanvas.h"
#include "RAS_Rect.h"
#include "KX_GameObject.h"
-
-using namespace bgl;
-
#define spit(x) std::cout << x << std::endl;
#include "MEM_guardedalloc.h"
@@ -219,9 +203,7 @@ void BL_Texture::InitNonPow2Tex(unsigned int *pix,int x,int y,bool mipmap)
bool BL_Texture::InitCubeMap(int unit, EnvMap *cubemap)
{
-#ifdef GL_ARB_texture_cube_map
-
- if (!RAS_EXT_support._ARB_texture_cube_map)
+ if (!GLEW_ARB_texture_cube_map)
{
spit("cubemaps not supported");
mOk = false;
@@ -311,9 +293,8 @@ bool BL_Texture::InitCubeMap(int unit, EnvMap *cubemap)
glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
- #ifdef GL_VERSION_1_2
- glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
- #endif
+ if(GLEW_VERSION_1_2)
+ glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
if (needs_split)
my_free_envmapdata(cubemap);
@@ -325,13 +306,6 @@ bool BL_Texture::InitCubeMap(int unit, EnvMap *cubemap)
mOk = IsValid();
return mOk;
-
-#else
-
- mOk = false;
- return mOk;
-
-#endif//GL_ARB_texture_cube_map
}
bool BL_Texture::IsValid()
@@ -360,51 +334,41 @@ unsigned int BL_Texture::GetTextureType() const
int BL_Texture::GetMaxUnits()
{
GLint unit=0;
-#ifdef GL_ARB_multitexture
- if(RAS_EXT_support._ARB_multitexture) {
+
+ if(GLEW_ARB_multitexture) {
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &unit);
return (MAXTEX>=unit?unit:MAXTEX);
}
-#endif
+
return 0;
}
void BL_Texture::ActivateFirst()
{
-#ifdef GL_ARB_multitexture
- if(RAS_EXT_support._ARB_multitexture)
- bgl::blActiveTextureARB(GL_TEXTURE0_ARB);
-#endif
+ if(GLEW_ARB_multitexture)
+ glActiveTextureARB(GL_TEXTURE0_ARB);
}
void BL_Texture::ActivateUnit(int unit)
{
-#ifdef GL_ARB_multitexture
- if(RAS_EXT_support._ARB_multitexture)
+ if(GLEW_ARB_multitexture)
if(unit <= MAXTEX)
- bgl::blActiveTextureARB(GL_TEXTURE0_ARB+unit);
-#endif
+ glActiveTextureARB(GL_TEXTURE0_ARB+unit);
}
void BL_Texture::DisableUnit()
{
-#ifdef GL_ARB_multitexture
- if(RAS_EXT_support._ARB_multitexture)
- bgl::blActiveTextureARB(GL_TEXTURE0_ARB+mUnit);
-
-#endif
-
+ if(GLEW_ARB_multitexture)
+ glActiveTextureARB(GL_TEXTURE0_ARB+mUnit);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
- #ifdef GL_ARB_texture_cube_map
- if(RAS_EXT_support._ARB_texture_cube_map && glIsEnabled(GL_TEXTURE_CUBE_MAP_ARB))
+ if(GLEW_ARB_texture_cube_map && glIsEnabled(GL_TEXTURE_CUBE_MAP_ARB))
glDisable(GL_TEXTURE_CUBE_MAP_ARB);
else
- #endif
{
if (glIsEnabled(GL_TEXTURE_2D))
glDisable(GL_TEXTURE_2D);
@@ -420,11 +384,9 @@ void BL_Texture::DisableUnit()
void BL_Texture::DisableAllTextures()
{
-#ifdef GL_ARB_multitexture
- glDisable(GL_BLEND);
for(int i=0; i<MAXTEX; i++) {
- if(RAS_EXT_support._ARB_multitexture)
- bgl::blActiveTextureARB(GL_TEXTURE0_ARB+i);
+ if(GLEW_ARB_multitexture)
+ glActiveTextureARB(GL_TEXTURE0_ARB+i);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
@@ -436,38 +398,29 @@ void BL_Texture::DisableAllTextures()
glDisable(GL_TEXTURE_GEN_Q);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
}
- if(RAS_EXT_support._ARB_multitexture)
- bgl::blActiveTextureARB(GL_TEXTURE0_ARB);
-#endif
+ if(GLEW_ARB_multitexture)
+ glActiveTextureARB(GL_TEXTURE0_ARB);
}
void BL_Texture::ActivateTexture()
{
-#ifdef GL_ARB_multitexture
- if(RAS_EXT_support._ARB_multitexture)
- bgl::blActiveTextureARB(GL_TEXTURE0_ARB+mUnit);
+ if(GLEW_ARB_multitexture)
+ glActiveTextureARB(GL_TEXTURE0_ARB+mUnit);
-#ifdef GL_ARB_texture_cube_map
- if (mType == GL_TEXTURE_CUBE_MAP_ARB && RAS_EXT_support._ARB_texture_cube_map)
+ if (mType == GL_TEXTURE_CUBE_MAP_ARB && GLEW_ARB_texture_cube_map)
{
glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, mTexture );
glEnable(GL_TEXTURE_CUBE_MAP_ARB);
}
- else
-#endif
- {
-
- #ifdef GL_ARB_texture_cube_map
- if(RAS_EXT_support._ARB_texture_cube_map )
+ else {
+ if(GLEW_ARB_texture_cube_map )
glDisable(GL_TEXTURE_CUBE_MAP_ARB);
- #endif
glBindTexture( GL_TEXTURE_2D, mTexture );
glEnable(GL_TEXTURE_2D);
}
-#endif
}
void BL_Texture::SetMapping(int mode)
@@ -481,9 +434,8 @@ void BL_Texture::SetMapping(int mode)
return;
}
-#ifdef GL_ARB_texture_cube_map
if( mType == GL_TEXTURE_CUBE_MAP_ARB &&
- RAS_EXT_support._ARB_texture_cube_map &&
+ GLEW_ARB_texture_cube_map &&
mode &USEREFL)
{
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB );
@@ -497,7 +449,6 @@ void BL_Texture::SetMapping(int mode)
return;
}
else
-#endif
{
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
@@ -512,11 +463,7 @@ void BL_Texture::SetMapping(int mode)
void BL_Texture::setTexEnv(BL_Material *mat, bool modulate)
{
-#ifndef GL_ARB_texture_env_combine
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
- return;
-#else
- if(modulate || !RAS_EXT_support._ARB_texture_env_combine){
+ if(modulate || !GLEW_ARB_texture_env_combine){
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
return;
}
@@ -650,7 +597,6 @@ void BL_Texture::setTexEnv(BL_Material *mat, bool modulate)
glTexEnvf( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0);
glEndList();
-#endif //!GL_ARB_texture_env_combine
}
int BL_Texture::GetPow2(int n)
diff --git a/source/gameengine/Ketsji/BL_Texture.h b/source/gameengine/Ketsji/BL_Texture.h
index 0d0c7a277f2..830ffceb0f7 100644
--- a/source/gameengine/Ketsji/BL_Texture.h
+++ b/source/gameengine/Ketsji/BL_Texture.h
@@ -59,6 +59,14 @@ public:
void SetMapping(int mode);
void DisableUnit();
void setTexEnv(BL_Material *mat, bool modulate=false);
+ unsigned int swapTexture (unsigned int newTex) {
+ // swap texture codes
+ unsigned int tmp = mTexture;
+ mTexture = newTex;
+ // return original texture code
+ return tmp;
+ }
+
};
#endif//__BL_TEXTURE_H__
diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt
index a10b07ff491..d054894589f 100644
--- a/source/gameengine/Ketsji/CMakeLists.txt
+++ b/source/gameengine/Ketsji/CMakeLists.txt
@@ -26,6 +26,19 @@
FILE(GLOB SRC *.cpp)
+#XXX disabled for 2.5 because of missing python
+#SET(SRC
+# ${SRC}
+# ../../../source/blender/python/api2_2x/Mathutils.c
+# ../../../source/blender/python/api2_2x/constant.c
+# ../../../source/blender/python/api2_2x/euler.c
+# ../../../source/blender/python/api2_2x/gen_utils.c
+# ../../../source/blender/python/api2_2x/matrix.c
+# ../../../source/blender/python/api2_2x/point.c
+# ../../../source/blender/python/api2_2x/quat.c
+# ../../../source/blender/python/api2_2x/vector.c
+#)
+
SET(INC
.
../../../source/kernel/gen_system
@@ -39,7 +52,8 @@ SET(INC
../../../intern/moto/include
../../../source/gameengine/Ketsji
../../../source/blender/blenlib
- ../../../source/blender/blenkernel
+ ../../../source/blender/blenkernel
+ ../../../source/blender/python/api2_2x
../../../source/blender
../../../source/blender/include
../../../source/blender/makesdna
@@ -57,8 +71,10 @@ SET(INC
../../../intern/SoundSystem
../../../source/blender/misc
../../../source/blender/blenloader
+ ../../../source/blender/gpu
../../../extern/bullet2/src
../../../extern/solid
+ ../../../extern/glew/include
${PYTHON_INC}
${SDL_INC}
)
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp
index 7b5b7fdf78c..eee8e9f6827 100644
--- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp
@@ -55,28 +55,13 @@ KX_NetworkEventManager::~KX_NetworkEventManager()
//printf("KX_NetworkEventManager destructor\n");
}
-void KX_NetworkEventManager::RegisterSensor(class SCA_ISensor* sensor)
-{
- //printf("KX_NetworkEventManager RegisterSensor\n");
- m_sensors.push_back(sensor);
-}
-
-void KX_NetworkEventManager::RemoveSensor(class SCA_ISensor* sensor)
-{
- //printf("KX_NetworkEventManager RemoveSensor\n");
- // Network specific RemoveSensor stuff goes here
-
- // parent
- SCA_EventManager::RemoveSensor(sensor);
-}
-
void KX_NetworkEventManager::NextFrame()
{
// printf("KX_NetworkEventManager::proceed %.2f - %.2f\n", curtime, deltatime);
// each frame, the logicmanager will call the network
// eventmanager to look for network events, and process it's
// 'network' sensors
- vector<class SCA_ISensor*>::iterator it;
+ set<class SCA_ISensor*>::iterator it;
for (it = m_sensors.begin(); !(it==m_sensors.end()); it++) {
// printf("KX_NetworkEventManager::proceed sensor %.2f\n", curtime);
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h
index 0b097ba2ef6..ae88f1d4987 100644
--- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h
@@ -42,9 +42,6 @@ public:
class NG_NetworkDeviceInterface *ndi);
virtual ~KX_NetworkEventManager ();
- virtual void RegisterSensor(class SCA_ISensor* sensor);
- virtual void RemoveSensor(class SCA_ISensor* sensor);
-
virtual void NextFrame();
virtual void EndFrame();
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp
index 3ade810c394..85921ae75ca 100644
--- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp
@@ -158,6 +158,9 @@ PyObject* KX_NetworkMessageActuator::PySetToPropName(
if (PyArg_ParseTuple(args, "s", &ToPropName)) {
m_toPropName = ToPropName;
}
+ else {
+ return NULL;
+ }
Py_Return;
}
@@ -173,7 +176,10 @@ PyObject* KX_NetworkMessageActuator::PySetSubject(
if (PyArg_ParseTuple(args, "s", &Subject)) {
m_subject = Subject;
}
-
+ else {
+ return NULL;
+ }
+
Py_Return;
}
@@ -188,6 +194,9 @@ PyObject* KX_NetworkMessageActuator::PySetBodyType(
if (PyArg_ParseTuple(args, "i", &BodyType)) {
m_bodyType = BodyType;
}
+ else {
+ return NULL;
+ }
Py_Return;
}
@@ -203,6 +212,9 @@ PyObject* KX_NetworkMessageActuator::PySetBody(
if (PyArg_ParseTuple(args, "s", &Body)) {
m_body = Body;
}
+ else {
+ return NULL;
+ }
Py_Return;
}
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp
index c9fa920a426..8956df9c96b 100644
--- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp
@@ -58,10 +58,15 @@ KX_NetworkMessageSensor::KX_NetworkMessageSensor(
m_NetworkScene(NetworkScene),
m_subject(subject),
m_frame_message_count (0),
- m_IsUp(false),
m_BodyList(NULL),
m_SubjectList(NULL)
{
+ Init();
+}
+
+void KX_NetworkMessageSensor::Init()
+{
+ m_IsUp = false;
}
KX_NetworkMessageSensor::~KX_NetworkMessageSensor()
@@ -139,7 +144,11 @@ bool KX_NetworkMessageSensor::Evaluate(CValue* event)
result = (WasUp != m_IsUp);
- // Return true if the message received state has changed.
+ // Return always true if a message was received otherwise we can loose messages
+ if (m_IsUp)
+ return true;
+ // Is it usefull to return also true when the first frame without a message??
+ // This will cause a fast on/off cycle that seems useless!
return result;
}
@@ -187,20 +196,20 @@ PyParentObject KX_NetworkMessageSensor::Parents[] = {
PyMethodDef KX_NetworkMessageSensor::Methods[] = {
{"setSubjectFilterText", (PyCFunction)
- KX_NetworkMessageSensor::sPySetSubjectFilterText, METH_VARARGS,
- SetSubjectFilterText_doc},
+ KX_NetworkMessageSensor::sPySetSubjectFilterText, METH_O,
+ (PY_METHODCHAR)SetSubjectFilterText_doc},
{"getFrameMessageCount", (PyCFunction)
- KX_NetworkMessageSensor::sPyGetFrameMessageCount, METH_VARARGS,
- GetFrameMessageCount_doc},
+ KX_NetworkMessageSensor::sPyGetFrameMessageCount, METH_NOARGS,
+ (PY_METHODCHAR)GetFrameMessageCount_doc},
{"getBodies", (PyCFunction)
- KX_NetworkMessageSensor::sPyGetBodies, METH_VARARGS,
- GetBodies_doc},
+ KX_NetworkMessageSensor::sPyGetBodies, METH_NOARGS,
+ (PY_METHODCHAR)GetBodies_doc},
{"getSubject", (PyCFunction)
- KX_NetworkMessageSensor::sPyGetSubject, METH_VARARGS,
- GetSubject_doc},
+ KX_NetworkMessageSensor::sPyGetSubject, METH_NOARGS,
+ (PY_METHODCHAR)GetSubject_doc},
{"getSubjects", (PyCFunction)
- KX_NetworkMessageSensor::sPyGetSubjects, METH_VARARGS,
- GetSubjects_doc},
+ KX_NetworkMessageSensor::sPyGetSubjects, METH_NOARGS,
+ (PY_METHODCHAR)GetSubjects_doc},
{NULL,NULL} //Sentinel
};
@@ -209,85 +218,66 @@ PyObject* KX_NetworkMessageSensor::_getattr(const STR_String& attr) {
}
// 1. Set the message subject that this sensor listens for
-char KX_NetworkMessageSensor::SetSubjectFilterText_doc[] =
+const char KX_NetworkMessageSensor::SetSubjectFilterText_doc[] =
"\tsetSubjectFilterText(value)\n"
"\tChange the message subject text that this sensor is listening to.\n";
-PyObject* KX_NetworkMessageSensor::PySetSubjectFilterText(
- PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_NetworkMessageSensor::PySetSubjectFilterText( PyObject* self, PyObject* value)
{
- char* Subject;
-
- if (PyArg_ParseTuple(args, "s", &Subject))
- {
- m_subject = Subject;
+ char* Subject = PyString_AsString(value);
+ if (Subject==NULL) {
+ PyErr_SetString(PyExc_TypeError, "expected a string message");
+ return NULL;
}
-
- Py_Return;
+
+ m_subject = Subject;
+ Py_RETURN_NONE;
}
// 2. Get the number of messages received since the last frame
-char KX_NetworkMessageSensor::GetFrameMessageCount_doc[] =
+const char KX_NetworkMessageSensor::GetFrameMessageCount_doc[] =
"\tgetFrameMessageCount()\n"
"\tGet the number of messages received since the last frame.\n";
-PyObject* KX_NetworkMessageSensor::PyGetFrameMessageCount(
- PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_NetworkMessageSensor::PyGetFrameMessageCount( PyObject* )
{
return PyInt_FromLong(long(m_frame_message_count));
}
// 3. Get the message bodies
-char KX_NetworkMessageSensor::GetBodies_doc[] =
+const char KX_NetworkMessageSensor::GetBodies_doc[] =
"\tgetBodies()\n"
"\tGet the list of message bodies.\n";
-PyObject* KX_NetworkMessageSensor::PyGetBodies(
- PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_NetworkMessageSensor::PyGetBodies( PyObject* )
{
if (m_BodyList) {
return ((PyObject*) m_BodyList->AddRef());
+ } else {
+ return ((PyObject*) new CListValue());
}
-
- Py_Return;
}
// 4. Get the message subject: field of the message sensor
-char KX_NetworkMessageSensor::GetSubject_doc[] =
+const char KX_NetworkMessageSensor::GetSubject_doc[] =
"\tgetSubject()\n"
"\tGet the subject: field of the message sensor.\n";
-PyObject* KX_NetworkMessageSensor::PyGetSubject(
- PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_NetworkMessageSensor::PyGetSubject( PyObject* )
{
- if (m_subject) {
- return PyString_FromString(m_subject);
- }
-
- Py_Return;
+ return PyString_FromString(m_subject ? m_subject : "");
}
// 5. Get the message subjects
-char KX_NetworkMessageSensor::GetSubjects_doc[] =
+const char KX_NetworkMessageSensor::GetSubjects_doc[] =
"\tgetSubjects()\n"
"\tGet list of message subjects.\n";
-PyObject* KX_NetworkMessageSensor::PyGetSubjects(
- PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_NetworkMessageSensor::PyGetSubjects( PyObject* )
{
if (m_SubjectList) {
- return ((PyObject*) m_SubjectList->AddRef());
- }
-
- Py_Return;
+ return ((PyObject*) m_SubjectList->AddRef());
+ } else {
+ return ((PyObject*) new CListValue());
+ }
}
diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h
index d051b715aab..8cdfd6cdb5a 100644
--- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h
+++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h
@@ -65,6 +65,7 @@ public:
virtual CValue* GetReplica();
virtual bool Evaluate(CValue* event);
virtual bool IsPositiveTrigger();
+ virtual void Init();
void EndFrame();
/* ------------------------------------------------------------- */
@@ -73,11 +74,11 @@ public:
virtual PyObject* _getattr(const STR_String& attr);
- KX_PYMETHOD_DOC(KX_NetworkMessageSensor, SetSubjectFilterText);
- KX_PYMETHOD_DOC(KX_NetworkMessageSensor, GetFrameMessageCount);
- KX_PYMETHOD_DOC(KX_NetworkMessageSensor, GetBodies);
- KX_PYMETHOD_DOC(KX_NetworkMessageSensor, GetSubject);
- KX_PYMETHOD_DOC(KX_NetworkMessageSensor, GetSubjects);
+ KX_PYMETHOD_DOC_O(KX_NetworkMessageSensor, SetSubjectFilterText);
+ KX_PYMETHOD_DOC_NOARGS(KX_NetworkMessageSensor, GetFrameMessageCount);
+ KX_PYMETHOD_DOC_NOARGS(KX_NetworkMessageSensor, GetBodies);
+ KX_PYMETHOD_DOC_NOARGS(KX_NetworkMessageSensor, GetSubject);
+ KX_PYMETHOD_DOC_NOARGS(KX_NetworkMessageSensor, GetSubjects);
};
diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
index bbf5640f8e0..f92200780d5 100644
--- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
+++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
@@ -6,21 +6,7 @@
#include <config.h>
#endif
-#ifdef WIN32
-#include <windows.h>
-#endif // WIN32
-#ifdef __APPLE__
-#define GL_GLEXT_LEGACY 1
-#include <OpenGL/gl.h>
-#include <OpenGL/glu.h>
-#else
-#include <GL/gl.h>
-#if defined(__sun__) && !defined(__sparc__)
-#include <mesa/glu.h>
-#else
-#include <GL/glu.h>
-#endif
-#endif
+#include "GL/glew.h"
#include "KX_BlenderMaterial.h"
#include "BL_Material.h"
@@ -33,14 +19,12 @@
#include "MT_Vector4.h"
#include "MT_Matrix4x4.h"
+#include "RAS_BucketManager.h"
#include "RAS_MeshObject.h"
#include "RAS_IRasterizer.h"
#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
-#include "RAS_OpenGLRasterizer/ARB_multitexture.h"
-extern "C" {
-//XXX #include "BDR_drawmesh.h"
-}
+#include "GPU_draw.h"
#include "STR_HashedString.h"
@@ -51,9 +35,11 @@ extern "C" {
#include "DNA_meshdata_types.h"
#include "BKE_mesh.h"
// ------------------------------------
-using namespace bgl;
#define spit(x) std::cout << x << std::endl;
+BL_Shader *KX_BlenderMaterial::mLastShader = NULL;
+BL_BlenderShader *KX_BlenderMaterial::mLastBlenderShader = NULL;
+
//static PyObject *gTextureDict = 0;
KX_BlenderMaterial::KX_BlenderMaterial(
@@ -61,7 +47,6 @@ KX_BlenderMaterial::KX_BlenderMaterial(
BL_Material *data,
bool skin,
int lightlayer,
- void *clientobject,
PyTypeObject *T
)
: PyObjectPlus(T),
@@ -72,35 +57,33 @@ KX_BlenderMaterial::KX_BlenderMaterial(
data->tilexrep[0],
data->tileyrep[0],
data->mode,
- ((data->ras_mode &TRANSP)!=0),
+ data->transp,
+ ((data->ras_mode &ALPHA)!=0),
((data->ras_mode &ZSORT)!=0),
- lightlayer,
- ((data->ras_mode &TRIANGLE)!=0),
- clientobject
+ lightlayer
),
mMaterial(data),
mShader(0),
+ mBlenderShader(0),
mScene(scene),
mUserDefBlend(0),
mModified(0),
+ mConstructed(false),
mPass(0)
{
// --------------------------------
// RAS_IPolyMaterial variables...
- m_flag |=RAS_BLENDERMAT;
- m_flag |=(mMaterial->IdMode>=ONETEX)?RAS_MULTITEX:0;
- m_flag |=(mMaterial->ras_mode & USE_LIGHT)!=0?RAS_MULTILIGHT:0;
- m_flag |=(mMaterial->ras_mode &ALPHA_TEST)!=0?RAS_FORCEALPHA:0;
+ m_flag |= RAS_BLENDERMAT;
+ m_flag |= (mMaterial->IdMode>=ONETEX)? RAS_MULTITEX: 0;
+ m_flag |= ((mMaterial->ras_mode & USE_LIGHT)!=0)? RAS_MULTILIGHT: 0;
+ m_flag |= (mMaterial->glslmat)? RAS_BLENDERGLSL: 0;
// figure max
int enabled = mMaterial->num_enabled;
int max = BL_Texture::GetMaxUnits();
mMaterial->num_enabled = enabled>=max?max:enabled;
- // base class
- m_enabled = mMaterial->num_enabled;
-
// test the sum of the various modes for equality
// so we can ether accept or reject this material
// as being equal, this is rather important to
@@ -111,14 +94,16 @@ KX_BlenderMaterial::KX_BlenderMaterial(
mMaterial->blend_mode[i]
);
}
- m_multimode += mMaterial->IdMode+mMaterial->ras_mode;
+ m_multimode += mMaterial->IdMode+ (mMaterial->ras_mode & ~(COLLIDER|USE_LIGHT));
}
KX_BlenderMaterial::~KX_BlenderMaterial()
{
// cleanup work
- OnExit();
+ if (mConstructed)
+ // clean only if material was actually used
+ OnExit();
}
@@ -137,41 +122,77 @@ unsigned int* KX_BlenderMaterial::GetMCol(void) const
void KX_BlenderMaterial::OnConstruction()
{
+ if (mConstructed)
+ // when material are reused between objects
+ return;
+
+ if(mMaterial->glslmat)
+ SetBlenderGLSLShader();
+
// for each unique material...
int i;
for(i=0; i<mMaterial->num_enabled; i++) {
if( mMaterial->mapping[i].mapping & USEENV ) {
- if(!RAS_EXT_support._ARB_texture_cube_map) {
+ if(!GLEW_ARB_texture_cube_map) {
spit("CubeMap textures not supported");
continue;
}
if(!mTextures[i].InitCubeMap(i, mMaterial->cubemap[i] ) )
spit("unable to initialize image("<<i<<") in "<<
- mMaterial->matname<< ", image will not be available");
+ mMaterial->matname<< ", image will not be available");
}
else {
if( mMaterial->img[i] ) {
if( ! mTextures[i].InitFromImage(i, mMaterial->img[i], (mMaterial->flag[i] &MIPMAP)!=0 ))
spit("unable to initialize image("<<i<<") in "<<
- mMaterial->matname<< ", image will not be available");
+ mMaterial->matname<< ", image will not be available");
}
}
}
+
mBlendFunc[0] =0;
mBlendFunc[1] =0;
+ mConstructed = true;
+}
+
+void KX_BlenderMaterial::EndFrame()
+{
+ if(mLastBlenderShader) {
+ mLastBlenderShader->SetProg(false);
+ mLastBlenderShader = NULL;
+ }
+
+ if(mLastShader) {
+ mLastShader->SetProg(false);
+ mLastShader = NULL;
+ }
}
void KX_BlenderMaterial::OnExit()
{
if( mShader ) {
- //note, the shader here is allocated, per unique material
- //and this function is called per face
- mShader->SetProg(0);
+ //note, the shader here is allocated, per unique material
+ //and this function is called per face
+ if(mShader == mLastShader) {
+ mShader->SetProg(false);
+ mLastShader = NULL;
+ }
+
delete mShader;
mShader = 0;
}
+ if( mBlenderShader ) {
+ if(mBlenderShader == mLastBlenderShader) {
+ mBlenderShader->SetProg(false);
+ mLastBlenderShader = NULL;
+ }
+
+ delete mBlenderShader;
+ mBlenderShader = 0;
+ }
+
BL_Texture::ActivateFirst();
for(int i=0; i<mMaterial->num_enabled; i++) {
BL_Texture::ActivateUnit(i);
@@ -180,24 +201,30 @@ void KX_BlenderMaterial::OnExit()
}
if( mMaterial->tface )
- ; //XXX set_tpage(mMaterial->tface);
+ GPU_set_tpage(mMaterial->tface);
}
void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras)
{
- MT_assert(RAS_EXT_support._ARB_shader_objects && mShader);
+ MT_assert(GLEW_ARB_shader_objects && mShader);
int i;
if( !enable || !mShader->Ok() ) {
// frame cleanup.
- mShader->SetProg(false);
+ if(mShader == mLastShader) {
+ mShader->SetProg(false);
+ mLastShader = NULL;
+ }
+
+ ras->SetBlendingMode(TF_SOLID);
BL_Texture::DisableAllTextures();
return;
}
BL_Texture::DisableAllTextures();
mShader->SetProg(true);
+ mLastShader = mShader;
BL_Texture::ActivateFirst();
@@ -211,29 +238,60 @@ void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras)
}
if(!mUserDefBlend) {
- setDefaultBlending();
+ ras->SetBlendingMode(mMaterial->transp);
}
else {
+ ras->SetBlendingMode(TF_SOLID);
+ ras->SetBlendingMode(-1); // indicates custom mode
+
// tested to be valid enums
glEnable(GL_BLEND);
glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
}
}
+void KX_BlenderMaterial::setBlenderShaderData( bool enable, RAS_IRasterizer *ras)
+{
+ if( !enable || !mBlenderShader->Ok() ) {
+ ras->SetBlendingMode(TF_SOLID);
+
+ // frame cleanup.
+ if(mLastBlenderShader) {
+ mLastBlenderShader->SetProg(false);
+ mLastBlenderShader= NULL;
+ }
+ else
+ BL_Texture::DisableAllTextures();
+
+ return;
+ }
+
+ if(!mBlenderShader->Equals(mLastBlenderShader)) {
+ ras->SetBlendingMode(mMaterial->transp);
+
+ if(mLastBlenderShader)
+ mLastBlenderShader->SetProg(false);
+ else
+ BL_Texture::DisableAllTextures();
+
+ mBlenderShader->SetProg(true, ras->GetTime());
+ mLastBlenderShader= mBlenderShader;
+ }
+}
void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras)
{
- if(RAS_EXT_support._ARB_shader_objects && mShader)
- mShader->SetProg(false);
-
BL_Texture::DisableAllTextures();
- if( !enable )
+
+ if( !enable ) {
+ ras->SetBlendingMode(TF_SOLID);
return;
+ }
BL_Texture::ActivateFirst();
if( mMaterial->IdMode == DEFAULT_BLENDER ) {
- setDefaultBlending();
+ ras->SetBlendingMode(mMaterial->transp);
return;
}
@@ -243,7 +301,7 @@ void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras)
mTextures[0].ActivateTexture();
mTextures[0].setTexEnv(0, true);
mTextures[0].SetMapping(mMaterial->mapping[0].mapping);
- setDefaultBlending();
+ ras->SetBlendingMode(mMaterial->transp);
}
return;
}
@@ -266,9 +324,12 @@ void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras)
}
if(!mUserDefBlend) {
- setDefaultBlending();
+ ras->SetBlendingMode(mMaterial->transp);
}
else {
+ ras->SetBlendingMode(TF_SOLID);
+ ras->SetBlendingMode(-1); // indicates custom mode
+
glEnable(GL_BLEND);
glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
}
@@ -284,29 +345,31 @@ KX_BlenderMaterial::ActivatShaders(
// reset...
if(tmp->mMaterial->IsShared())
cachingInfo =0;
-
+
+ if(mLastBlenderShader) {
+ mLastBlenderShader->SetProg(false);
+ mLastBlenderShader= NULL;
+ }
+
if (GetCachingInfo() != cachingInfo) {
if (!cachingInfo)
- tmp->setShaderData( false, rasty);
+ tmp->setShaderData(false, rasty);
cachingInfo = GetCachingInfo();
- if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED ) {
- tmp->setShaderData( true, rasty);
- rasty->EnableTextures(true);
- }
- else {
- tmp->setShaderData( false, rasty);
- rasty->EnableTextures(false);
- }
+ if(rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)
+ tmp->setShaderData(true, rasty);
+ else
+ tmp->setShaderData(false, rasty);
if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
rasty->SetCullFace(false);
else
rasty->SetCullFace(true);
- if (((mMaterial->ras_mode &WIRE)!=0) || mMaterial->mode & RAS_IRasterizer::KX_LINES)
+ if (((mMaterial->ras_mode &WIRE)!=0) || (mMaterial->mode & RAS_IRasterizer::KX_LINES) ||
+ (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
{
if((mMaterial->ras_mode &WIRE)!=0)
rasty->SetCullFace(false);
@@ -321,33 +384,84 @@ KX_BlenderMaterial::ActivatShaders(
}
void
+KX_BlenderMaterial::ActivateBlenderShaders(
+ RAS_IRasterizer* rasty,
+ TCachingInfo& cachingInfo)const
+{
+ KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
+
+ if(mLastShader) {
+ mLastShader->SetProg(false);
+ mLastShader= NULL;
+ }
+
+ if (GetCachingInfo() != cachingInfo) {
+ if (!cachingInfo)
+ tmp->setBlenderShaderData(false, rasty);
+
+ cachingInfo = GetCachingInfo();
+
+ if(rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)
+ tmp->setBlenderShaderData(true, rasty);
+ else
+ tmp->setBlenderShaderData(false, rasty);
+
+ if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
+ rasty->SetCullFace(false);
+ else
+ rasty->SetCullFace(true);
+
+ if (((mMaterial->ras_mode & WIRE)!=0) || (mMaterial->mode & RAS_IRasterizer::KX_LINES) ||
+ (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
+ {
+ if((mMaterial->ras_mode &WIRE)!=0)
+ rasty->SetCullFace(false);
+ rasty->SetLines(true);
+ }
+ else
+ rasty->SetLines(false);
+
+ ActivatGLMaterials(rasty);
+ mBlenderShader->SetAttribs(rasty, mMaterial);
+ }
+}
+
+void
KX_BlenderMaterial::ActivateMat(
RAS_IRasterizer* rasty,
TCachingInfo& cachingInfo
)const
{
KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
+
+ if(mLastShader) {
+ mLastShader->SetProg(false);
+ mLastShader= NULL;
+ }
+
+ if(mLastBlenderShader) {
+ mLastBlenderShader->SetProg(false);
+ mLastBlenderShader= NULL;
+ }
+
if (GetCachingInfo() != cachingInfo) {
if (!cachingInfo)
tmp->setTexData( false,rasty );
cachingInfo = GetCachingInfo();
- if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) {
+ if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)
tmp->setTexData( true,rasty );
- rasty->EnableTextures(true);
- }
- else{
+ else
tmp->setTexData( false,rasty);
- rasty->EnableTextures(false);
- }
if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
rasty->SetCullFace(false);
else
rasty->SetCullFace(true);
- if (((mMaterial->ras_mode &WIRE)!=0) || mMaterial->mode & RAS_IRasterizer::KX_LINES)
+ if (((mMaterial->ras_mode &WIRE)!=0) || (mMaterial->mode & RAS_IRasterizer::KX_LINES) ||
+ (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
{
if((mMaterial->ras_mode &WIRE)!=0)
rasty->SetCullFace(false);
@@ -356,77 +470,113 @@ KX_BlenderMaterial::ActivateMat(
else
rasty->SetLines(false);
}
+
ActivatGLMaterials(rasty);
ActivateTexGen(rasty);
}
-
bool
KX_BlenderMaterial::Activate(
RAS_IRasterizer* rasty,
TCachingInfo& cachingInfo
)const
{
- bool dopass = false;
- if( RAS_EXT_support._ARB_shader_objects && ( mShader && mShader->Ok() ) ) {
- if( (mPass++) < mShader->getNumPass() ) {
+ if(GLEW_ARB_shader_objects && (mShader && mShader->Ok())) {
+ if((mPass++) < mShader->getNumPass() ) {
ActivatShaders(rasty, cachingInfo);
- dopass = true;
- return dopass;
+ return true;
+ }
+ else {
+ if(mShader == mLastShader) {
+ mShader->SetProg(false);
+ mLastShader = NULL;
+ }
+ mPass = 0;
+ return false;
+ }
+ }
+ else if( GLEW_ARB_shader_objects && (mBlenderShader && mBlenderShader->Ok() ) ) {
+ if(mPass++ == 0) {
+ ActivateBlenderShaders(rasty, cachingInfo);
+ return true;
}
else {
- mShader->SetProg(false);
mPass = 0;
- dopass = false;
- return dopass;
+ return false;
}
}
else {
- switch (mPass++)
- {
- case 0:
- ActivateMat(rasty, cachingInfo);
- dopass = true;
- break;
- default:
- mPass = 0;
- dopass = false;
- break;
+ if(mPass++ == 0) {
+ ActivateMat(rasty, cachingInfo);
+ return true;
+ }
+ else {
+ mPass = 0;
+ return false;
}
}
- return dopass;
}
-void KX_BlenderMaterial::ActivateMeshSlot(const KX_MeshSlot & ms, RAS_IRasterizer* rasty) const
+bool KX_BlenderMaterial::UsesLighting(RAS_IRasterizer *rasty) const
{
- if(mShader && RAS_EXT_support._ARB_shader_objects)
+ if(!RAS_IPolyMaterial::UsesLighting(rasty))
+ return false;
+
+ if(mShader && mShader->Ok())
+ return true;
+ else if(mBlenderShader && mBlenderShader->Ok())
+ return false;
+ else
+ return true;
+}
+
+void KX_BlenderMaterial::ActivateMeshSlot(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty) const
+{
+ if(mShader && GLEW_ARB_shader_objects) {
mShader->Update(ms, rasty);
+ }
+ else if(mBlenderShader && GLEW_ARB_shader_objects) {
+ int blendmode;
+
+ mBlenderShader->Update(ms, rasty);
+
+ /* we do blend modes here, because they can change per object
+ * with the same material due to obcolor/obalpha */
+ blendmode = mBlenderShader->GetBlendMode();
+ if((blendmode == TF_SOLID || blendmode == TF_ALPHA) && mMaterial->transp != TF_SOLID)
+ blendmode = mMaterial->transp;
+
+ rasty->SetBlendingMode(blendmode);
+ }
}
void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const
{
- rasty->SetSpecularity(
- mMaterial->speccolor[0]*mMaterial->spec_f,
- mMaterial->speccolor[1]*mMaterial->spec_f,
- mMaterial->speccolor[2]*mMaterial->spec_f,
- mMaterial->spec_f
- );
+ if(mShader || !mBlenderShader) {
+ rasty->SetSpecularity(
+ mMaterial->speccolor[0]*mMaterial->spec_f,
+ mMaterial->speccolor[1]*mMaterial->spec_f,
+ mMaterial->speccolor[2]*mMaterial->spec_f,
+ mMaterial->spec_f
+ );
- rasty->SetShinyness( mMaterial->hard );
+ rasty->SetShinyness( mMaterial->hard );
- rasty->SetDiffuse(
- mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit,
- mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit,
- mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit,
- 1.0f);
+ rasty->SetDiffuse(
+ mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit,
+ mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit,
+ mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit,
+ 1.0f);
- rasty->SetEmissive(
- mMaterial->matcolor[0]*mMaterial->emit,
- mMaterial->matcolor[1]*mMaterial->emit,
- mMaterial->matcolor[2]*mMaterial->emit,
- 1.0 );
+ rasty->SetEmissive(
+ mMaterial->matcolor[0]*mMaterial->emit,
+ mMaterial->matcolor[1]*mMaterial->emit,
+ mMaterial->matcolor[2]*mMaterial->emit,
+ 1.0 );
+
+ rasty->SetAmbient(mMaterial->amb);
+ }
- rasty->SetAmbient(mMaterial->amb);
if (mMaterial->material)
rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0);
}
@@ -434,52 +584,43 @@ void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const
void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const
{
- if(mShader && RAS_EXT_support._ARB_shader_objects)
- if(mShader->GetAttribute() == BL_Shader::SHD_TANGENT)
- ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT);
+ if(ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) {
+ ras->SetAttribNum(0);
+ if(mShader && GLEW_ARB_shader_objects) {
+ if(mShader->GetAttribute() == BL_Shader::SHD_TANGENT) {
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, 0);
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT, 1);
+ ras->SetAttribNum(2);
+ }
+ }
- for(int i=0; i<mMaterial->num_enabled; i++) {
- int mode = mMaterial->mapping[i].mapping;
+ ras->SetTexCoordNum(mMaterial->num_enabled);
- if (mode &USECUSTOMUV)
- {
- STR_String str = mMaterial->mapping[i].uvCoName;
- if (!str.IsEmpty())
- ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_UV2, i);
- continue;
- }
+ for(int i=0; i<mMaterial->num_enabled; i++) {
+ int mode = mMaterial->mapping[i].mapping;
- if( mode &(USEREFL|USEOBJ))
- ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_GEN, i);
- else if(mode &USEORCO)
- ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_ORCO, i);
- else if(mode &USENORM)
- ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_NORM, i);
- else if(mode &USEUV)
- ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_UV1, i);
- else if(mode &USETANG)
- ras->SetTexCoords(RAS_IRasterizer::RAS_TEXTANGENT, i);
- else
- ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_DISABLE, i);
- }
-}
+ if (mode &USECUSTOMUV)
+ {
+ STR_String str = mMaterial->mapping[i].uvCoName;
+ if (!str.IsEmpty())
+ ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV2, i);
+ continue;
+ }
-bool KX_BlenderMaterial::setDefaultBlending()
-{
- if( mMaterial->transp &TF_ADD) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE);
- return true;
- }
-
- if( mMaterial->transp & TF_ALPHA ) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- return true;
+ if( mode &(USEREFL|USEOBJ))
+ ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_GEN, i);
+ else if(mode &USEORCO)
+ ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_ORCO, i);
+ else if(mode &USENORM)
+ ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_NORM, i);
+ else if(mode &USEUV)
+ ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV1, i);
+ else if(mode &USETANG)
+ ras->SetTexCoord(RAS_IRasterizer::RAS_TEXTANGENT, i);
+ else
+ ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_DISABLE, i);
+ }
}
-
- glDisable(GL_BLEND);
- return false;
}
void KX_BlenderMaterial::setTexMatrixData(int i)
@@ -487,8 +628,7 @@ void KX_BlenderMaterial::setTexMatrixData(int i)
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
-#ifdef GL_ARB_texture_cube_map
- if( RAS_EXT_support._ARB_texture_cube_map &&
+ if( GLEW_ARB_texture_cube_map &&
mTextures[i].GetTextureType() == GL_TEXTURE_CUBE_MAP_ARB &&
mMaterial->mapping[i].mapping & USEREFL) {
glScalef(
@@ -498,7 +638,6 @@ void KX_BlenderMaterial::setTexMatrixData(int i)
);
}
else
-#endif
{
glScalef(
mMaterial->mapping[i].scale[0],
@@ -556,8 +695,7 @@ void KX_BlenderMaterial::setObjectMatrixData(int i, RAS_IRasterizer *ras)
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
- MT_Matrix4x4 mvmat;
- ras->GetViewMatrix(mvmat);
+ const MT_Matrix4x4& mvmat = ras->GetViewMatrix();
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
@@ -647,28 +785,23 @@ int KX_BlenderMaterial::_setattr(const STR_String& attr, PyObject *pyvalue)
KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()")
{
-#ifdef GL_ARB_fragment_shader
- if( !RAS_EXT_support._ARB_fragment_shader) {
+ if( !GLEW_ARB_fragment_shader) {
if(!mModified)
spit("Fragment shaders not supported");
mModified = true;
Py_Return;
}
-#endif
-#ifdef GL_ARB_vertex_shader
- if( !RAS_EXT_support._ARB_vertex_shader) {
+ if( !GLEW_ARB_vertex_shader) {
if(!mModified)
spit("Vertex shaders not supported");
mModified = true;
Py_Return;
}
-#endif
-#ifdef GL_ARB_shader_objects
- if(!RAS_EXT_support._ARB_shader_objects) {
+ if(!GLEW_ARB_shader_objects) {
if(!mModified)
spit("GLSL not supported");
mModified = true;
@@ -684,7 +817,9 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()")
}
if(mShader && !mShader->GetError()) {
+ m_flag &= ~RAS_BLENDERGLSL;
mMaterial->SetSharedMaterial(true);
+ mScene->GetBucketManager()->ReleaseDisplayLists(this);
Py_INCREF(mShader);
return mShader;
}else
@@ -707,13 +842,20 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()")
}
PyErr_Format(PyExc_ValueError, "GLSL Error");
return NULL;
-
-#else
- Py_Return;
-#endif//GL_ARB_shader_objects
}
+void KX_BlenderMaterial::SetBlenderGLSLShader(void)
+{
+ if(!mBlenderShader)
+ mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, m_lightlayer);
+
+ if(!mBlenderShader->Ok()) {
+ delete mBlenderShader;
+ mBlenderShader = 0;
+ }
+}
+
KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()")
{
return PyInt_FromLong( mMaterial->material_index );
diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h
index 2b1264154d0..6e5db1b56c1 100644
--- a/source/gameengine/Ketsji/KX_BlenderMaterial.h
+++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h
@@ -8,6 +8,7 @@
#include "BL_Material.h"
#include "BL_Texture.h"
#include "BL_Shader.h"
+#include "BL_BlenderShader.h"
#include "PyObjectPlus.h"
@@ -27,7 +28,6 @@ public:
BL_Material* mat,
bool skin,
int lightlayer,
- void* clientobject,
PyTypeObject* T=&Type
);
@@ -46,7 +46,7 @@ public:
virtual
void ActivateMeshSlot(
- const KX_MeshSlot & ms,
+ const RAS_MeshSlot & ms,
RAS_IRasterizer* rasty
) const;
@@ -60,9 +60,19 @@ public:
TCachingInfo& cachingInfo
)const;
+ void ActivateBlenderShaders(
+ RAS_IRasterizer* rasty,
+ TCachingInfo& cachingInfo
+ )const;
MTFace* GetMTFace(void) const;
unsigned int* GetMCol(void) const;
+ BL_Texture * getTex (unsigned int idx) {
+ return (idx < MAXTEX) ? mTextures + idx : NULL;
+ }
+ Image * getImage (unsigned int idx) {
+ return (idx < MAXTEX && mMaterial) ? mMaterial->img[idx] : NULL;
+ }
// for ipos
void UpdateIPO(
@@ -85,24 +95,32 @@ public:
// --------------------------------
// pre calculate to avoid pops/lag at startup
virtual void OnConstruction( );
+
+ static void EndFrame();
+
private:
- BL_Material* mMaterial;
- BL_Shader* mShader;
+ BL_Material* mMaterial;
+ BL_Shader* mShader;
+ BL_BlenderShader* mBlenderShader;
KX_Scene* mScene;
BL_Texture mTextures[MAXTEX]; // texture array
bool mUserDefBlend;
unsigned int mBlendFunc[2];
bool mModified;
+ bool mConstructed; // if false, don't clean on exit
+
+ void SetBlenderGLSLShader();
void ActivatGLMaterials( RAS_IRasterizer* rasty )const;
void ActivateTexGen( RAS_IRasterizer *ras ) const;
+ bool UsesLighting(RAS_IRasterizer *rasty) const;
// message centers
void setTexData( bool enable,RAS_IRasterizer *ras);
+ void setBlenderShaderData( bool enable, RAS_IRasterizer *ras);
void setShaderData( bool enable, RAS_IRasterizer *ras);
- bool setDefaultBlending();
void setObjectMatrixData(int i, RAS_IRasterizer *ras);
void setTexMatrixData(int i);
@@ -111,6 +129,10 @@ private:
// cleanup stuff
void OnExit();
+ // shader chacing
+ static BL_BlenderShader *mLastBlenderShader;
+ static BL_Shader *mLastShader;
+
mutable int mPass;
};
diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp
index aa5d1f1cec1..bf838e60210 100644
--- a/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp
+++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.cpp
@@ -13,18 +13,32 @@
#include "KX_ClientObjectInfo.h"
#include "PHY_IPhysicsEnvironment.h"
+#include "CcdPhysicsEnvironment.h"
+#include "BulletSoftBody/btSoftBody.h"
KX_BulletPhysicsController::KX_BulletPhysicsController (const CcdConstructionInfo& ci, bool dyna)
: KX_IPhysicsController(dyna,(PHY_IPhysicsController*)this),
-CcdPhysicsController(ci)
+CcdPhysicsController(ci),
+m_savedCollisionFlags(0)
{
}
KX_BulletPhysicsController::~KX_BulletPhysicsController ()
{
-
+ // The game object has a direct link to
+ if (m_pObject)
+ {
+ // If we cheat in SetObject, we must also cheat here otherwise the
+ // object will still things it has a physical controller
+ // Note that it requires that m_pObject is reset in case the object is deleted
+ // before the controller (usual case, see KX_Scene::RemoveNodeDestructObjec)
+ // The non usual case is when the object is not deleted because its reference is hanging
+ // in a AddObject actuator but the node is deleted. This case is covered here.
+ KX_GameObject* gameobj = (KX_GameObject*) m_pObject->GetSGClientObject();
+ gameobj->SetPhysicsController(NULL,false);
+ }
}
void KX_BulletPhysicsController::resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ)
@@ -58,6 +72,7 @@ void KX_BulletPhysicsController::SetObject (SG_IObject* object)
}
+
void KX_BulletPhysicsController::setMargin (float collisionMargin)
{
CcdPhysicsController::SetMargin(collisionMargin);
@@ -90,10 +105,17 @@ MT_Vector3 KX_BulletPhysicsController::GetLinearVelocity()
CcdPhysicsController::GetLinearVelocity(angVel[0],angVel[1],angVel[2]);//rcruiz
return MT_Vector3(angVel[0],angVel[1],angVel[2]);
}
+MT_Vector3 KX_BulletPhysicsController::GetAngularVelocity()
+{
+ float angVel[3];
+ //CcdPhysicsController::GetAngularVelocity(angVel[0],angVel[1],angVel[2]);
+ CcdPhysicsController::GetAngularVelocity(angVel[0],angVel[1],angVel[2]);//rcruiz
+ return MT_Vector3(angVel[0],angVel[1],angVel[2]);
+}
MT_Vector3 KX_BulletPhysicsController::GetVelocity(const MT_Point3& pos)
{
float linVel[3];
- CcdPhysicsController::GetLinearVelocity(linVel[0],linVel[1],linVel[2]);
+ CcdPhysicsController::GetVelocity(pos[0], pos[1], pos[2], linVel[0],linVel[1],linVel[2]);
return MT_Vector3(linVel[0],linVel[1],linVel[2]);
}
@@ -112,9 +134,10 @@ void KX_BulletPhysicsController::getOrientation(MT_Quaternion& orn)
CcdPhysicsController::getOrientation(myorn[0],myorn[1],myorn[2],myorn[3]);
orn = MT_Quaternion(myorn[0],myorn[1],myorn[2],myorn[3]);
}
-void KX_BulletPhysicsController::setOrientation(const MT_Quaternion& orn)
+void KX_BulletPhysicsController::setOrientation(const MT_Matrix3x3& orn)
{
- CcdPhysicsController::setOrientation(orn.x(),orn.y(),orn.z(),orn.w());
+ btMatrix3x3 btmat(orn[0][0], orn[0][1], orn[0][2], orn[1][0], orn[1][1], orn[1][2], orn[2][0], orn[2][1], orn[2][2]);
+ CcdPhysicsController::setWorldOrientation(btmat);
}
void KX_BulletPhysicsController::setPosition(const MT_Point3& pos)
{
@@ -126,13 +149,23 @@ void KX_BulletPhysicsController::setScaling(const MT_Vector3& scaling)
}
MT_Scalar KX_BulletPhysicsController::GetMass()
{
-
- MT_Scalar invmass = GetRigidBody()->getInvMass();
+ if (GetSoftBody())
+ return GetSoftBody()->getTotalMass();
+
+ MT_Scalar invmass = 0.f;
+ if (GetRigidBody())
+ invmass = GetRigidBody()->getInvMass();
if (invmass)
return 1.f/invmass;
return 0.f;
}
+
+MT_Scalar KX_BulletPhysicsController::GetRadius()
+{
+ return MT_Scalar(CcdPhysicsController::GetRadius());
+}
+
MT_Vector3 KX_BulletPhysicsController::getReactionForce()
{
assert(0);
@@ -142,14 +175,37 @@ void KX_BulletPhysicsController::setRigidBody(bool rigid)
{
}
-void KX_BulletPhysicsController::SuspendDynamics()
+void KX_BulletPhysicsController::SuspendDynamics(bool ghost)
{
- GetRigidBody()->setActivationState(DISABLE_SIMULATION);
-
+ btRigidBody *body = GetRigidBody();
+ if (body && body->getActivationState() != DISABLE_SIMULATION)
+ {
+ btBroadphaseProxy* handle = body->getBroadphaseHandle();
+ m_savedCollisionFlags = body->getCollisionFlags();
+ m_savedMass = GetMass();
+ m_savedCollisionFilterGroup = handle->m_collisionFilterGroup;
+ m_savedCollisionFilterMask = handle->m_collisionFilterMask;
+ body->setActivationState(DISABLE_SIMULATION);
+ GetPhysicsEnvironment()->updateCcdPhysicsController(this,
+ 0.0,
+ btCollisionObject::CF_STATIC_OBJECT|((ghost)?btCollisionObject::CF_NO_CONTACT_RESPONSE:(m_savedCollisionFlags&btCollisionObject::CF_NO_CONTACT_RESPONSE)),
+ btBroadphaseProxy::StaticFilter,
+ btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter);
+ }
}
+
void KX_BulletPhysicsController::RestoreDynamics()
{
- GetRigidBody()->forceActivationState(ACTIVE_TAG);
+ btRigidBody *body = GetRigidBody();
+ if (body && body->getActivationState() == DISABLE_SIMULATION)
+ {
+ GetPhysicsEnvironment()->updateCcdPhysicsController(this,
+ m_savedMass,
+ m_savedCollisionFlags,
+ m_savedCollisionFilterGroup,
+ m_savedCollisionFilterMask);
+ GetRigidBody()->forceActivationState(ACTIVE_TAG);
+ }
}
SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode)
@@ -161,6 +217,9 @@ SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode)
//parentcontroller is here be able to avoid collisions between parent/child
PHY_IPhysicsController* parentctrl = NULL;
+ KX_BulletPhysicsController* parentKxCtrl = NULL;
+ CcdPhysicsController* ccdParent = NULL;
+
if (destnode != destnode->GetRootSGParent())
{
@@ -180,12 +239,15 @@ SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode)
KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject());
if (clientgameobj)
{
- parentctrl = (KX_BulletPhysicsController*)clientgameobj->GetPhysicsController();
+ parentKxCtrl = (KX_BulletPhysicsController*)clientgameobj->GetPhysicsController();
+ parentctrl = parentKxCtrl;
+ ccdParent = parentKxCtrl;
}
}
}
}
+ physicsreplica->setParentCtrl(ccdParent);
physicsreplica->PostProcessReplica(motionstate,parentctrl);
physicsreplica->m_userdata = (PHY_IPhysicsController*)physicsreplica;
return physicsreplica;
@@ -196,18 +258,22 @@ SG_Controller* KX_BulletPhysicsController::GetReplica(class SG_Node* destnode)
void KX_BulletPhysicsController::SetSumoTransform(bool nondynaonly)
{
- GetRigidBody()->activate(true);
+ if (GetRigidBody())
+ GetRigidBody()->activate(true);
if (!m_bDyna)
{
- GetRigidBody()->setCollisionFlags(GetRigidBody()->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
+ GetCollisionObject()->setCollisionFlags(GetRigidBody()->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
} else
{
if (!nondynaonly)
{
btTransform worldTrans;
- GetRigidBody()->getMotionState()->getWorldTransform(worldTrans);
- GetRigidBody()->setCenterOfMassTransform(worldTrans);
+ if (GetRigidBody())
+ {
+ GetRigidBody()->getMotionState()->getWorldTransform(worldTrans);
+ GetRigidBody()->setCenterOfMassTransform(worldTrans);
+ }
/*
scaling?
diff --git a/source/gameengine/Ketsji/KX_BulletPhysicsController.h b/source/gameengine/Ketsji/KX_BulletPhysicsController.h
index 619ac42503f..cdcb82c87ca 100644
--- a/source/gameengine/Ketsji/KX_BulletPhysicsController.h
+++ b/source/gameengine/Ketsji/KX_BulletPhysicsController.h
@@ -7,6 +7,11 @@
class KX_BulletPhysicsController : public KX_IPhysicsController ,public CcdPhysicsController
{
+private:
+ int m_savedCollisionFlags;
+ short int m_savedCollisionFilterGroup;
+ short int m_savedCollisionFilterMask;
+ MT_Scalar m_savedMass;
public:
@@ -25,11 +30,12 @@ public:
virtual void ApplyTorque(const MT_Vector3& torque,bool local);
virtual void ApplyForce(const MT_Vector3& force,bool local);
virtual MT_Vector3 GetLinearVelocity();
+ virtual MT_Vector3 GetAngularVelocity();
virtual MT_Vector3 GetVelocity(const MT_Point3& pos);
virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local);
virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local);
virtual void getOrientation(MT_Quaternion& orn);
- virtual void setOrientation(const MT_Quaternion& orn);
+ virtual void setOrientation(const MT_Matrix3x3& orn);
virtual void setPosition(const MT_Point3& pos);
virtual void setScaling(const MT_Vector3& scaling);
virtual MT_Scalar GetMass();
@@ -38,14 +44,12 @@ public:
virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ);
- virtual void SuspendDynamics();
+ virtual void SuspendDynamics(bool ghost);
virtual void RestoreDynamics();
virtual SG_Controller* GetReplica(class SG_Node* destnode);
- void SetDyna(bool isDynamic) {
- m_bDyna = isDynamic;
- }
+ virtual MT_Scalar GetRadius();
virtual void SetSumoTransform(bool nondynaonly);
diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp
index 86dbd06871f..53b3e348a36 100644
--- a/source/gameengine/Ketsji/KX_Camera.cpp
+++ b/source/gameengine/Ketsji/KX_Camera.cpp
@@ -29,7 +29,8 @@
*/
#include "KX_Camera.h"
-
+#include "KX_Scene.h"
+#include "KX_PythonInit.h"
#include "KX_Python.h"
#include "KX_PyMath.h"
#ifdef HAVE_CONFIG_H
@@ -54,7 +55,9 @@ KX_Camera::KX_Camera(void* sgReplicationInfo,
m_name = "cam";
m_projection_matrix.setIdentity();
m_modelview_matrix.setIdentity();
- SetProperty("camera",new CIntValue(1));
+ CValue* val = new CIntValue(1);
+ SetProperty("camera",val);
+ val->Release();
}
@@ -63,7 +66,22 @@ KX_Camera::~KX_Camera()
}
+CValue* KX_Camera::GetReplica()
+{
+ KX_Camera* replica = new KX_Camera(*this);
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ ProcessReplica(replica);
+
+ return replica;
+}
+void KX_Camera::ProcessReplica(KX_Camera* replica)
+{
+ KX_GameObject::ProcessReplica(replica);
+}
+
MT_Transform KX_Camera::GetWorldToCamera() const
{
MT_Transform camtrans;
@@ -186,6 +204,11 @@ float KX_Camera::GetCameraFar() const
return m_camdata.m_clipend;
}
+float KX_Camera::GetFocalLength() const
+{
+ return m_camdata.m_focallength;
+}
+
RAS_CameraData* KX_Camera::GetCameraData()
@@ -388,6 +411,7 @@ PyMethodDef KX_Camera::Methods[] = {
KX_PYMETHODTABLE(KX_Camera, setProjectionMatrix),
KX_PYMETHODTABLE(KX_Camera, enableViewport),
KX_PYMETHODTABLE(KX_Camera, setViewport),
+ KX_PYMETHODTABLE(KX_Camera, setOnTop),
{NULL,NULL} //Sentinel
};
@@ -564,7 +588,7 @@ KX_PYMETHODDEF_DOC(KX_Camera, sphereInsideFrustum,
PyErr_SetString(PyExc_TypeError, "sphereInsideFrustum: Expected arguments: (center, radius)");
- Py_Return;
+ return NULL;
}
KX_PYMETHODDEF_DOC(KX_Camera, boxInsideFrustum,
@@ -742,6 +766,10 @@ KX_PYMETHODDEF_DOC(KX_Camera, enableViewport,
else
EnableViewport(false);
}
+ else {
+ return NULL;
+ }
+
Py_Return;
}
@@ -753,6 +781,20 @@ KX_PYMETHODDEF_DOC(KX_Camera, setViewport,
if (PyArg_ParseTuple(args,"iiii",&left, &bottom, &right, &top))
{
SetViewport(left, bottom, right, top);
+ } else {
+ return NULL;
}
Py_Return;
}
+
+KX_PYMETHODDEF_DOC(KX_Camera, setOnTop,
+"setOnTop()\n"
+"Sets this camera's viewport on top\n")
+{
+ class KX_Scene* scene;
+
+ scene = KX_GetActiveScene();
+ MT_assert(scene);
+ scene->SetCameraOnTop(this);
+ Py_Return;
+}
diff --git a/source/gameengine/Ketsji/KX_Camera.h b/source/gameengine/Ketsji/KX_Camera.h
index a276397c9c3..75d574cd697 100644
--- a/source/gameengine/Ketsji/KX_Camera.h
+++ b/source/gameengine/Ketsji/KX_Camera.h
@@ -131,6 +131,24 @@ public:
KX_Camera(void* sgReplicationInfo,SG_Callbacks callbacks,const RAS_CameraData& camdata, bool frustum_culling = true, PyTypeObject *T = &Type);
virtual ~KX_Camera();
+ /**
+ * Inherited from CValue -- return a new copy of this
+ * instance allocated on the heap. Ownership of the new
+ * object belongs with the caller.
+ */
+ virtual CValue*
+ GetReplica(
+ );
+
+ /**
+ * Inherited from CValue -- Makes sure any internal
+ * data owned by this class is deep copied. Called internally
+ */
+ virtual void
+ ProcessReplica(
+ KX_Camera* replica
+ );
+
MT_Transform GetWorldToCamera() const;
MT_Transform GetCameraToWorld() const;
@@ -166,12 +184,14 @@ public:
*/
const MT_Matrix4x4& GetModelviewMatrix() const;
- /** Gets the focal length. */
+ /** Gets the aperture. */
float GetLens() const;
/** Gets the near clip distance. */
float GetCameraNear() const;
/** Gets the far clip distance. */
float GetCameraFar() const;
+ /** Gets the focal length (only used for stereo rendering) */
+ float GetFocalLength() const;
/** Gets all camera data. */
RAS_CameraData* GetCameraData();
@@ -248,6 +268,7 @@ public:
KX_PYMETHOD_DOC(KX_Camera, enableViewport);
KX_PYMETHOD_DOC(KX_Camera, setViewport);
+ KX_PYMETHOD_DOC(KX_Camera, setOnTop);
virtual PyObject* _getattr(const STR_String& attr); /* lens, near, far, projection_matrix */
virtual int _setattr(const STR_String& attr, PyObject *pyvalue);
diff --git a/source/gameengine/Ketsji/KX_CameraActuator.cpp b/source/gameengine/Ketsji/KX_CameraActuator.cpp
index cb3180cb05e..4d24e83843e 100644
--- a/source/gameengine/Ketsji/KX_CameraActuator.cpp
+++ b/source/gameengine/Ketsji/KX_CameraActuator.cpp
@@ -35,6 +35,8 @@
#include <math.h>
#include "KX_GameObject.h"
+#include "PyObjectPlus.h"
+
STR_String KX_CameraActuator::X_AXIS_STRING = "x";
STR_String KX_CameraActuator::Y_AXIS_STRING = "y";
@@ -49,7 +51,7 @@ STR_String KX_CameraActuator::Y_AXIS_STRING = "y";
KX_CameraActuator::KX_CameraActuator(
SCA_IObject* gameobj,
- CValue *obj,
+ SCA_IObject *obj,
MT_Scalar hght,
MT_Scalar minhght,
MT_Scalar maxhght,
@@ -63,11 +65,14 @@ KX_CameraActuator::KX_CameraActuator(
m_maxHeight (maxhght),
m_x (xytog)
{
+ if (m_ob)
+ m_ob->RegisterActuator(this);
}
KX_CameraActuator::~KX_CameraActuator()
{
- //nothing to do
+ if (m_ob)
+ m_ob->UnregisterActuator(this);
}
CValue*
@@ -81,8 +86,35 @@ GetReplica(
return replica;
};
+void KX_CameraActuator::ProcessReplica()
+{
+ if (m_ob)
+ m_ob->RegisterActuator(this);
+ SCA_IActuator::ProcessReplica();
+}
+
+bool KX_CameraActuator::UnlinkObject(SCA_IObject* clientobj)
+{
+ if (clientobj == m_ob)
+ {
+ // this object is being deleted, we cannot continue to track it.
+ m_ob = NULL;
+ return true;
+ }
+ return false;
+}
+void KX_CameraActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
+{
+ void **h_obj = (*obj_map)[m_ob];
+ if (h_obj) {
+ if (m_ob)
+ m_ob->UnregisterActuator(this);
+ m_ob = (SCA_IObject*)(*h_obj);
+ m_ob->RegisterActuator(this);
+ }
+}
/* three functions copied from blender arith... don't know if there's an equivalent */
@@ -155,14 +187,25 @@ static void Kx_VecUpMat3(float *vec, float mat[][3], short axis)
mat[coz][0]= vec[0];
mat[coz][1]= vec[1];
mat[coz][2]= vec[2];
- Kx_Normalize((float *)mat[coz]);
+ if (Kx_Normalize((float *)mat[coz]) == 0.f) {
+ /* this is a very abnormal situation: the camera has reach the object center exactly
+ We will choose a completely arbitrary direction */
+ mat[coz][0] = 1.0f;
+ mat[coz][1] = 0.0f;
+ mat[coz][2] = 0.0f;
+ }
inp= mat[coz][2];
mat[coy][0]= - inp*mat[coz][0];
mat[coy][1]= - inp*mat[coz][1];
mat[coy][2]= 1.0 - inp*mat[coz][2];
- Kx_Normalize((float *)mat[coy]);
+ if (Kx_Normalize((float *)mat[coy]) == 0.f) {
+ /* the camera is vertical, chose the y axis arbitrary */
+ mat[coy][0] = 0.f;
+ mat[coy][1] = 1.f;
+ mat[coy][2] = 0.f;
+ }
Kx_Crossf(mat[cox], mat[coy], mat[coz]);
@@ -170,8 +213,14 @@ static void Kx_VecUpMat3(float *vec, float mat[][3], short axis)
bool KX_CameraActuator::Update(double curtime, bool frame)
{
- bool result = true;
+ /* wondering... is it really neccesary/desirable to suppress negative */
+ /* events here? */
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+ if (bNegativeEvent || !m_ob)
+ return false;
+
KX_GameObject *obj = (KX_GameObject*) GetParent();
MT_Point3 from = obj->NodeGetWorldPosition();
MT_Matrix3x3 frommat = obj->NodeGetWorldOrientation();
@@ -184,13 +233,6 @@ bool KX_CameraActuator::Update(double curtime, bool frame)
float mindistsq, maxdistsq, distsq;
float mat[3][3];
- /* wondering... is it really neccesary/desirable to suppress negative */
- /* events here? */
- bool bNegativeEvent = IsNegativeEvent();
- RemoveAllEvents();
-
- if (bNegativeEvent) return false;
-
/* The rules: */
/* CONSTRAINT 1: not implemented */
/* CONSTRAINT 2: can camera see actor? */
@@ -304,7 +346,7 @@ bool KX_CameraActuator::Update(double curtime, bool frame)
actormat[2][0]= mat[0][2]; actormat[2][1]= mat[1][2]; actormat[2][2]= mat[2][2];
obj->NodeSetLocalOrientation(actormat);
- return result;
+ return true;
}
CValue *KX_CameraActuator::findObject(char *obName)
@@ -355,16 +397,16 @@ PyParentObject KX_CameraActuator::Parents[] = {
};
PyMethodDef KX_CameraActuator::Methods[] = {
- {"setObject",(PyCFunction) KX_CameraActuator::sPySetObject, METH_VARARGS, SetObject_doc},
- {"getObject",(PyCFunction) KX_CameraActuator::sPyGetObject, METH_NOARGS, GetObject_doc},
- {"setMin" ,(PyCFunction) KX_CameraActuator::sPySetMin, METH_VARARGS, SetMin_doc},
- {"getMin" ,(PyCFunction) KX_CameraActuator::sPyGetMin, METH_NOARGS, GetMin_doc},
- {"setMax" ,(PyCFunction) KX_CameraActuator::sPySetMax, METH_VARARGS, SetMax_doc},
- {"getMax" ,(PyCFunction) KX_CameraActuator::sPyGetMax, METH_NOARGS, GetMax_doc},
- {"setHeight",(PyCFunction) KX_CameraActuator::sPySetHeight, METH_VARARGS, SetHeight_doc},
- {"getHeight",(PyCFunction) KX_CameraActuator::sPyGetHeight, METH_NOARGS, GetHeight_doc},
- {"setXY" ,(PyCFunction) KX_CameraActuator::sPySetXY, METH_VARARGS, SetXY_doc},
- {"getXY" ,(PyCFunction) KX_CameraActuator::sPyGetXY, METH_VARARGS, GetXY_doc},
+ {"setObject",(PyCFunction) KX_CameraActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc},
+ {"getObject",(PyCFunction) KX_CameraActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc},
+ {"setMin" ,(PyCFunction) KX_CameraActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetMin_doc},
+ {"getMin" ,(PyCFunction) KX_CameraActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetMin_doc},
+ {"setMax" ,(PyCFunction) KX_CameraActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetMax_doc},
+ {"getMax" ,(PyCFunction) KX_CameraActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetMax_doc},
+ {"setHeight",(PyCFunction) KX_CameraActuator::sPySetHeight, METH_VARARGS, (PY_METHODCHAR)SetHeight_doc},
+ {"getHeight",(PyCFunction) KX_CameraActuator::sPyGetHeight, METH_NOARGS, (PY_METHODCHAR)GetHeight_doc},
+ {"setXY" ,(PyCFunction) KX_CameraActuator::sPySetXY, METH_VARARGS, (PY_METHODCHAR)SetXY_doc},
+ {"getXY" ,(PyCFunction) KX_CameraActuator::sPyGetXY, METH_VARARGS, (PY_METHODCHAR)GetXY_doc},
{NULL,NULL,NULL,NULL} //Sentinel
};
@@ -372,48 +414,48 @@ PyObject* KX_CameraActuator::_getattr(const STR_String& attr) {
_getattr_up(SCA_IActuator);
}
/* get obj ---------------------------------------------------------- */
-char KX_CameraActuator::GetObject_doc[] =
-"getObject\n"
+const char KX_CameraActuator::GetObject_doc[] =
+"getObject(name_only = 1)\n"
+"name_only - optional arg, when true will return the KX_GameObject rather then its name\n"
"\tReturns the object this sensor reacts to.\n";
-PyObject* KX_CameraActuator::PyGetObject(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_CameraActuator::PyGetObject(PyObject* self, PyObject* args)
{
- return PyString_FromString(m_ob->GetName());
+ int ret_name_only = 1;
+ if (!PyArg_ParseTuple(args, "|i", &ret_name_only))
+ return NULL;
+
+ if (!m_ob)
+ Py_RETURN_NONE;
+
+ if (ret_name_only)
+ return PyString_FromString(m_ob->GetName());
+ else
+ return m_ob->AddRef();
}
/* set obj ---------------------------------------------------------- */
-char KX_CameraActuator::SetObject_doc[] =
-"setObject\n"
+const char KX_CameraActuator::SetObject_doc[] =
+"setObject(object)\n"
+"\t- object: KX_GameObject, string or None\n"
"\tSets the object this sensor reacts to.\n";
-PyObject* KX_CameraActuator::PySetObject(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_CameraActuator::PySetObject(PyObject* self, PyObject* value)
{
-
- PyObject* gameobj;
- if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj))
- {
- m_ob = (CValue*)gameobj;
- Py_Return;
- }
- PyErr_Clear();
+ KX_GameObject *gameobj;
- char* objectname;
- if (PyArg_ParseTuple(args, "s", &objectname))
- {
- CValue *object = (CValue*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname));
- if(object)
- {
- m_ob = object;
- Py_Return;
- }
- }
+ if (!ConvertPythonToGameObject(value, &gameobj, true))
+ return NULL; // ConvertPythonToGameObject sets the error
- return NULL;
+ if (m_ob != NULL)
+ m_ob->UnregisterActuator(this);
+
+ m_ob = (SCA_IObject*)gameobj;
+ if (m_ob)
+ m_ob->RegisterActuator(this);
+
+ Py_RETURN_NONE;
}
/* get min ---------------------------------------------------------- */
-char KX_CameraActuator::GetMin_doc[] =
+const char KX_CameraActuator::GetMin_doc[] =
"getMin\n"
"\tReturns the minimum value set in the Min: field.\n";
PyObject* KX_CameraActuator::PyGetMin(PyObject* self,
@@ -423,7 +465,7 @@ PyObject* KX_CameraActuator::PyGetMin(PyObject* self,
return PyFloat_FromDouble(m_minHeight);
}
/* set min ---------------------------------------------------------- */
-char KX_CameraActuator::SetMin_doc[] =
+const char KX_CameraActuator::SetMin_doc[] =
"setMin\n"
"\tSets the minimum value.\n";
PyObject* KX_CameraActuator::PySetMin(PyObject* self,
@@ -439,7 +481,7 @@ PyObject* KX_CameraActuator::PySetMin(PyObject* self,
return NULL;
}
/* get min ---------------------------------------------------------- */
-char KX_CameraActuator::GetMax_doc[] =
+const char KX_CameraActuator::GetMax_doc[] =
"getMax\n"
"\tReturns the maximum value set in the Max: field.\n";
PyObject* KX_CameraActuator::PyGetMax(PyObject* self,
@@ -449,7 +491,7 @@ PyObject* KX_CameraActuator::PyGetMax(PyObject* self,
return PyFloat_FromDouble(m_maxHeight);
}
/* set min ---------------------------------------------------------- */
-char KX_CameraActuator::SetMax_doc[] =
+const char KX_CameraActuator::SetMax_doc[] =
"setMax\n"
"\tSets the maximum value.\n";
PyObject* KX_CameraActuator::PySetMax(PyObject* self,
@@ -465,7 +507,7 @@ PyObject* KX_CameraActuator::PySetMax(PyObject* self,
return NULL;
}
/* get height ---------------------------------------------------------- */
-char KX_CameraActuator::GetHeight_doc[] =
+const char KX_CameraActuator::GetHeight_doc[] =
"getHeight\n"
"\tReturns the height value set in the height: field.\n";
PyObject* KX_CameraActuator::PyGetHeight(PyObject* self,
@@ -475,7 +517,7 @@ PyObject* KX_CameraActuator::PyGetHeight(PyObject* self,
return PyFloat_FromDouble(m_height);
}
/* set height ---------------------------------------------------------- */
-char KX_CameraActuator::SetHeight_doc[] =
+const char KX_CameraActuator::SetHeight_doc[] =
"setHeight\n"
"\tSets the height value.\n";
PyObject* KX_CameraActuator::PySetHeight(PyObject* self,
@@ -491,7 +533,7 @@ PyObject* KX_CameraActuator::PySetHeight(PyObject* self,
return NULL;
}
/* set XY ---------------------------------------------------------- */
-char KX_CameraActuator::SetXY_doc[] =
+const char KX_CameraActuator::SetXY_doc[] =
"setXY\n"
"\tSets axis the camera tries to get behind.\n"
"\t1=x, 0=y\n";
@@ -509,7 +551,7 @@ PyObject* KX_CameraActuator::PySetXY(PyObject* self,
}
/* get XY -------------------------------------------------------------*/
-char KX_CameraActuator::GetXY_doc[] =
+const char KX_CameraActuator::GetXY_doc[] =
"getXY\n"
"\tGets the axis the camera tries to get behind.\n"
"\tTrue = X, False = Y\n";
diff --git a/source/gameengine/Ketsji/KX_CameraActuator.h b/source/gameengine/Ketsji/KX_CameraActuator.h
index eb007e403ec..d53d12b3b82 100644
--- a/source/gameengine/Ketsji/KX_CameraActuator.h
+++ b/source/gameengine/Ketsji/KX_CameraActuator.h
@@ -49,7 +49,7 @@ class KX_CameraActuator : public SCA_IActuator
Py_Header;
private :
/** Object that will be tracked. */
- CValue *m_ob;
+ SCA_IObject *m_ob;
/** height (float), */
//const MT_Scalar m_height;
@@ -87,7 +87,7 @@ private :
SCA_IObject *gameobj,
//const CValue *ob,
- CValue *ob,
+ SCA_IObject *ob,
MT_Scalar hght,
MT_Scalar minhght,
MT_Scalar maxhght,
@@ -103,6 +103,7 @@ private :
/** Methods Inherited from CValue */
CValue* GetReplica();
+ virtual void ProcessReplica();
/** Methods inherited from SCA_IActuator */
@@ -110,7 +111,10 @@ private :
double curtime,
bool frame
);
+ virtual bool UnlinkObject(SCA_IObject* clientobj);
+ /** Methods inherited from SCA_ILogicBrick */
+ virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
/* --------------------------------------------------------------------- */
/* Python interface ---------------------------------------------------- */
@@ -119,9 +123,9 @@ private :
virtual PyObject* _getattr(const STR_String& attr);
/* set object to look at */
- KX_PYMETHOD_DOC(KX_CameraActuator,SetObject);
+ KX_PYMETHOD_DOC_O(KX_CameraActuator,SetObject);
/* get current object */
- KX_PYMETHOD_DOC(KX_CameraActuator,GetObject);
+ KX_PYMETHOD_DOC_VARARGS(KX_CameraActuator,GetObject);
KX_PYMETHOD_DOC(KX_CameraActuator,SetMin);
KX_PYMETHOD_DOC(KX_CameraActuator,GetMin);
KX_PYMETHOD_DOC(KX_CameraActuator,SetMax);
diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
index bd843d97199..76357e9c58f 100644
--- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
+++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
@@ -35,6 +35,7 @@
#include "MT_Point3.h"
#include "MT_Matrix3x3.h"
#include "KX_GameObject.h"
+#include "KX_RayCast.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -45,35 +46,60 @@
/* ------------------------------------------------------------------------- */
KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj,
- int dampTime,
+ int posDampTime,
+ int rotDampTime,
float minBound,
float maxBound,
+ float refDir[3],
int locrotxyz,
- PyTypeObject* T)
- : SCA_IActuator(gameobj, T)
+ int time,
+ int option,
+ char *property,
+ PyTypeObject* T) :
+ m_refDirection(refDir),
+ m_currentTime(0),
+ SCA_IActuator(gameobj, T)
{
- m_dampTime = dampTime;
+ m_posDampTime = posDampTime;
+ m_rotDampTime = rotDampTime;
m_locrot = locrotxyz;
+ m_option = option;
+ m_activeTime = time;
+ if (property) {
+ strncpy(m_property, property, sizeof(m_property));
+ m_property[sizeof(m_property)-1] = 0;
+ } else {
+ m_property[0] = 0;
+ }
/* The units of bounds are determined by the type of constraint. To */
/* make the constraint application easier and more transparent later on, */
/* I think converting the bounds to the applicable domain makes more */
/* sense. */
switch (m_locrot) {
- case KX_ACT_CONSTRAINT_LOCX:
- case KX_ACT_CONSTRAINT_LOCY:
- case KX_ACT_CONSTRAINT_LOCZ:
+ case KX_ACT_CONSTRAINT_ORIX:
+ case KX_ACT_CONSTRAINT_ORIY:
+ case KX_ACT_CONSTRAINT_ORIZ:
+ {
+ MT_Scalar len = m_refDirection.length();
+ if (MT_fuzzyZero(len)) {
+ // missing a valid direction
+ std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no valid reference direction!" << std::endl;
+ m_locrot = KX_ACT_CONSTRAINT_NODEF;
+ } else {
+ m_refDirection /= len;
+ }
+ m_minimumBound = cos(minBound);
+ m_maximumBound = cos(maxBound);
+ m_minimumSine = sin(minBound);
+ m_maximumSine = sin(maxBound);
+ }
+ break;
+ default:
m_minimumBound = minBound;
m_maximumBound = maxBound;
+ m_minimumSine = 0.f;
+ m_maximumSine = 0.f;
break;
- case KX_ACT_CONSTRAINT_ROTX:
- case KX_ACT_CONSTRAINT_ROTY:
- case KX_ACT_CONSTRAINT_ROTZ:
- /* The user interface asks for degrees, we are radian. */
- m_minimumBound = MT_radians(minBound);
- m_maximumBound = MT_radians(maxBound);
- break;
- default:
- ; /* error */
}
} /* End of constructor */
@@ -83,77 +109,426 @@ KX_ConstraintActuator::~KX_ConstraintActuator()
// there's nothing to be done here, really....
} /* end of destructor */
-bool KX_ConstraintActuator::Update(double curtime, bool frame)
+bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data)
{
- bool result = false;
- bool bNegativeEvent = IsNegativeEvent();
- RemoveAllEvents();
-
- if (bNegativeEvent)
- return false; // do nothing on negative events
-
- /* Constraint clamps the values to the specified range, with a sort of */
- /* low-pass filtered time response, if the damp time is unequal to 0. */
-
- /* Having to retrieve location/rotation and setting it afterwards may not */
- /* be efficient enough... Somthing to look at later. */
- KX_GameObject *parent = (KX_GameObject*) GetParent();
- MT_Point3 position = parent->NodeGetWorldPosition();
- MT_Matrix3x3 rotation = parent->NodeGetWorldOrientation();
-// MT_Vector3 eulerrot = rotation.getEuler();
-
- switch (m_locrot) {
- case KX_ACT_CONSTRAINT_LOCX:
- Clamp(position[0], m_minimumBound, m_maximumBound);
- result = true;
- break;
- case KX_ACT_CONSTRAINT_LOCY:
- Clamp(position[1], m_minimumBound, m_maximumBound);
- result = true;
- break;
- case KX_ACT_CONSTRAINT_LOCZ:
- Clamp(position[2], m_minimumBound, m_maximumBound);
- result = true;
- break;
+ m_hitObject = client->m_gameobject;
-// case KX_ACT_CONSTRAINT_ROTX:
-// /* The angles are Euler angles (I think that's what they are called) */
-// /* but we need to convert from/to the MT_Matrix3x3. */
-// Clamp(eulerrot[0], m_minimumBound, m_maximumBound);
-// break;
-// case KX_ACT_CONSTRAINT_ROTY:
-// Clamp(eulerrot[1], m_minimumBound, m_maximumBound);
-// break;
-// case KX_ACT_CONSTRAINT_ROTZ:
-// Clamp(eulerrot[2], m_minimumBound, m_maximumBound);
-// break;
-// default:
-// ; /* error */
- }
+ bool bFound = false;
- /* Will be replaced by a filtered clamp. */
-
+ if (m_property[0] == 0)
+ {
+ bFound = true;
+ }
+ else
+ {
+ if (m_option & KX_ACT_CONSTRAINT_MATERIAL)
+ {
+ if (client->m_auxilary_info)
+ {
+ bFound = !strcmp(m_property, ((char*)client->m_auxilary_info));
+ }
+ }
+ else
+ {
+ bFound = m_hitObject->GetProperty(m_property) != NULL;
+ }
+ }
+ // update the hit status
+ result->m_hitFound = bFound;
+ // stop looking
+ return true;
+}
- switch (m_locrot) {
- case KX_ACT_CONSTRAINT_LOCX:
- case KX_ACT_CONSTRAINT_LOCY:
- case KX_ACT_CONSTRAINT_LOCZ:
- parent->NodeSetLocalPosition(position);
- break;
+/* this function is used to pre-filter the object before casting the ray on them.
+ This is useful for "X-Ray" option when we want to see "through" unwanted object.
+ */
+bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo* client)
+{
+ if (client->m_type > KX_ClientObjectInfo::ACTOR)
+ {
+ // Unknown type of object, skip it.
+ // Should not occur as the sensor objects are filtered in RayTest()
+ printf("Invalid client type %d found in ray casting\n", client->m_type);
+ return false;
+ }
+ // no X-Ray function yet
+ return true;
+}
+bool KX_ConstraintActuator::Update(double curtime, bool frame)
+{
-// case KX_ACT_CONSTRAINT_ROTX:
-// case KX_ACT_CONSTRAINT_ROTY:
-// case KX_ACT_CONSTRAINT_ROTZ:
-// rotation.setEuler(eulerrot);
-// parent->NodeSetLocalOrientation(rotation);
- break;
+ bool result = false;
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
- default:
- ; /* error */
+ if (!bNegativeEvent) {
+ /* Constraint clamps the values to the specified range, with a sort of */
+ /* low-pass filtered time response, if the damp time is unequal to 0. */
+
+ /* Having to retrieve location/rotation and setting it afterwards may not */
+ /* be efficient enough... Somthing to look at later. */
+ KX_GameObject *obj = (KX_GameObject*) GetParent();
+ MT_Point3 position = obj->NodeGetWorldPosition();
+ MT_Point3 newposition;
+ MT_Vector3 normal, direction, refDirection;
+ MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation();
+ MT_Scalar filter, newdistance, cosangle;
+ int axis, sign;
+
+ if (m_posDampTime) {
+ filter = m_posDampTime/(1.0+m_posDampTime);
+ } else {
+ filter = 0.0;
+ }
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_ORIX:
+ case KX_ACT_CONSTRAINT_ORIY:
+ case KX_ACT_CONSTRAINT_ORIZ:
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_ORIX:
+ direction[0] = rotation[0][0];
+ direction[1] = rotation[1][0];
+ direction[2] = rotation[2][0];
+ axis = 0;
+ break;
+ case KX_ACT_CONSTRAINT_ORIY:
+ direction[0] = rotation[0][1];
+ direction[1] = rotation[1][1];
+ direction[2] = rotation[2][1];
+ axis = 1;
+ break;
+ default:
+ direction[0] = rotation[0][2];
+ direction[1] = rotation[1][2];
+ direction[2] = rotation[2][2];
+ axis = 2;
+ break;
+ }
+ if ((m_maximumBound < (1.0f-FLT_EPSILON)) || (m_minimumBound < (1.0f-FLT_EPSILON))) {
+ // reference direction needs to be evaluated
+ // 1. get the cosine between current direction and target
+ cosangle = direction.dot(m_refDirection);
+ if (cosangle >= (m_maximumBound-FLT_EPSILON) && cosangle <= (m_minimumBound+FLT_EPSILON)) {
+ // no change to do
+ result = true;
+ goto CHECK_TIME;
+ }
+ // 2. define a new reference direction
+ // compute local axis with reference direction as X and
+ // Y in direction X refDirection plane
+ MT_Vector3 zaxis = m_refDirection.cross(direction);
+ if (MT_fuzzyZero2(zaxis.length2())) {
+ // direction and refDirection are identical,
+ // choose any other direction to define plane
+ if (direction[0] < 0.9999)
+ zaxis = m_refDirection.cross(MT_Vector3(1.0,0.0,0.0));
+ else
+ zaxis = m_refDirection.cross(MT_Vector3(0.0,1.0,0.0));
+ }
+ MT_Vector3 yaxis = zaxis.cross(m_refDirection);
+ yaxis.normalize();
+ if (cosangle > m_minimumBound) {
+ // angle is too close to reference direction,
+ // choose a new reference that is exactly at minimum angle
+ refDirection = m_minimumBound * m_refDirection + m_minimumSine * yaxis;
+ } else {
+ // angle is too large, choose new reference direction at maximum angle
+ refDirection = m_maximumBound * m_refDirection + m_maximumSine * yaxis;
+ }
+ } else {
+ refDirection = m_refDirection;
+ }
+ // apply damping on the direction
+ direction = filter*direction + (1.0-filter)*refDirection;
+ obj->AlignAxisToVect(direction, axis);
+ result = true;
+ goto CHECK_TIME;
+ case KX_ACT_CONSTRAINT_DIRPX:
+ case KX_ACT_CONSTRAINT_DIRPY:
+ case KX_ACT_CONSTRAINT_DIRPZ:
+ case KX_ACT_CONSTRAINT_DIRNX:
+ case KX_ACT_CONSTRAINT_DIRNY:
+ case KX_ACT_CONSTRAINT_DIRNZ:
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_DIRPX:
+ normal[0] = rotation[0][0];
+ normal[1] = rotation[1][0];
+ normal[2] = rotation[2][0];
+ axis = 0; // axis according to KX_GameObject::AlignAxisToVect()
+ sign = 0; // X axis will be parrallel to direction of ray
+ break;
+ case KX_ACT_CONSTRAINT_DIRPY:
+ normal[0] = rotation[0][1];
+ normal[1] = rotation[1][1];
+ normal[2] = rotation[2][1];
+ axis = 1;
+ sign = 0;
+ break;
+ case KX_ACT_CONSTRAINT_DIRPZ:
+ normal[0] = rotation[0][2];
+ normal[1] = rotation[1][2];
+ normal[2] = rotation[2][2];
+ axis = 2;
+ sign = 0;
+ break;
+ case KX_ACT_CONSTRAINT_DIRNX:
+ normal[0] = -rotation[0][0];
+ normal[1] = -rotation[1][0];
+ normal[2] = -rotation[2][0];
+ axis = 0;
+ sign = 1;
+ break;
+ case KX_ACT_CONSTRAINT_DIRNY:
+ normal[0] = -rotation[0][1];
+ normal[1] = -rotation[1][1];
+ normal[2] = -rotation[2][1];
+ axis = 1;
+ sign = 1;
+ break;
+ case KX_ACT_CONSTRAINT_DIRNZ:
+ normal[0] = -rotation[0][2];
+ normal[1] = -rotation[1][2];
+ normal[2] = -rotation[2][2];
+ axis = 2;
+ sign = 1;
+ break;
+ }
+ normal.normalize();
+ if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
+ // direction of the ray is along the local axis
+ direction = normal;
+ } else {
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_DIRPX:
+ direction = MT_Vector3(1.0,0.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_DIRPY:
+ direction = MT_Vector3(0.0,1.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_DIRPZ:
+ direction = MT_Vector3(0.0,0.0,1.0);
+ break;
+ case KX_ACT_CONSTRAINT_DIRNX:
+ direction = MT_Vector3(-1.0,0.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_DIRNY:
+ direction = MT_Vector3(0.0,-1.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_DIRNZ:
+ direction = MT_Vector3(0.0,0.0,-1.0);
+ break;
+ }
+ }
+ {
+ MT_Point3 topoint = position + (m_maximumBound) * direction;
+ PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment();
+ KX_IPhysicsController *spc = obj->GetPhysicsController();
+
+ if (!pe) {
+ std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no physics environment!" << std::endl;
+ goto CHECK_TIME;
+ }
+ if (!spc) {
+ // the object is not physical, we probably want to avoid hitting its own parent
+ KX_GameObject *parent = obj->GetParent();
+ if (parent) {
+ spc = parent->GetPhysicsController();
+ parent->Release();
+ }
+ }
+ KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc);
+ result = KX_RayCast::RayTest(pe, position, topoint, callback);
+ if (result) {
+ MT_Vector3 newnormal = callback.m_hitNormal;
+ // compute new position & orientation
+ if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) {
+ // if none option is set, the actuator does nothing but detect ray
+ // (works like a sensor)
+ goto CHECK_TIME;
+ }
+ if (m_option & KX_ACT_CONSTRAINT_NORMAL) {
+ MT_Scalar rotFilter;
+ // apply damping on the direction
+ if (m_rotDampTime) {
+ rotFilter = m_rotDampTime/(1.0+m_rotDampTime);
+ } else {
+ rotFilter = filter;
+ }
+ newnormal = rotFilter*normal - (1.0-rotFilter)*newnormal;
+ obj->AlignAxisToVect((sign)?-newnormal:newnormal, axis);
+ if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
+ direction = newnormal;
+ direction.normalize();
+ }
+ }
+ if (m_option & KX_ACT_CONSTRAINT_DISTANCE) {
+ if (m_posDampTime) {
+ newdistance = filter*(position-callback.m_hitPoint).length()+(1.0-filter)*m_minimumBound;
+ } else {
+ newdistance = m_minimumBound;
+ }
+ // logically we should cancel the speed along the ray direction as we set the
+ // position along that axis
+ spc = obj->GetPhysicsController();
+ if (spc && spc->IsDyna()) {
+ MT_Vector3 linV = spc->GetLinearVelocity();
+ // cancel the projection along the ray direction
+ MT_Scalar fallspeed = linV.dot(direction);
+ if (!MT_fuzzyZero(fallspeed))
+ spc->SetLinearVelocity(linV-fallspeed*direction,false);
+ }
+ } else {
+ newdistance = (position-callback.m_hitPoint).length();
+ }
+ newposition = callback.m_hitPoint-newdistance*direction;
+ } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
+ // no contact but still keep running
+ result = true;
+ goto CHECK_TIME;
+ }
+ }
+ break;
+ case KX_ACT_CONSTRAINT_FHPX:
+ case KX_ACT_CONSTRAINT_FHPY:
+ case KX_ACT_CONSTRAINT_FHPZ:
+ case KX_ACT_CONSTRAINT_FHNX:
+ case KX_ACT_CONSTRAINT_FHNY:
+ case KX_ACT_CONSTRAINT_FHNZ:
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_FHPX:
+ normal[0] = -rotation[0][0];
+ normal[1] = -rotation[1][0];
+ normal[2] = -rotation[2][0];
+ direction = MT_Vector3(1.0,0.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_FHPY:
+ normal[0] = -rotation[0][1];
+ normal[1] = -rotation[1][1];
+ normal[2] = -rotation[2][1];
+ direction = MT_Vector3(0.0,1.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_FHPZ:
+ normal[0] = -rotation[0][2];
+ normal[1] = -rotation[1][2];
+ normal[2] = -rotation[2][2];
+ direction = MT_Vector3(0.0,0.0,1.0);
+ break;
+ case KX_ACT_CONSTRAINT_FHNX:
+ normal[0] = rotation[0][0];
+ normal[1] = rotation[1][0];
+ normal[2] = rotation[2][0];
+ direction = MT_Vector3(-1.0,0.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_FHNY:
+ normal[0] = rotation[0][1];
+ normal[1] = rotation[1][1];
+ normal[2] = rotation[2][1];
+ direction = MT_Vector3(0.0,-1.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_FHNZ:
+ normal[0] = rotation[0][2];
+ normal[1] = rotation[1][2];
+ normal[2] = rotation[2][2];
+ direction = MT_Vector3(0.0,0.0,-1.0);
+ break;
+ }
+ normal.normalize();
+ {
+ PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment();
+ KX_IPhysicsController *spc = obj->GetPhysicsController();
+
+ if (!pe) {
+ std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no physics environment!" << std::endl;
+ goto CHECK_TIME;
+ }
+ if (!spc || !spc->IsDyna()) {
+ // the object is not dynamic, it won't support setting speed
+ goto CHECK_TIME;
+ }
+ m_hitObject = NULL;
+ // distance of Fh area is stored in m_minimum
+ MT_Point3 topoint = position + (m_minimumBound+spc->GetRadius()) * direction;
+ KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc);
+ result = KX_RayCast::RayTest(pe, position, topoint, callback);
+ // we expect a hit object
+ if (!m_hitObject)
+ result = false;
+ if (result)
+ {
+ MT_Vector3 newnormal = callback.m_hitNormal;
+ // compute new position & orientation
+ MT_Scalar distance = (callback.m_hitPoint-position).length()-spc->GetRadius();
+ // estimate the velocity of the hit point
+ MT_Point3 relativeHitPoint;
+ relativeHitPoint = (callback.m_hitPoint-m_hitObject->NodeGetWorldPosition());
+ MT_Vector3 velocityHitPoint = m_hitObject->GetVelocity(relativeHitPoint);
+ MT_Vector3 relativeVelocity = spc->GetLinearVelocity() - velocityHitPoint;
+ MT_Scalar relativeVelocityRay = direction.dot(relativeVelocity);
+ MT_Scalar springExtent = 1.0 - distance/m_minimumBound;
+ // Fh force is stored in m_maximum
+ MT_Scalar springForce = springExtent * m_maximumBound;
+ // damping is stored in m_refDirection [0] = damping, [1] = rot damping
+ MT_Scalar springDamp = relativeVelocityRay * m_refDirection[0];
+ MT_Vector3 newVelocity = spc->GetLinearVelocity()-(springForce+springDamp)*direction;
+ if (m_option & KX_ACT_CONSTRAINT_NORMAL)
+ {
+ newVelocity+=(springForce+springDamp)*(newnormal-newnormal.dot(direction)*direction);
+ }
+ spc->SetLinearVelocity(newVelocity, false);
+ if (m_option & KX_ACT_CONSTRAINT_DOROTFH)
+ {
+ MT_Vector3 angSpring = (normal.cross(newnormal))*m_maximumBound;
+ MT_Vector3 angVelocity = spc->GetAngularVelocity();
+ // remove component that is parallel to normal
+ angVelocity -= angVelocity.dot(newnormal)*newnormal;
+ MT_Vector3 angDamp = angVelocity * ((m_refDirection[1]>MT_EPSILON)?m_refDirection[1]:m_refDirection[0]);
+ spc->SetAngularVelocity(spc->GetAngularVelocity()+(angSpring-angDamp), false);
+ }
+ } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
+ // no contact but still keep running
+ result = true;
+ }
+ // don't set the position with this constraint
+ goto CHECK_TIME;
+ }
+ break;
+ case KX_ACT_CONSTRAINT_LOCX:
+ case KX_ACT_CONSTRAINT_LOCY:
+ case KX_ACT_CONSTRAINT_LOCZ:
+ newposition = position = obj->GetSGNode()->GetLocalPosition();
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_LOCX:
+ Clamp(newposition[0], m_minimumBound, m_maximumBound);
+ break;
+ case KX_ACT_CONSTRAINT_LOCY:
+ Clamp(newposition[1], m_minimumBound, m_maximumBound);
+ break;
+ case KX_ACT_CONSTRAINT_LOCZ:
+ Clamp(newposition[2], m_minimumBound, m_maximumBound);
+ break;
+ }
+ result = true;
+ if (m_posDampTime) {
+ newposition = filter*position + (1.0-filter)*newposition;
+ }
+ obj->NodeSetLocalPosition(newposition);
+ goto CHECK_TIME;
+ }
+ if (result) {
+ // set the new position but take into account parent if any
+ obj->NodeSetWorldPosition(newposition);
+ }
+ CHECK_TIME:
+ if (result && m_activeTime > 0 ) {
+ if (++m_currentTime >= m_activeTime)
+ result = false;
+ }
+ }
+ if (!result) {
+ m_currentTime = 0;
}
-
return result;
} /* end of KX_ConstraintActuator::Update(double curtime,double deltatime) */
@@ -212,14 +587,28 @@ PyParentObject KX_ConstraintActuator::Parents[] = {
};
PyMethodDef KX_ConstraintActuator::Methods[] = {
- {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, SetDamp_doc},
- {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_VARARGS, GetDamp_doc},
- {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetMin_doc},
- {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_VARARGS, GetMin_doc},
- {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetMax_doc},
- {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_VARARGS, GetMax_doc},
- {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, SetLimit_doc},
- {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_VARARGS, GetLimit_doc},
+ {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, (PY_METHODCHAR)SetDamp_doc},
+ {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_NOARGS, (PY_METHODCHAR)GetDamp_doc},
+ {"setRotDamp", (PyCFunction) KX_ConstraintActuator::sPySetRotDamp, METH_VARARGS, (PY_METHODCHAR)SetRotDamp_doc},
+ {"getRotDamp", (PyCFunction) KX_ConstraintActuator::sPyGetRotDamp, METH_NOARGS, (PY_METHODCHAR)GetRotDamp_doc},
+ {"setDirection", (PyCFunction) KX_ConstraintActuator::sPySetDirection, METH_VARARGS, (PY_METHODCHAR)SetDirection_doc},
+ {"getDirection", (PyCFunction) KX_ConstraintActuator::sPyGetDirection, METH_NOARGS, (PY_METHODCHAR)GetDirection_doc},
+ {"setOption", (PyCFunction) KX_ConstraintActuator::sPySetOption, METH_VARARGS, (PY_METHODCHAR)SetOption_doc},
+ {"getOption", (PyCFunction) KX_ConstraintActuator::sPyGetOption, METH_NOARGS, (PY_METHODCHAR)GetOption_doc},
+ {"setTime", (PyCFunction) KX_ConstraintActuator::sPySetTime, METH_VARARGS, (PY_METHODCHAR)SetTime_doc},
+ {"getTime", (PyCFunction) KX_ConstraintActuator::sPyGetTime, METH_NOARGS, (PY_METHODCHAR)GetTime_doc},
+ {"setProperty", (PyCFunction) KX_ConstraintActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc},
+ {"getProperty", (PyCFunction) KX_ConstraintActuator::sPyGetProperty, METH_NOARGS, (PY_METHODCHAR)GetProperty_doc},
+ {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetMin_doc},
+ {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetMin_doc},
+ {"setDistance", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetDistance_doc},
+ {"getDistance", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetDistance_doc},
+ {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetMax_doc},
+ {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetMax_doc},
+ {"setRayLength", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetRayLength_doc},
+ {"getRayLength", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetRayLength_doc},
+ {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, (PY_METHODCHAR)SetLimit_doc},
+ {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_NOARGS, (PY_METHODCHAR)GetLimit_doc},
{NULL,NULL} //Sentinel
};
@@ -228,10 +617,10 @@ PyObject* KX_ConstraintActuator::_getattr(const STR_String& attr) {
}
/* 2. setDamp */
-char KX_ConstraintActuator::SetDamp_doc[] =
+const char KX_ConstraintActuator::SetDamp_doc[] =
"setDamp(duration)\n"
"\t- duration: integer\n"
-"\tSets the time with which the constraint application is delayed.\n"
+"\tSets the time constant of the orientation and distance constraint.\n"
"\tIf the duration is negative, it is set to 0.\n";
PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self,
PyObject* args,
@@ -241,23 +630,182 @@ PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self,
return NULL;
}
- m_dampTime = dampArg;
- if (m_dampTime < 0) m_dampTime = 0;
+ m_posDampTime = dampArg;
+ if (m_posDampTime < 0) m_posDampTime = 0;
Py_Return;
}
/* 3. getDamp */
-char KX_ConstraintActuator::GetDamp_doc[] =
-"GetDamp()\n"
+const char KX_ConstraintActuator::GetDamp_doc[] =
+"getDamp()\n"
+"\tReturns the damping parameter.\n";
+PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self){
+ return PyInt_FromLong(m_posDampTime);
+}
+
+/* 2. setRotDamp */
+const char KX_ConstraintActuator::SetRotDamp_doc[] =
+"setRotDamp(duration)\n"
+"\t- duration: integer\n"
+"\tSets the time constant of the orientation constraint.\n"
+"\tIf the duration is negative, it is set to 0.\n";
+PyObject* KX_ConstraintActuator::PySetRotDamp(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int dampArg;
+ if(!PyArg_ParseTuple(args, "i", &dampArg)) {
+ return NULL;
+ }
+
+ m_rotDampTime = dampArg;
+ if (m_rotDampTime < 0) m_rotDampTime = 0;
+
+ Py_Return;
+}
+/* 3. getRotDamp */
+const char KX_ConstraintActuator::GetRotDamp_doc[] =
+"getRotDamp()\n"
"\tReturns the damping time for application of the constraint.\n";
-PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self,
+PyObject* KX_ConstraintActuator::PyGetRotDamp(PyObject* self){
+ return PyInt_FromLong(m_rotDampTime);
+}
+
+/* 2. setDirection */
+const char KX_ConstraintActuator::SetDirection_doc[] =
+"setDirection(vector)\n"
+"\t- vector: 3-tuple\n"
+"\tSets the reference direction in world coordinate for the orientation constraint.\n";
+PyObject* KX_ConstraintActuator::PySetDirection(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float x, y, z;
+ MT_Scalar len;
+ MT_Vector3 dir;
+
+ if(!PyArg_ParseTuple(args, "(fff)", &x, &y, &z)) {
+ return NULL;
+ }
+ dir[0] = x;
+ dir[1] = y;
+ dir[2] = z;
+ len = dir.length();
+ if (MT_fuzzyZero(len)) {
+ std::cout << "Invalid direction" << std::endl;
+ return NULL;
+ }
+ m_refDirection = dir/len;
+
+ Py_Return;
+}
+/* 3. getDirection */
+const char KX_ConstraintActuator::GetDirection_doc[] =
+"getDirection()\n"
+"\tReturns the reference direction of the orientation constraint as a 3-tuple.\n";
+PyObject* KX_ConstraintActuator::PyGetDirection(PyObject* self){
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_refDirection[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_refDirection[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_refDirection[2]));
+ return retVal;
+}
+
+/* 2. setOption */
+const char KX_ConstraintActuator::SetOption_doc[] =
+"setOption(option)\n"
+"\t- option: integer\n"
+"\tSets several options of the distance constraint.\n"
+"\tBinary combination of the following values:\n"
+"\t\t 64 : Activate alignment to surface\n"
+"\t\t128 : Detect material rather than property\n"
+"\t\t256 : No deactivation if ray does not hit target\n"
+"\t\t512 : Activate distance control\n";
+PyObject* KX_ConstraintActuator::PySetOption(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int option;
+ if(!PyArg_ParseTuple(args, "i", &option)) {
+ return NULL;
+ }
+
+ m_option = option;
+
+ Py_Return;
+}
+/* 3. getOption */
+const char KX_ConstraintActuator::GetOption_doc[] =
+"getOption()\n"
+"\tReturns the option parameter.\n";
+PyObject* KX_ConstraintActuator::PyGetOption(PyObject* self){
+ return PyInt_FromLong(m_option);
+}
+
+/* 2. setTime */
+const char KX_ConstraintActuator::SetTime_doc[] =
+"setTime(duration)\n"
+"\t- duration: integer\n"
+"\tSets the activation time of the actuator.\n"
+"\tThe actuator disables itself after this many frame.\n"
+"\tIf set to 0 or negative, the actuator is not limited in time.\n";
+PyObject* KX_ConstraintActuator::PySetTime(PyObject* self,
PyObject* args,
- PyObject* kwds){
- return PyInt_FromLong(m_dampTime);
+ PyObject* kwds) {
+ int t;
+ if(!PyArg_ParseTuple(args, "i", &t)) {
+ return NULL;
+ }
+
+ if (t < 0)
+ t = 0;
+ m_activeTime = t;
+
+ Py_Return;
+}
+/* 3. getTime */
+const char KX_ConstraintActuator::GetTime_doc[] =
+"getTime()\n"
+"\tReturns the time parameter.\n";
+PyObject* KX_ConstraintActuator::PyGetTime(PyObject* self){
+ return PyInt_FromLong(m_activeTime);
}
+/* 2. setProperty */
+const char KX_ConstraintActuator::SetProperty_doc[] =
+"setProperty(property)\n"
+"\t- property: string\n"
+"\tSets the name of the property or material for the ray detection of the distance constraint.\n"
+"\tIf empty, the ray will detect any collisioning object.\n";
+PyObject* KX_ConstraintActuator::PySetProperty(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ char *property;
+ if (!PyArg_ParseTuple(args, "s", &property)) {
+ return NULL;
+ }
+ if (property == NULL) {
+ m_property[0] = 0;
+ } else {
+ strncpy(m_property, property, sizeof(m_property));
+ m_property[sizeof(m_property)-1] = 0;
+ }
+
+ Py_Return;
+}
+/* 3. getProperty */
+const char KX_ConstraintActuator::GetProperty_doc[] =
+"getProperty()\n"
+"\tReturns the property parameter.\n";
+PyObject* KX_ConstraintActuator::PyGetProperty(PyObject* self){
+ return PyString_FromString(m_property);
+}
+
+/* 4. setDistance */
+const char KX_ConstraintActuator::SetDistance_doc[] =
+"setDistance(distance)\n"
+"\t- distance: float\n"
+"\tSets the target distance in distance constraint\n";
/* 4. setMin */
-char KX_ConstraintActuator::SetMin_doc[] =
+const char KX_ConstraintActuator::SetMin_doc[] =
"setMin(lower_bound)\n"
"\t- lower_bound: float\n"
"\tSets the lower value of the interval to which the value\n"
@@ -271,9 +819,7 @@ PyObject* KX_ConstraintActuator::PySetMin(PyObject* self,
}
switch (m_locrot) {
- case KX_ACT_CONSTRAINT_LOCX:
- case KX_ACT_CONSTRAINT_LOCY:
- case KX_ACT_CONSTRAINT_LOCZ:
+ default:
m_minimumBound = minArg;
break;
case KX_ACT_CONSTRAINT_ROTX:
@@ -281,25 +827,30 @@ PyObject* KX_ConstraintActuator::PySetMin(PyObject* self,
case KX_ACT_CONSTRAINT_ROTZ:
m_minimumBound = MT_radians(minArg);
break;
- default:
- ; /* error */
}
Py_Return;
}
+/* 5. getDistance */
+const char KX_ConstraintActuator::GetDistance_doc[] =
+"getDistance()\n"
+"\tReturns the distance parameter \n";
/* 5. getMin */
-char KX_ConstraintActuator::GetMin_doc[] =
+const char KX_ConstraintActuator::GetMin_doc[] =
"getMin()\n"
"\tReturns the lower value of the interval to which the value\n"
"\tis clipped.\n";
-PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self) {
return PyFloat_FromDouble(m_minimumBound);
}
+/* 6. setRayLength */
+const char KX_ConstraintActuator::SetRayLength_doc[] =
+"setRayLength(length)\n"
+"\t- length: float\n"
+"\tSets the maximum ray length of the distance constraint\n";
/* 6. setMax */
-char KX_ConstraintActuator::SetMax_doc[] =
+const char KX_ConstraintActuator::SetMax_doc[] =
"setMax(upper_bound)\n"
"\t- upper_bound: float\n"
"\tSets the upper value of the interval to which the value\n"
@@ -313,9 +864,7 @@ PyObject* KX_ConstraintActuator::PySetMax(PyObject* self,
}
switch (m_locrot) {
- case KX_ACT_CONSTRAINT_LOCX:
- case KX_ACT_CONSTRAINT_LOCY:
- case KX_ACT_CONSTRAINT_LOCZ:
+ default:
m_maximumBound = maxArg;
break;
case KX_ACT_CONSTRAINT_ROTX:
@@ -323,31 +872,41 @@ PyObject* KX_ConstraintActuator::PySetMax(PyObject* self,
case KX_ACT_CONSTRAINT_ROTZ:
m_maximumBound = MT_radians(maxArg);
break;
- default:
- ; /* error */
}
Py_Return;
}
+/* 7. getRayLength */
+const char KX_ConstraintActuator::GetRayLength_doc[] =
+"getRayLength()\n"
+"\tReturns the length of the ray\n";
/* 7. getMax */
-char KX_ConstraintActuator::GetMax_doc[] =
+const char KX_ConstraintActuator::GetMax_doc[] =
"getMax()\n"
"\tReturns the upper value of the interval to which the value\n"
"\tis clipped.\n";
-PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self) {
return PyFloat_FromDouble(m_maximumBound);
}
/* This setter/getter probably for the constraint type */
/* 8. setLimit */
-char KX_ConstraintActuator::SetLimit_doc[] =
+const char KX_ConstraintActuator::SetLimit_doc[] =
"setLimit(type)\n"
-"\t- type: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY,\n"
-"\t KX_CONSTRAINTACT_LOCZ, KX_CONSTRAINTACT_ROTX,\n"
-"\t KX_CONSTRAINTACT_ROTY, or KX_CONSTRAINTACT_ROTZ.\n"
+"\t- type: integer\n"
+"\t 1 : LocX\n"
+"\t 2 : LocY\n"
+"\t 3 : LocZ\n"
+"\t 7 : Distance along +X axis\n"
+"\t 8 : Distance along +Y axis\n"
+"\t 9 : Distance along +Z axis\n"
+"\t 10 : Distance along -X axis\n"
+"\t 11 : Distance along -Y axis\n"
+"\t 12 : Distance along -Z axis\n"
+"\t 13 : Align X axis\n"
+"\t 14 : Align Y axis\n"
+"\t 15 : Align Z axis\n"
"\tSets the type of constraint.\n";
PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self,
PyObject* args,
@@ -362,12 +921,10 @@ PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self,
Py_Return;
}
/* 9. getLimit */
-char KX_ConstraintActuator::GetLimit_doc[] =
-"getLimit(type)\n"
+const char KX_ConstraintActuator::GetLimit_doc[] =
+"getLimit()\n"
"\tReturns the type of constraint.\n";
-PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self) {
return PyInt_FromLong(m_locrot);
}
diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.h b/source/gameengine/Ketsji/KX_ConstraintActuator.h
index a21a5f30de6..28b9b1e6a0b 100644
--- a/source/gameengine/Ketsji/KX_ConstraintActuator.h
+++ b/source/gameengine/Ketsji/KX_ConstraintActuator.h
@@ -34,19 +34,40 @@
#include "SCA_IActuator.h"
#include "MT_Scalar.h"
+#include "MT_Vector3.h"
+#include "KX_ClientObjectInfo.h"
+
+class KX_RayCast;
+class KX_GameObject;
class KX_ConstraintActuator : public SCA_IActuator
{
Py_Header;
protected:
// Damp time (int),
- int m_dampTime;
- // min (float),
+ int m_posDampTime;
+ int m_rotDampTime;
+ // min (float)
float m_minimumBound;
- // max (float),
+ // max (float)
float m_maximumBound;
+ // sinus of minimum angle
+ float m_minimumSine;
+ // sinus of maximum angle
+ float m_maximumSine;
+ // reference direction
+ MT_Vector3 m_refDirection;
// locrotxyz choice (pick one): only one choice allowed at a time!
int m_locrot;
+ // active time of actuator
+ int m_activeTime;
+ int m_currentTime;
+ // option
+ int m_option;
+ // property to check
+ char m_property[32];
+ // hit object
+ KX_GameObject* m_hitObject;
/**
* Clamp <var> to <min>, <max>. Borders are included (in as far as
@@ -56,6 +77,7 @@ protected:
public:
+ // m_locrot
enum KX_CONSTRAINTTYPE {
KX_ACT_CONSTRAINT_NODEF = 0,
KX_ACT_CONSTRAINT_LOCX,
@@ -64,16 +86,46 @@ protected:
KX_ACT_CONSTRAINT_ROTX,
KX_ACT_CONSTRAINT_ROTY,
KX_ACT_CONSTRAINT_ROTZ,
+ KX_ACT_CONSTRAINT_DIRPX,
+ KX_ACT_CONSTRAINT_DIRPY,
+ KX_ACT_CONSTRAINT_DIRPZ,
+ KX_ACT_CONSTRAINT_DIRNX,
+ KX_ACT_CONSTRAINT_DIRNY,
+ KX_ACT_CONSTRAINT_DIRNZ,
+ KX_ACT_CONSTRAINT_ORIX,
+ KX_ACT_CONSTRAINT_ORIY,
+ KX_ACT_CONSTRAINT_ORIZ,
+ KX_ACT_CONSTRAINT_FHPX,
+ KX_ACT_CONSTRAINT_FHPY,
+ KX_ACT_CONSTRAINT_FHPZ,
+ KX_ACT_CONSTRAINT_FHNX,
+ KX_ACT_CONSTRAINT_FHNY,
+ KX_ACT_CONSTRAINT_FHNZ,
KX_ACT_CONSTRAINT_MAX
};
-
+ // match ACT_CONST_... values from BIF_interface.h
+ enum KX_CONSTRAINTOPT {
+ KX_ACT_CONSTRAINT_NORMAL = 64,
+ KX_ACT_CONSTRAINT_MATERIAL = 128,
+ KX_ACT_CONSTRAINT_PERMANENT = 256,
+ KX_ACT_CONSTRAINT_DISTANCE = 512,
+ KX_ACT_CONSTRAINT_LOCAL = 1024,
+ KX_ACT_CONSTRAINT_DOROTFH = 2048
+ };
bool IsValidMode(KX_CONSTRAINTTYPE m);
+ bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
+ bool NeedRayCast(KX_ClientObjectInfo*);
KX_ConstraintActuator(SCA_IObject* gameobj,
- int damptime,
+ int posDamptime,
+ int rotDampTime,
float min,
float max,
+ float refDir[3],
int locrot,
+ int time,
+ int option,
+ char *property,
PyTypeObject* T=&Type);
virtual ~KX_ConstraintActuator();
virtual CValue* GetReplica() {
@@ -93,14 +145,27 @@ protected:
virtual PyObject* _getattr(const STR_String& attr);
KX_PYMETHOD_DOC(KX_ConstraintActuator,SetDamp);
- KX_PYMETHOD_DOC(KX_ConstraintActuator,GetDamp);
+ KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetDamp);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetRotDamp);
+ KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetRotDamp);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetDirection);
+ KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetDirection);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetOption);
+ KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetOption);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetTime);
+ KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetTime);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetProperty);
+ KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetProperty);
KX_PYMETHOD_DOC(KX_ConstraintActuator,SetMin);
- KX_PYMETHOD_DOC(KX_ConstraintActuator,GetMin);
+ KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetMin);
+ static const char SetDistance_doc[];
+ static const char GetDistance_doc[];
KX_PYMETHOD_DOC(KX_ConstraintActuator,SetMax);
- KX_PYMETHOD_DOC(KX_ConstraintActuator,GetMax);
+ KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetMax);
+ static const char SetRayLength_doc[];
+ static const char GetRayLength_doc[];
KX_PYMETHOD_DOC(KX_ConstraintActuator,SetLimit);
- KX_PYMETHOD_DOC(KX_ConstraintActuator,GetLimit);
-
+ KX_PYMETHOD_DOC_NOARGS(KX_ConstraintActuator,GetLimit);
};
#endif //__KX_CONSTRAINTACTUATOR
diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp
index 987125ca9ba..c9095ff34f6 100644
--- a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp
+++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp
@@ -27,6 +27,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
+#include "PyObjectPlus.h"
#include "KX_ConstraintWrapper.h"
#include "PHY_IPhysicsEnvironment.h"
@@ -53,8 +54,7 @@ PyObject* KX_ConstraintWrapper::PyTestMethod(PyObject* self,
PyObject* kwds)
{
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
PyObject* KX_ConstraintWrapper::PyGetConstraintId(PyObject* self,
diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h b/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h
index 6653026f28a..53486cecf73 100644
--- a/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h
+++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObject.h
@@ -75,6 +75,7 @@ struct KX_CBounds
struct KX_ObjectProperties
{
bool m_dyna;
+ bool m_softbody;
double m_radius;
bool m_angular_rigidbody;
bool m_in_active_layer;
@@ -86,6 +87,47 @@ struct KX_ObjectProperties
bool m_disableSleeping;
bool m_hasCompoundChildren;
bool m_isCompoundChild;
+
+ /////////////////////////
+
+ int m_gamesoftFlag;
+ float m_soft_linStiff; /* linear stiffness 0..1 */
+ float m_soft_angStiff; /* angular stiffness 0..1 */
+ float m_soft_volume; /* volume preservation 0..1 */
+
+ int m_soft_viterations; /* Velocities solver iterations */
+ int m_soft_piterations; /* Positions solver iterations */
+ int m_soft_diterations; /* Drift solver iterations */
+ int m_soft_citerations; /* Cluster solver iterations */
+
+ float m_soft_kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */
+ float m_soft_kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */
+ float m_soft_kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */
+ float m_soft_kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
+
+ float m_soft_kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
+ float m_soft_kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
+ float m_soft_kVCF; /* Velocities correction factor (Baumgarte) */
+ float m_soft_kDP; /* Damping coefficient [0,1] */
+
+ float m_soft_kDG; /* Drag coefficient [0,+inf] */
+ float m_soft_kLF; /* Lift coefficient [0,+inf] */
+ float m_soft_kPR; /* Pressure coefficient [-inf,+inf] */
+ float m_soft_kVC; /* Volume conversation coefficient [0,+inf] */
+
+ float m_soft_kDF; /* Dynamic friction coefficient [0,1] */
+ float m_soft_kMT; /* Pose matching coefficient [0,1] */
+ float m_soft_kCHR; /* Rigid contacts hardness [0,1] */
+ float m_soft_kKHR; /* Kinetic contacts hardness [0,1] */
+
+ float m_soft_kSHR; /* Soft contacts hardness [0,1] */
+ float m_soft_kAHR; /* Anchors hardness [0,1] */
+ int m_soft_collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */
+ int m_soft_numclusteriterations; /* number of iterations to refine collision clusters*/
+
+ /////////////////////////
+
+ double m_margin;
KX_BoundBoxClass m_boundclass;
union {
KX_BoxBounds box;
diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp
index 26e0b47b84b..0e7a6d92ec1 100644
--- a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp
+++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp
@@ -38,6 +38,8 @@
#include "RAS_MeshObject.h"
#include "KX_Scene.h"
#include "SYS_System.h"
+#include "BL_SkinMeshObject.h"
+#include "BulletSoftBody/btSoftBody.h"
#include "PHY_Pro.h" //todo cleanup
#include "KX_ClientObjectInfo.h"
@@ -76,16 +78,16 @@
struct KX_PhysicsInstance
{
DT_VertexBaseHandle m_vertexbase;
- int m_vtxarray;
+ RAS_DisplayArray* m_darray;
RAS_IPolyMaterial* m_material;
-
- KX_PhysicsInstance(DT_VertexBaseHandle vertex_base, int vtxarray, RAS_IPolyMaterial* mat)
+
+ KX_PhysicsInstance(DT_VertexBaseHandle vertex_base, RAS_DisplayArray *darray, RAS_IPolyMaterial* mat)
: m_vertexbase(vertex_base),
- m_vtxarray(vtxarray),
- m_material(mat)
+ m_darray(darray),
+ m_material(mat)
{
}
-
+
~KX_PhysicsInstance()
{
DT_DeleteVertexBase(m_vertexbase);
@@ -100,11 +102,11 @@ static void BL_RegisterSumoObject(KX_GameObject* gameobj,class SM_Scene* sumoSce
static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope);
void KX_ConvertSumoObject( KX_GameObject* gameobj,
- RAS_MeshObject* meshobj,
- KX_Scene* kxscene,
- PHY_ShapeProps* kxshapeprops,
- PHY_MaterialProps* kxmaterial,
- struct KX_ObjectProperties* objprop)
+ RAS_MeshObject* meshobj,
+ KX_Scene* kxscene,
+ PHY_ShapeProps* kxshapeprops,
+ PHY_MaterialProps* kxmaterial,
+ struct KX_ObjectProperties* objprop)
{
@@ -150,23 +152,23 @@ void KX_ConvertSumoObject( KX_GameObject* gameobj,
objprop->m_boundobject.box.m_extends[1],
objprop->m_boundobject.box.m_extends[2]);
smprop->m_inertia.scale(objprop->m_boundobject.box.m_extends[0]*objprop->m_boundobject.box.m_extends[0],
- objprop->m_boundobject.box.m_extends[1]*objprop->m_boundobject.box.m_extends[1],
- objprop->m_boundobject.box.m_extends[2]*objprop->m_boundobject.box.m_extends[2]);
+ objprop->m_boundobject.box.m_extends[1]*objprop->m_boundobject.box.m_extends[1],
+ objprop->m_boundobject.box.m_extends[2]*objprop->m_boundobject.box.m_extends[2]);
smprop->m_inertia *= smprop->m_mass/MT_Vector3(objprop->m_boundobject.box.m_extends).length();
break;
case KX_BOUNDCYLINDER:
shape = DT_NewCylinder(smprop->m_radius, objprop->m_boundobject.c.m_height);
smprop->m_inertia.scale(smprop->m_mass*smprop->m_radius*smprop->m_radius,
- smprop->m_mass*smprop->m_radius*smprop->m_radius,
- smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height);
+ smprop->m_mass*smprop->m_radius*smprop->m_radius,
+ smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height);
break;
case KX_BOUNDCONE:
shape = DT_NewCone(objprop->m_radius, objprop->m_boundobject.c.m_height);
smprop->m_inertia.scale(smprop->m_mass*smprop->m_radius*smprop->m_radius,
- smprop->m_mass*smprop->m_radius*smprop->m_radius,
- smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height);
+ smprop->m_mass*smprop->m_radius*smprop->m_radius,
+ smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height);
break;
- /* Dynamic mesh objects. WARNING! slow. */
+ /* Dynamic mesh objects. WARNING! slow. */
case KX_BOUNDPOLYTOPE:
polytope = true;
// fall through
@@ -186,15 +188,15 @@ void KX_ConvertSumoObject( KX_GameObject* gameobj,
shape = DT_NewSphere(objprop->m_radius);
smprop->m_inertia *= smprop->m_mass*smprop->m_radius*smprop->m_radius;
break;
-
+
}
-
+
sumoObj = new SM_Object(shape, !objprop->m_ghost?smmaterial:NULL,smprop,NULL);
-
+
sumoObj->setRigidBody(objprop->m_angular_rigidbody?true:false);
-
+
BL_RegisterSumoObject(gameobj,sceneptr,sumoObj,"",true, true);
-
+
}
else {
// non physics object
@@ -320,12 +322,11 @@ static void BL_RegisterSumoObject(
physicscontroller->SetObject(gameobj->GetSGNode());
}
-static DT_ShapeHandle InstancePhysicsComplex(RAS_MeshObject* meshobj, int vtxarray, RAS_IPolyMaterial *mat)
+static DT_ShapeHandle InstancePhysicsComplex(RAS_MeshObject* meshobj, RAS_DisplayArray *darray, RAS_IPolyMaterial *mat)
{
// instance a mesh from a single vertex array & material
- const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(mat)[vtxarray])[0]);
- //const KX_IndexArray &index_array = *meshobj->GetIndexCache(mat)[vtxarray];
- DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getLocalXYZ(), sizeof(RAS_TexVert));
+ const RAS_TexVert *vertex_array = &darray->m_vertex[0];
+ DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getXYZ(), sizeof(RAS_TexVert));
DT_ShapeHandle shape = DT_NewComplexShape(vertex_base);
@@ -337,15 +338,19 @@ static DT_ShapeHandle InstancePhysicsComplex(RAS_MeshObject* meshobj, int vtxarr
// only add polygons that have the collisionflag set
if (poly->IsCollider())
{
- DT_VertexIndices(3, poly->GetVertexIndexBase().m_indexarray);
+ DT_Begin();
+ DT_VertexIndex(poly->GetVertexOffset(0));
+ DT_VertexIndex(poly->GetVertexOffset(1));
+ DT_VertexIndex(poly->GetVertexOffset(2));
+ DT_End();
// tesselate
if (poly->VertexCount() == 4)
{
DT_Begin();
- DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[0]);
- DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[2]);
- DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[3]);
+ DT_VertexIndex(poly->GetVertexOffset(0));
+ DT_VertexIndex(poly->GetVertexOffset(2));
+ DT_VertexIndex(poly->GetVertexOffset(3));
DT_End();
}
}
@@ -354,16 +359,15 @@ static DT_ShapeHandle InstancePhysicsComplex(RAS_MeshObject* meshobj, int vtxarr
//DT_VertexIndices(indices.size(), &indices[0]);
DT_EndComplexShape();
- map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, vtxarray, mat));
+ map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, darray, mat));
return shape;
}
-static DT_ShapeHandle InstancePhysicsPolytope(RAS_MeshObject* meshobj, int vtxarray, RAS_IPolyMaterial *mat)
+static DT_ShapeHandle InstancePhysicsPolytope(RAS_MeshObject* meshobj, RAS_DisplayArray *darray, RAS_IPolyMaterial *mat)
{
// instance a mesh from a single vertex array & material
- const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(mat)[vtxarray])[0]);
- //const KX_IndexArray &index_array = *meshobj->GetIndexCache(mat)[vtxarray];
- DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getLocalXYZ(), sizeof(RAS_TexVert));
+ const RAS_TexVert *vertex_array = &darray->m_vertex[0];
+ DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getXYZ(), sizeof(RAS_TexVert));
std::vector<DT_Index> indices;
for (int p = 0; p < meshobj->NumPolygons(); p++)
@@ -373,12 +377,12 @@ static DT_ShapeHandle InstancePhysicsPolytope(RAS_MeshObject* meshobj, int vtxar
// only add polygons that have the collisionflag set
if (poly->IsCollider())
{
- indices.push_back(poly->GetVertexIndexBase().m_indexarray[0]);
- indices.push_back(poly->GetVertexIndexBase().m_indexarray[1]);
- indices.push_back(poly->GetVertexIndexBase().m_indexarray[2]);
+ indices.push_back(poly->GetVertexOffset(0));
+ indices.push_back(poly->GetVertexOffset(1));
+ indices.push_back(poly->GetVertexOffset(2));
if (poly->VertexCount() == 4)
- indices.push_back(poly->GetVertexIndexBase().m_indexarray[3]);
+ indices.push_back(poly->GetVertexOffset(3));
}
}
@@ -386,7 +390,7 @@ static DT_ShapeHandle InstancePhysicsPolytope(RAS_MeshObject* meshobj, int vtxar
DT_VertexIndices(indices.size(), &indices[0]);
DT_EndPolytope();
- map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, vtxarray, mat));
+ map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, darray, mat));
return shape;
}
@@ -398,8 +402,8 @@ bool KX_ReInstanceShapeFromMesh(RAS_MeshObject* meshobj)
KX_PhysicsInstance *instance = *map_gamemesh_to_instance[GEN_HashedPtr(meshobj)];
if (instance)
{
- const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(instance->m_material)[instance->m_vtxarray])[0]);
- DT_ChangeVertexBase(instance->m_vertexbase, vertex_array[0].getLocalXYZ());
+ const RAS_TexVert *vertex_array = &instance->m_darray->m_vertex[0];
+ DT_ChangeVertexBase(instance->m_vertexbase, vertex_array[0].getXYZ());
return true;
}
return false;
@@ -425,7 +429,7 @@ static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope
// Count the number of collision polygons and check they all come from the same
// vertex array
int numvalidpolys = 0;
- int vtxarray = -1;
+ RAS_DisplayArray *darray = NULL;
RAS_IPolyMaterial *poly_material = NULL;
bool reinstance = true;
@@ -437,14 +441,14 @@ static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope
if (poly->IsCollider())
{
// check polygon is from the same vertex array
- if (poly->GetVertexIndexBase().m_vtxarray != vtxarray)
+ if (poly->GetDisplayArray() != darray)
{
- if (vtxarray < 0)
- vtxarray = poly->GetVertexIndexBase().m_vtxarray;
+ if (darray == NULL)
+ darray = poly->GetDisplayArray();
else
{
reinstance = false;
- vtxarray = -1;
+ darray = NULL;
}
}
@@ -478,9 +482,9 @@ static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope
if (reinstance)
{
if (polytope)
- shape = InstancePhysicsPolytope(meshobj, vtxarray, poly_material);
+ shape = InstancePhysicsPolytope(meshobj, darray, poly_material);
else
- shape = InstancePhysicsComplex(meshobj, vtxarray, poly_material);
+ shape = InstancePhysicsComplex(meshobj, darray, poly_material);
}
else
{
@@ -489,7 +493,7 @@ static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope
std::cout << "CreateShapeFromMesh: " << meshobj->GetName() << " is not suitable for polytope." << std::endl;
if (!poly_material)
std::cout << " Check mesh materials." << std::endl;
- if (vtxarray < 0)
+ if (darray == NULL)
std::cout << " Check number of vertices." << std::endl;
}
@@ -505,18 +509,10 @@ static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope
if (poly->IsCollider())
{ /* We have to tesselate here because SOLID can only raycast triangles */
DT_Begin();
- /* V1 */
- DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[2],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
- /* V2 */
- DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[1],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
- /* V3 */
- DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[0],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
+ /* V1, V2, V3 */
+ DT_Vertex(poly->GetVertex(2)->getXYZ());
+ DT_Vertex(poly->GetVertex(1)->getXYZ());
+ DT_Vertex(poly->GetVertex(0)->getXYZ());
numvalidpolys++;
DT_End();
@@ -524,18 +520,10 @@ static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope
if (poly->VertexCount() == 4)
{
DT_Begin();
- /* V1 */
- DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[3],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
- /* V3 */
- DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[2],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
- /* V4 */
- DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[0],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
+ /* V1, V3, V4 */
+ DT_Vertex(poly->GetVertex(3)->getXYZ());
+ DT_Vertex(poly->GetVertex(2)->getXYZ());
+ DT_Vertex(poly->GetVertex(0)->getXYZ());
numvalidpolys++;
DT_End();
@@ -679,196 +667,107 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj,
#endif //WIN32
-static GEN_Map<GEN_HashedPtr,btCollisionShape*> map_gamemesh_to_bulletshape;
-
-// forward declarations
-static btCollisionShape* CreateBulletShapeFromMesh(RAS_MeshObject* meshobj, bool polytope)
-{
- if (!meshobj)
- return 0;
-
- btCollisionShape* collisionMeshShape = 0;
- btConvexHullShape* convexHullShape = 0;
- btTriangleMeshShape* concaveShape = 0;
-
- btTriangleMesh* collisionMeshData = 0;
-
- //see if there is any polygons, if not, bail out.
-
- int numPoints = 0;
- btVector3* points = 0;
-
- btCollisionShape** shapeptr = map_gamemesh_to_bulletshape[GEN_HashedPtr(meshobj)];
-
- // Mesh has already been converted: reuse
- if (shapeptr)
- {
- //return *shapeptr;
- }
-
- // Mesh has no polygons!
- int numpolys = meshobj->NumPolygons();
- if (!numpolys)
- {
- return NULL;
- }
-
- // Count the number of collision polygons and check they all come from the same
- // vertex array
- int numvalidpolys = 0;
- int vtxarray = -1;
- RAS_IPolyMaterial *poly_material = NULL;
- bool reinstance = true;
-
- for (int p=0; p<numpolys; p++)
+
+ class KX_SoftBodyDeformer : public RAS_Deformer
{
- RAS_Polygon* poly = meshobj->GetPolygon(p);
+ class RAS_MeshObject* m_pMeshObject;
+ class KX_GameObject* m_gameobj;
- // only add polygons that have the collisionflag set
- if (poly->IsCollider())
+ public:
+ KX_SoftBodyDeformer(RAS_MeshObject* pMeshObject,KX_GameObject* gameobj)
+ :m_pMeshObject(pMeshObject),
+ m_gameobj(gameobj)
{
- // check polygon is from the same vertex array
- if (poly->GetVertexIndexBase().m_vtxarray != vtxarray)
- {
- if (vtxarray < 0)
- vtxarray = poly->GetVertexIndexBase().m_vtxarray;
- else
- {
- reinstance = false;
- vtxarray = -1;
- }
- }
-
- // check poly is from the same material
- if (poly->GetMaterial()->GetPolyMaterial() != poly_material)
- {
- if (poly_material)
- {
- reinstance = false;
- poly_material = NULL;
- }
- else
- poly_material = poly->GetMaterial()->GetPolyMaterial();
- }
-
- // count the number of collision polys
- numvalidpolys++;
+ //printf("KX_SoftBodyDeformer\n");
+ };
- // We have one collision poly, and we can't reinstance, so we
- // might as well break here.
- if (!reinstance)
- break;
+ virtual ~KX_SoftBodyDeformer()
+ {
+ //printf("~KX_SoftBodyDeformer\n");
+ };
+ virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map)
+ {
+ //printf("relink\n");
}
- }
-
- // No collision polygons
- if (numvalidpolys < 1)
- return NULL;
+ virtual bool Apply(class RAS_IPolyMaterial *polymat)
+ {
+ KX_BulletPhysicsController* ctrl = (KX_BulletPhysicsController*) m_gameobj->GetPhysicsController();
+ if (!ctrl)
+ return false;
+ btSoftBody* softBody= ctrl->GetSoftBody();
+ if (!softBody)
+ return false;
- if (polytope)
- {
- convexHullShape = new btConvexHullShape(&points[0].getX(),numPoints);
- collisionMeshShape = convexHullShape;
- } else
- {
- collisionMeshData = new btTriangleMesh();
-// concaveShape = new btTriangleMeshShape(collisionMeshData);
- //collisionMeshShape = concaveShape;
+ //printf("apply\n");
+ RAS_MeshSlot::iterator it;
+ RAS_MeshMaterial *mmat;
+ RAS_MeshSlot *slot;
+ size_t i;
- }
+ // update the vertex in m_transverts
+ Update();
- numvalidpolys = 0;
- for (int p2=0; p2<numpolys; p2++)
- {
- RAS_Polygon* poly = meshobj->GetPolygon(p2);
+ // The vertex cache can only be updated for this deformer:
+ // Duplicated objects with more than one ploymaterial (=multiple mesh slot per object)
+ // share the same mesh (=the same cache). As the rendering is done per polymaterial
+ // cycling through the objects, the entire mesh cache cannot be updated in one shot.
+ mmat = m_pMeshObject->GetMeshMaterial(polymat);
+ if(!mmat->m_slots[(void*)m_gameobj])
+ return true;
- // only add polygons that have the collisionflag set
- if (poly->IsCollider())
- {
- //Bullet can raycast any shape, so
- if (polytope)
- {
- for (int i=0;i<poly->VertexCount();i++)
- {
- const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[i],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
- btPoint3 point(vtx[0],vtx[1],vtx[2]);
- convexHullShape->addPoint(point);
- }
- if (poly->VertexCount())
- numvalidpolys++;
+ slot = *mmat->m_slots[(void*)m_gameobj];
- } else
+ // for each array
+ for(slot->begin(it); !slot->end(it); slot->next(it))
{
- {
- const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[2],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
- btPoint3 vertex0(vtx[0],vtx[1],vtx[2]);
- vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[1],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
- btPoint3 vertex1(vtx[0],vtx[1],vtx[2]);
- vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[0],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
- btPoint3 vertex2(vtx[0],vtx[1],vtx[2]);
- collisionMeshData->addTriangle(vertex0,vertex1,vertex2);
- numvalidpolys++;
- }
- if (poly->VertexCount() == 4)
- {
- const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[3],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
- btPoint3 vertex0(vtx[0],vtx[1],vtx[2]);
- vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[2],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
- btPoint3 vertex1(vtx[0],vtx[1],vtx[2]);
- vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray,
- poly->GetVertexIndexBase().m_indexarray[0],
- poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
- btPoint3 vertex2(vtx[0],vtx[1],vtx[2]);
- collisionMeshData->addTriangle(vertex0,vertex1,vertex2);
- numvalidpolys++;
- }
+ btSoftBody::tNodeArray& nodes(softBody->m_nodes);
- }
- }
- }
+ int index = 0;
+ for(i=it.startvertex; i<it.endvertex; i++,index++) {
+ RAS_TexVert& v = it.vertex[i];
+ btAssert(v.getSoftBodyIndex() >= 0);
+ MT_Point3 pt (
+ nodes[v.getSoftBodyIndex()].m_x.getX(),
+ nodes[v.getSoftBodyIndex()].m_x.getY(),
+ nodes[v.getSoftBodyIndex()].m_x.getZ());
+ v.SetXYZ(pt);
+ MT_Vector3 normal (
+ nodes[v.getSoftBodyIndex()].m_n.getX(),
+ nodes[v.getSoftBodyIndex()].m_n.getY(),
+ nodes[v.getSoftBodyIndex()].m_n.getZ());
+ v.SetNormal(normal);
- if (numvalidpolys > 0)
- {
-
- //map_gamemesh_to_bulletshape.insert(GEN_HashedPtr(meshobj),collisionMeshShape);
- if (!polytope)
+ }
+ }
+ return true;
+ }
+ virtual bool Update(void)
{
- bool useQuantization = true;
- concaveShape = new btBvhTriangleMeshShape( collisionMeshData, useQuantization );
- //concaveShape = new btTriangleMeshShape( collisionMeshData );
-
- concaveShape->recalcLocalAabb();
- collisionMeshShape = concaveShape;
-
- }
-
-
+ //printf("update\n");
+ return true;//??
+ }
+ virtual RAS_Deformer *GetReplica(class KX_GameObject* replica)
+ {
+ KX_SoftBodyDeformer* deformer = new KX_SoftBodyDeformer(replica->GetMesh(0),replica);
+ return deformer;
+ }
- return collisionMeshShape;
- }
+ virtual bool SkipVertexTransform()
+ {
+ return true;
+ }
- delete collisionMeshShape;
- return NULL;
+ protected:
+ //class RAS_MeshObject *m_pMesh;
+ };
-}
+// forward declarations
void KX_ConvertBulletObject( class KX_GameObject* gameobj,
class RAS_MeshObject* meshobj,
@@ -885,6 +784,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
bool isbulletdyna = false;
CcdConstructionInfo ci;
class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
+ class CcdShapeConstructionInfo *shapeInfo = new CcdShapeConstructionInfo();
@@ -892,125 +792,108 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
{
ci.m_collisionFlags |= btCollisionObject::CF_STATIC_OBJECT;
}
+ if (objprop->m_ghost)
+ {
+ ci.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE;
+ }
ci.m_MotionState = motionstate;
ci.m_gravity = btVector3(0,0,0);
ci.m_localInertiaTensor =btVector3(0,0,0);
ci.m_mass = objprop->m_dyna ? shapeprops->m_mass : 0.f;
+ ci.m_margin = objprop->m_margin;
+ shapeInfo->m_radius = objprop->m_radius;
isbulletdyna = objprop->m_dyna;
ci.m_localInertiaTensor = btVector3(ci.m_mass/3.f,ci.m_mass/3.f,ci.m_mass/3.f);
- btTransform trans;
- trans.setIdentity();
-
btCollisionShape* bm = 0;
switch (objprop->m_boundclass)
{
case KX_BOUNDSPHERE:
{
- float radius = objprop->m_radius;
- btVector3 inertiaHalfExtents (
- radius,
- radius,
- radius);
+ //float radius = objprop->m_radius;
+ //btVector3 inertiaHalfExtents (
+ // radius,
+ // radius,
+ // radius);
//blender doesn't support multisphere, but for testing:
//bm = new MultiSphereShape(inertiaHalfExtents,,&trans.getOrigin(),&radius,1);
- bm = new btSphereShape(objprop->m_radius);
- bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
+ shapeInfo->m_shapeType = PHY_SHAPE_SPHERE;
+ bm = shapeInfo->CreateBulletShape();
break;
};
case KX_BOUNDBOX:
{
- MT_Vector3 halfExtents (
+ shapeInfo->m_halfExtend.setValue(
objprop->m_boundobject.box.m_extends[0],
- objprop->m_boundobject.box.m_extends[1],
- objprop->m_boundobject.box.m_extends[2]);
-
- halfExtents /= 2.f;
-
- //btVector3 he (halfExtents[0]-CONVEX_DISTANCE_MARGIN ,halfExtents[1]-CONVEX_DISTANCE_MARGIN ,halfExtents[2]-CONVEX_DISTANCE_MARGIN );
- //he = he.absolute();
-
- btVector3 he (halfExtents[0],halfExtents[1],halfExtents[2]);
- he = he.absolute();
-
+ objprop->m_boundobject.box.m_extends[1],
+ objprop->m_boundobject.box.m_extends[2]);
- bm = new btBoxShape(he);
- bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
+ shapeInfo->m_halfExtend /= 2.0;
+ shapeInfo->m_halfExtend = shapeInfo->m_halfExtend.absolute();
+ shapeInfo->m_shapeType = PHY_SHAPE_BOX;
+ bm = shapeInfo->CreateBulletShape();
break;
};
case KX_BOUNDCYLINDER:
{
- btVector3 halfExtents (
+ shapeInfo->m_halfExtend.setValue(
objprop->m_boundobject.c.m_radius,
objprop->m_boundobject.c.m_radius,
objprop->m_boundobject.c.m_height * 0.5f
);
- bm = new btCylinderShapeZ(halfExtents);
- bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
-
+ shapeInfo->m_shapeType = PHY_SHAPE_CYLINDER;
+ bm = shapeInfo->CreateBulletShape();
break;
}
- case KX_BOUNDCONE:
+ case KX_BOUNDCONE:
{
- btVector3 halfExtents (objprop->m_boundobject.box.m_extends[0],
- objprop->m_boundobject.box.m_extends[1],
- objprop->m_boundobject.box.m_extends[2]);
-
-
- halfExtents /= 2.f;
-
- bm = new btConeShapeZ(objprop->m_boundobject.c.m_radius,objprop->m_boundobject.c.m_height);
- bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
-
+ shapeInfo->m_radius = objprop->m_boundobject.c.m_radius;
+ shapeInfo->m_height = objprop->m_boundobject.c.m_height;
+ shapeInfo->m_shapeType = PHY_SHAPE_CONE;
+ bm = shapeInfo->CreateBulletShape();
break;
}
- case KX_BOUNDPOLYTOPE:
- {
- bm = CreateBulletShapeFromMesh(meshobj,true);
- if (bm)
+ case KX_BOUNDPOLYTOPE:
+ {
+ shapeInfo->SetMesh(meshobj, true,false);
+ bm = shapeInfo->CreateBulletShape();
+ break;
+ }
+ case KX_BOUNDMESH:
+ {
+
+ if (!ci.m_mass ||objprop->m_softbody)
+ {
+ // mesh shapes can be shared, check first if we already have a shape on that mesh
+ class CcdShapeConstructionInfo *sharedShapeInfo = CcdShapeConstructionInfo::FindMesh(meshobj, false);
+ if (sharedShapeInfo != NULL)
{
- bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
- }
- break;
- }
- case KX_BOUNDMESH:
- {
- if (!ci.m_mass)
- {
- bm = CreateBulletShapeFromMesh(meshobj,false);
- ci.m_localInertiaTensor.setValue(0.f,0.f,0.f);
- //no moving concave meshes, so don't bother calculating inertia
- //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
+ delete shapeInfo;
+ shapeInfo = sharedShapeInfo;
+ shapeInfo->AddRef();
+ } else
+ {
+ shapeInfo->SetMesh(meshobj, false,false);
}
+ if (objprop->m_softbody)
+ shapeInfo->setVertexWeldingThreshold(0.01f); //todo: expose this to the UI
- break;
- }
-
- default:
- //interpret the shape as a concave triangle-mesh
- {
- if (meshobj)
+ bm = shapeInfo->CreateBulletShape();
+ //no moving concave meshes, so don't bother calculating inertia
+ //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
+ } else
{
- bm = CreateBulletShapeFromMesh(meshobj,false);
- ci.m_localInertiaTensor.setValue(0.f,0.f,0.f);
-
- // assert(0);
-
- /*
- meshobj->ScheduleCollisionPolygons();
-
- KX_DeformableMesh* gfxmesh = new KX_DeformableMesh(meshobj);
- gfxmesh->sendFixedMapping();
- //trianglemesh
- bm = new TriangleMeshInterface(gfxmesh,trans);
- */
+ shapeInfo->SetMesh(meshobj, false,true);
+ bm = shapeInfo->CreateBulletShape();
}
+
+ break;
}
}
@@ -1018,10 +901,13 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
// ci.m_localInertiaTensor.setValue(0.1f,0.1f,0.1f);
if (!bm)
+ {
+ delete motionstate;
+ delete shapeInfo;
return;
+ }
- bm->setMargin(0.06);
-
+ bm->setMargin(ci.m_margin);
if (objprop->m_isCompoundChild)
@@ -1030,30 +916,46 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
//take relative transform into account!
KX_BulletPhysicsController* parentCtrl = (KX_BulletPhysicsController*)objprop->m_dynamic_parent->GetPhysicsController();
assert(parentCtrl);
+ CcdShapeConstructionInfo* parentShapeInfo = parentCtrl->GetShapeInfo();
btRigidBody* rigidbody = parentCtrl->GetRigidBody();
btCollisionShape* colShape = rigidbody->getCollisionShape();
assert(colShape->isCompound());
btCompoundShape* compoundShape = (btCompoundShape*)colShape;
- btTransform childTrans;
- childTrans.setIdentity();
- NodeList& children = objprop->m_dynamic_parent->GetSGNode()->GetSGChildren();
- MT_Point3 childPos = gameobj->GetSGNode()->GetLocalPosition();
- MT_Matrix3x3 childRot = gameobj->GetSGNode()->GetLocalOrientation();
- MT_Vector3 childScale = gameobj->GetSGNode()->GetLocalScale();
+ // compute the local transform from parent, this may include a parent inverse node
+ SG_Node* gameNode = gameobj->GetSGNode();
+ SG_Node* parentInverseNode = gameNode->GetSGParent();
+ if (parentInverseNode && parentInverseNode->GetSGClientObject() != NULL)
+ // this is not a parent inverse node, cancel it
+ parentInverseNode = NULL;
+ // now combine the parent inverse node and the game node
+ MT_Point3 childPos = gameNode->GetLocalPosition();
+ MT_Matrix3x3 childRot = gameNode->GetLocalOrientation();
+ MT_Vector3 childScale = gameNode->GetLocalScale();
+ if (parentInverseNode)
+ {
+ const MT_Point3& parentInversePos = parentInverseNode->GetLocalPosition();
+ const MT_Matrix3x3& parentInverseRot = parentInverseNode->GetLocalOrientation();
+ const MT_Vector3& parentInverseScale = parentInverseNode->GetLocalScale();
+ childRot = parentInverseRot * childRot;
+ childScale = parentInverseScale * childScale;
+ childPos = parentInversePos+parentInverseScale*(parentInverseRot*childPos);
+ }
- bm->setLocalScaling(btVector3(childScale.x(),childScale.y(),childScale.z()));
- childTrans.setOrigin(btVector3(childPos.x(),childPos.y(),childPos.z()));
+ shapeInfo->m_childScale.setValue(childScale.x(),childScale.y(),childScale.z());
+ bm->setLocalScaling(shapeInfo->m_childScale);
+
+ shapeInfo->m_childTrans.setOrigin(btVector3(childPos.x(),childPos.y(),childPos.z()));
float rotval[12];
childRot.getValue(rotval);
btMatrix3x3 newRot;
newRot.setValue(rotval[0],rotval[1],rotval[2],rotval[4],rotval[5],rotval[6],rotval[8],rotval[9],rotval[10]);
newRot = newRot.transpose();
- childTrans.setBasis(newRot);
-
-
- compoundShape->addChildShape(childTrans,bm);
+ shapeInfo->m_childTrans.setBasis(newRot);
+ parentShapeInfo->AddShape(shapeInfo);
+
+ compoundShape->addChildShape(shapeInfo->m_childTrans,bm);
//do some recalc?
//recalc inertia for rigidbody
if (!rigidbody->isStaticOrKinematicObject())
@@ -1068,12 +970,16 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
if (objprop->m_hasCompoundChildren)
{
- //replace shape by compoundShape
+ // create a compound shape info
+ CcdShapeConstructionInfo *compoundShapeInfo = new CcdShapeConstructionInfo();
+ compoundShapeInfo->m_shapeType = PHY_SHAPE_COMPOUND;
+ compoundShapeInfo->AddShape(shapeInfo);
+ // create the compound shape manually as we already have the child shape
btCompoundShape* compoundShape = new btCompoundShape();
- btTransform identTrans;
- identTrans.setIdentity();
- compoundShape->addChildShape(identTrans,bm);
+ compoundShape->addChildShape(shapeInfo->m_childTrans,bm);
+ // now replace the shape
bm = compoundShape;
+ shapeInfo = compoundShapeInfo;
}
@@ -1109,9 +1015,7 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
ci.m_collisionShape = bm;
-
-
-
+ ci.m_shapeInfo = shapeInfo;
ci.m_friction = smmaterial->m_friction;//tweak the friction a bit, so the default 0.5 works nice
ci.m_restitution = smmaterial->m_restitution;
ci.m_physicsEnv = env;
@@ -1121,7 +1025,69 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
//need a bit of damping, else system doesn't behave well
ci.m_inertiaFactor = shapeprops->m_inertia/0.4f;//defaults to 0.4, don't want to change behaviour
+ ci.m_do_anisotropic = shapeprops->m_do_anisotropic;
+ ci.m_anisotropicFriction.setValue(shapeprops->m_friction_scaling[0],shapeprops->m_friction_scaling[1],shapeprops->m_friction_scaling[2]);
+
+
+//////////
+ //do Fh, do Rot Fh
+ ci.m_do_fh = shapeprops->m_do_fh;
+ ci.m_do_rot_fh = shapeprops->m_do_rot_fh ;
+ ci.m_fh_damping = smmaterial->m_fh_damping;
+ ci.m_fh_distance = smmaterial->m_fh_distance;
+ ci.m_fh_normal = smmaterial->m_fh_normal;
+ ci.m_fh_spring = smmaterial->m_fh_spring;
+ ci.m_radius = objprop->m_radius;
+
+
+ ///////////////////
+ ci.m_gamesoftFlag = objprop->m_gamesoftFlag;
+ ci.m_soft_linStiff = objprop->m_soft_linStiff;
+ ci.m_soft_angStiff = objprop->m_soft_angStiff; /* angular stiffness 0..1 */
+ ci.m_soft_volume= objprop->m_soft_volume; /* volume preservation 0..1 */
+
+ ci.m_soft_viterations= objprop->m_soft_viterations; /* Velocities solver iterations */
+ ci.m_soft_piterations= objprop->m_soft_piterations; /* Positions solver iterations */
+ ci.m_soft_diterations= objprop->m_soft_diterations; /* Drift solver iterations */
+ ci.m_soft_citerations= objprop->m_soft_citerations; /* Cluster solver iterations */
+
+ ci.m_soft_kSRHR_CL= objprop->m_soft_kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */
+ ci.m_soft_kSKHR_CL= objprop->m_soft_kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */
+ ci.m_soft_kSSHR_CL= objprop->m_soft_kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */
+ ci.m_soft_kSR_SPLT_CL= objprop->m_soft_kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
+
+ ci.m_soft_kSK_SPLT_CL= objprop->m_soft_kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
+ ci.m_soft_kSS_SPLT_CL= objprop->m_soft_kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
+ ci.m_soft_kVCF= objprop->m_soft_kVCF; /* Velocities correction factor (Baumgarte) */
+ ci.m_soft_kDP= objprop->m_soft_kDP; /* Damping coefficient [0,1] */
+
+ ci.m_soft_kDG= objprop->m_soft_kDG; /* Drag coefficient [0,+inf] */
+ ci.m_soft_kLF= objprop->m_soft_kLF; /* Lift coefficient [0,+inf] */
+ ci.m_soft_kPR= objprop->m_soft_kPR; /* Pressure coefficient [-inf,+inf] */
+ ci.m_soft_kVC= objprop->m_soft_kVC; /* Volume conversation coefficient [0,+inf] */
+
+ ci.m_soft_kDF= objprop->m_soft_kDF; /* Dynamic friction coefficient [0,1] */
+ ci.m_soft_kMT= objprop->m_soft_kMT; /* Pose matching coefficient [0,1] */
+ ci.m_soft_kCHR= objprop->m_soft_kCHR; /* Rigid contacts hardness [0,1] */
+ ci.m_soft_kKHR= objprop->m_soft_kKHR; /* Kinetic contacts hardness [0,1] */
+
+ ci.m_soft_kSHR= objprop->m_soft_kSHR; /* Soft contacts hardness [0,1] */
+ ci.m_soft_kAHR= objprop->m_soft_kAHR; /* Anchors hardness [0,1] */
+ ci.m_soft_collisionflags= objprop->m_soft_collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */
+ ci.m_soft_numclusteriterations= objprop->m_soft_numclusteriterations; /* number of iterations to refine collision clusters*/
+
+ ////////////////////
+
+ ci.m_collisionFilterGroup = (isbulletdyna) ? short(CcdConstructionInfo::DefaultFilter) : short(CcdConstructionInfo::StaticFilter);
+ ci.m_collisionFilterMask = (isbulletdyna) ? short(CcdConstructionInfo::AllFilter) : short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter);
+ ci.m_bRigid = objprop->m_dyna && objprop->m_angular_rigidbody;
+ ci.m_bSoft = objprop->m_softbody;
+ MT_Vector3 scaling = gameobj->NodeGetWorldScaling();
+ ci.m_scaling.setValue(scaling[0], scaling[1], scaling[2]);
KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna);
+ // shapeInfo is reference counted, decrement now as we don't use it anymore
+ if (shapeInfo)
+ shapeInfo->Release();
if (objprop->m_in_active_layer)
{
@@ -1132,15 +1098,23 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
gameobj->SetPhysicsController(physicscontroller,isbulletdyna);
physicscontroller->setNewClientInfo(gameobj->getClientInfo());
- btRigidBody* rbody = physicscontroller->GetRigidBody();
-
- if (objprop->m_disableSleeping)
- rbody->setActivationState(DISABLE_DEACTIVATION);
-
- if (objprop->m_ghost)
{
- rbody->setCollisionFlags(rbody->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE);
+ btRigidBody* rbody = physicscontroller->GetRigidBody();
+
+ if (rbody && objprop->m_disableSleeping)
+ rbody->setActivationState(DISABLE_DEACTIVATION);
}
+
+ CcdPhysicsController* parentCtrl = objprop->m_dynamic_parent ? (KX_BulletPhysicsController*)objprop->m_dynamic_parent->GetPhysicsController() : 0;
+ physicscontroller->setParentCtrl(parentCtrl);
+
+
+ //Now done directly in ci.m_collisionFlags so that it propagates to replica
+ //if (objprop->m_ghost)
+ //{
+ // rbody->setCollisionFlags(rbody->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE);
+ //}
+
if (objprop->m_dyna && !objprop->m_angular_rigidbody)
{
/*
@@ -1155,8 +1129,10 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
*/
//env->createConstraint(physicscontroller,0,PHY_ANGULAR_CONSTRAINT,0,0,0,0,0,1);
- physicscontroller->GetRigidBody()->setAngularFactor(0.f);
-
+
+ //Now done directly in ci.m_bRigid so that it propagates to replica
+ //physicscontroller->GetRigidBody()->setAngularFactor(0.f);
+ ;
}
bool isActor = objprop->m_isactor;
@@ -1180,22 +1156,25 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
physicscontroller->SetObject(gameobj->GetSGNode());
+
+ ///test for soft bodies
+ if (objprop->m_softbody && physicscontroller)
+ {
+ btSoftBody* softBody = physicscontroller->GetSoftBody();
+ if (softBody && gameobj->GetMesh(0))//only the first mesh, if any
+ {
+ //should be a mesh then, so add a soft body deformer
+ KX_SoftBodyDeformer* softbodyDeformer = new KX_SoftBodyDeformer( gameobj->GetMesh(0),gameobj);
+ gameobj->SetDeformer(softbodyDeformer);
+
+ }
+ }
+
}
void KX_ClearBulletSharedShapes()
{
- int numshapes = map_gamemesh_to_bulletshape.size();
- int i;
- btCollisionShape*shape=0;
- for (i=0;i<numshapes ;i++)
- {
- shape = *map_gamemesh_to_bulletshape.at(i);
- //delete shape;
- }
-
- map_gamemesh_to_bulletshape.clear();
-
}
#endif
diff --git a/source/gameengine/Ketsji/KX_GameActuator.cpp b/source/gameengine/Ketsji/KX_GameActuator.cpp
index fcd32d5f4fe..76459e46731 100644
--- a/source/gameengine/Ketsji/KX_GameActuator.cpp
+++ b/source/gameengine/Ketsji/KX_GameActuator.cpp
@@ -34,6 +34,7 @@
//#include <iostream>
#include "KX_Scene.h"
#include "KX_KetsjiEngine.h"
+#include "KX_PythonInit.h" /* for config load/saving */
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -125,6 +126,71 @@ bool KX_GameActuator::Update()
}
break;
}
+ case KX_GAME_SAVECFG:
+ {
+ if (m_ketsjiengine)
+ {
+ char mashal_path[512];
+ char *marshal_buffer = NULL;
+ int marshal_length;
+ FILE *fp = NULL;
+
+ pathGamePythonConfig(mashal_path);
+ marshal_length = saveGamePythonConfig(&marshal_buffer);
+
+ if (marshal_length && marshal_buffer) {
+ fp = fopen(mashal_path, "wb");
+ if (fp) {
+ if (fwrite(marshal_buffer, 1, marshal_length, fp) != marshal_length) {
+ printf("Warning: could not write marshal data\n");
+ }
+ fclose(fp);
+ } else {
+ printf("Warning: could not open marshal file\n");
+ }
+ } else {
+ printf("Warning: could not create marshal buffer\n");
+ }
+ }
+ break;
+ }
+ case KX_GAME_LOADCFG:
+ {
+ if (m_ketsjiengine)
+ {
+ char mashal_path[512];
+ char *marshal_buffer;
+ int marshal_length;
+ FILE *fp = NULL;
+ int result;
+
+ pathGamePythonConfig(mashal_path);
+
+ fp = fopen(mashal_path, "rb");
+ if (fp) {
+ // obtain file size:
+ fseek (fp , 0 , SEEK_END);
+ marshal_length = ftell(fp);
+ rewind(fp);
+
+ marshal_buffer = (char*) malloc (sizeof(char)*marshal_length);
+
+ result = fread (marshal_buffer, 1, marshal_length, fp);
+
+ if (result == marshal_length) {
+ loadGamePythonConfig(marshal_buffer, marshal_length);
+ } else {
+ printf("warning: could not read all of '%s'\n", mashal_path);
+ }
+
+ free(marshal_buffer);
+ fclose(fp);
+ } else {
+ printf("warning: could not open '%s'\n", mashal_path);
+ }
+ }
+ break;
+ }
default:
; /* do nothing? this is an internal error !!! */
}
@@ -175,13 +241,13 @@ PyParentObject KX_GameActuator::Parents[] =
PyMethodDef KX_GameActuator::Methods[] =
{
- {"getFile", (PyCFunction) KX_GameActuator::sPyGetFile, METH_VARARGS, GetFile_doc},
- {"setFile", (PyCFunction) KX_GameActuator::sPySetFile, METH_VARARGS, SetFile_doc},
+ {"getFile", (PyCFunction) KX_GameActuator::sPyGetFile, METH_VARARGS, (PY_METHODCHAR)GetFile_doc},
+ {"setFile", (PyCFunction) KX_GameActuator::sPySetFile, METH_VARARGS, (PY_METHODCHAR)SetFile_doc},
{NULL,NULL} //Sentinel
};
/* getFile */
-char KX_GameActuator::GetFile_doc[] =
+const char KX_GameActuator::GetFile_doc[] =
"getFile()\n"
"get the name of the file to start.\n";
PyObject* KX_GameActuator::PyGetFile(PyObject* self, PyObject* args, PyObject* kwds)
@@ -190,7 +256,7 @@ PyObject* KX_GameActuator::PyGetFile(PyObject* self, PyObject* args, PyObject* k
}
/* setFile */
-char KX_GameActuator::SetFile_doc[] =
+const char KX_GameActuator::SetFile_doc[] =
"setFile(name)\n"
"set the name of the file to start.\n";
PyObject* KX_GameActuator::PySetFile(PyObject* self, PyObject* args, PyObject* kwds)
diff --git a/source/gameengine/Ketsji/KX_GameActuator.h b/source/gameengine/Ketsji/KX_GameActuator.h
index 8565dc46caa..bb3448995dc 100644
--- a/source/gameengine/Ketsji/KX_GameActuator.h
+++ b/source/gameengine/Ketsji/KX_GameActuator.h
@@ -54,6 +54,8 @@ protected:
KX_GAME_START,
KX_GAME_RESTART,
KX_GAME_QUIT,
+ KX_GAME_SAVECFG,
+ KX_GAME_LOADCFG,
KX_GAME_MAX
};
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
index 1cb64585ff8..a168beb9a70 100644
--- a/source/gameengine/Ketsji/KX_GameObject.cpp
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -51,6 +51,7 @@ typedef unsigned long uint_ptr;
#include "KX_GameObject.h"
#include "RAS_MeshObject.h"
#include "KX_MeshProxy.h"
+#include "KX_PolyProxy.h"
#include <stdio.h> // printf
#include "SG_Controller.h"
#include "KX_IPhysicsController.h"
@@ -58,8 +59,13 @@ typedef unsigned long uint_ptr;
#include "SG_Controller.h"
#include "KX_ClientObjectInfo.h"
#include "RAS_BucketManager.h"
-
+#include "KX_RayCast.h"
+#include "KX_PythonInit.h"
#include "KX_PyMath.h"
+#include "SCA_IActuator.h"
+#include "SCA_ISensor.h"
+
+#include "PyObjectPlus.h" /* python stuff */
// This file defines relationships between parents and children
// in the game engine.
@@ -73,36 +79,56 @@ KX_GameObject::KX_GameObject(
) :
SCA_IObject(T),
m_bDyna(false),
+ m_layer(0),
+ m_pBlenderObject(NULL),
+ m_pBlenderGroupObject(NULL),
m_bSuspendDynamics(false),
m_bUseObjectColor(false),
+ m_bIsNegativeScaling(false),
m_bVisible(true),
+ m_bCulled(true),
m_pPhysicsController1(NULL),
+ m_pPhysicsEnvironment(NULL),
+ m_xray(false),
+ m_pHitObject(NULL),
m_isDeformable(false)
{
m_ignore_activity_culling = false;
m_pClient_info = new KX_ClientObjectInfo(this, KX_ClientObjectInfo::ACTOR);
m_pSGNode = new SG_Node(this,sgReplicationInfo,callbacks);
-
+
// define the relationship between this node and it's parent.
KX_NormalParentRelation * parent_relation =
KX_NormalParentRelation::New();
m_pSGNode->SetParentRelation(parent_relation);
-
-
};
KX_GameObject::~KX_GameObject()
{
+ RemoveMeshes();
+
// is this delete somewhere ?
//if (m_sumoObj)
// delete m_sumoObj;
delete m_pClient_info;
//if (m_pSGNode)
// delete m_pSGNode;
-
+ if (m_pSGNode)
+ {
+ // must go through controllers and make sure they will not use us anymore
+ // This is important for KX_BulletPhysicsControllers that unregister themselves
+ // from the object when they are deleted.
+ SGControllerList::iterator contit;
+ SGControllerList& controllers = m_pSGNode->GetSGControllerList();
+ for (contit = controllers.begin();contit!=controllers.end();++contit)
+ {
+ (*contit)->ClearObject();
+ }
+ m_pSGNode->SetSGClientObject(NULL);
+ }
}
@@ -186,7 +212,73 @@ KX_GameObject* KX_GameObject::GetParent()
}
+void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj)
+{
+ // check on valid node in case a python controller holds a reference to a deleted object
+ if (obj && GetSGNode() && obj->GetSGNode() && GetSGNode()->GetSGParent() != obj->GetSGNode())
+ {
+ // Make sure the objects have some scale
+ MT_Vector3 scale1 = NodeGetWorldScaling();
+ MT_Vector3 scale2 = obj->NodeGetWorldScaling();
+ if (fabs(scale2[0]) < FLT_EPSILON ||
+ fabs(scale2[1]) < FLT_EPSILON ||
+ fabs(scale2[2]) < FLT_EPSILON ||
+ fabs(scale1[0]) < FLT_EPSILON ||
+ fabs(scale1[1]) < FLT_EPSILON ||
+ fabs(scale1[2]) < FLT_EPSILON) { return; }
+
+ // Remove us from our old parent and set our new parent
+ RemoveParent(scene);
+ obj->GetSGNode()->AddChild(GetSGNode());
+
+ if (m_pPhysicsController1)
+ {
+ m_pPhysicsController1->SuspendDynamics(true);
+ }
+ // Set us to our new scale, position, and orientation
+ scale2[0] = 1.0/scale2[0];
+ scale2[1] = 1.0/scale2[1];
+ scale2[2] = 1.0/scale2[2];
+ scale1 = scale1 * scale2;
+ MT_Matrix3x3 invori = obj->NodeGetWorldOrientation().inverse();
+ MT_Vector3 newpos = invori*(NodeGetWorldPosition()-obj->NodeGetWorldPosition())*scale2;
+
+ NodeSetLocalScale(scale1);
+ NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2]));
+ NodeSetLocalOrientation(invori*NodeGetWorldOrientation());
+ NodeUpdateGS(0.f,true);
+ // object will now be a child, it must be removed from the parent list
+ CListValue* rootlist = scene->GetRootParentList();
+ if (rootlist->RemoveValue(this))
+ // the object was in parent list, decrement ref count as it's now removed
+ Release();
+ }
+}
+
+void KX_GameObject::RemoveParent(KX_Scene *scene)
+{
+ // check on valid node in case a python controller holds a reference to a deleted object
+ if (GetSGNode() && GetSGNode()->GetSGParent())
+ {
+ // Set us to the right spot
+ GetSGNode()->SetLocalScale(GetSGNode()->GetWorldScaling());
+ GetSGNode()->SetLocalOrientation(GetSGNode()->GetWorldOrientation());
+ GetSGNode()->SetLocalPosition(GetSGNode()->GetWorldPosition());
+ // Remove us from our parent
+ GetSGNode()->DisconnectFromParent();
+ NodeUpdateGS(0.f,true);
+ // the object is now a root object, add it to the parentlist
+ CListValue* rootlist = scene->GetRootParentList();
+ if (!rootlist->SearchValue(this))
+ // object was not in root list, add it now and increment ref count
+ rootlist->Add(AddRef());
+ if (m_pPhysicsController1)
+ {
+ m_pPhysicsController1->RestoreDynamics();
+ }
+ }
+}
void KX_GameObject::ProcessReplica(KX_GameObject* replica)
{
@@ -194,6 +286,7 @@ void KX_GameObject::ProcessReplica(KX_GameObject* replica)
replica->m_pSGNode = NULL;
replica->m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info);
replica->m_pClient_info->m_gameobject = replica;
+ replica->m_state = 0;
}
@@ -201,11 +294,11 @@ void KX_GameObject::ProcessReplica(KX_GameObject* replica)
CValue* KX_GameObject::GetReplica()
{
KX_GameObject* replica = new KX_GameObject(*this);
-
+
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
ProcessReplica(replica);
-
+
return replica;
}
@@ -241,12 +334,12 @@ void KX_GameObject::ApplyMovement(const MT_Vector3& dloc,bool local)
void KX_GameObject::ApplyRotation(const MT_Vector3& drot,bool local)
{
MT_Matrix3x3 rotmat(drot);
- rotmat.transpose();
-
- if (m_pPhysicsController1) // (IsDynamic())
- m_pPhysicsController1->RelativeRotate(rotmat,local);
- // in worldspace
+
GetSGNode()->RelativeRotate(rotmat,local);
+
+ if (m_pPhysicsController1) { // (IsDynamic())
+ m_pPhysicsController1->RelativeRotate(rotmat,local);
+ }
}
@@ -264,31 +357,54 @@ double* KX_GameObject::GetOpenGLMatrix()
trans.setBasis(GetSGNode()->GetWorldOrientation());
MT_Vector3 scaling = GetSGNode()->GetWorldScaling();
-
+ m_bIsNegativeScaling = ((scaling[0] < 0.0) ^ (scaling[1] < 0.0) ^ (scaling[2] < 0.0)) ? true : false;
trans.scale(scaling[0], scaling[1], scaling[2]);
trans.getValue(fl);
return fl;
}
+void KX_GameObject::AddMeshUser()
+{
+ for (size_t i=0;i<m_meshes.size();i++)
+ m_meshes[i]->AddMeshUser(this);
+
+ UpdateBuckets(false);
+}
+
+static void UpdateBuckets_recursive(SG_Node* node)
+{
+ NodeList& children = node->GetSGChildren();
+ for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit)
+ {
+ SG_Node* childnode = (*childit);
+ KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject());
+ if (clientgameobj != NULL) // This is a GameObject
+ clientgameobj->UpdateBuckets(0);
+
+ // if the childobj is NULL then this may be an inverse parent link
+ // so a non recursive search should still look down this node.
+ UpdateBuckets_recursive(childnode);
+ }
+}
-void KX_GameObject::Bucketize()
+void KX_GameObject::UpdateBuckets( bool recursive )
{
double* fl = GetOpenGLMatrix();
for (size_t i=0;i<m_meshes.size();i++)
- m_meshes[i]->Bucketize(fl, this, m_bUseObjectColor, m_objectColor);
+ m_meshes[i]->UpdateBuckets(this, fl, m_bUseObjectColor, m_objectColor, m_bVisible, m_bCulled);
+
+ if (recursive) {
+ UpdateBuckets_recursive(m_pSGNode);
+ }
}
-
-
void KX_GameObject::RemoveMeshes()
{
- double* fl = GetOpenGLMatrix();
-
for (size_t i=0;i<m_meshes.size();i++)
- m_meshes[i]->RemoveFromBuckets(fl, this);
+ m_meshes[i]->RemoveFromBuckets(this);
//note: meshes can be shared, and are deleted by KX_BlenderSceneConverter
@@ -332,34 +448,25 @@ void KX_GameObject::ResetDebugColor()
SetDebugColor(0xff000000);
}
+void KX_GameObject::InitIPO(bool ipo_as_force,
+ bool ipo_add,
+ bool ipo_local)
+{
+ SGControllerList::iterator it = GetSGNode()->GetSGControllerList().begin();
+ while (it != GetSGNode()->GetSGControllerList().end()) {
+ (*it)->SetOption(SG_Controller::SG_CONTR_IPO_RESET, true);
+ (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, ipo_as_force);
+ (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_ADD, ipo_add);
+ (*it)->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, ipo_local);
+ it++;
+ }
+}
void KX_GameObject::UpdateIPO(float curframetime,
- bool recurse,
- bool ipo_as_force,
- bool force_local)
+ bool recurse)
{
-
- // The ipo-actuator needs a sumo reference... this is retrieved (unfortunately)
- // by the iposgcontr itself...
-// ipocontr->SetSumoReference(gameobj->GetSumoScene(),
-// gameobj->GetSumoObject());
-
-
- // The ipo has to be treated as a force, and not a displacement!
- // For this case, we send some settings to the controller. This
- // may need some caching...
- if (ipo_as_force) {
- SGControllerList::iterator it = GetSGNode()->GetSGControllerList().begin();
-
- while (it != GetSGNode()->GetSGControllerList().end()) {
- (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, ipo_as_force);
- (*it)->SetOption(SG_Controller::SG_CONTR_IPO_FORCES_ACT_LOCAL, force_local);
- it++;
- }
- }
-
- // The rest is the 'normal' update procedure.
+ // just the 'normal' update procedure.
GetSGNode()->SetSimulatedTime(curframetime,recurse);
GetSGNode()->UpdateWorldData(curframetime);
UpdateTransform();
@@ -368,6 +475,7 @@ void KX_GameObject::UpdateIPO(float curframetime,
// IPO update
void
KX_GameObject::UpdateMaterialData(
+ dword matname_hash,
MT_Vector4 rgba,
MT_Vector3 specrgb,
MT_Scalar hard,
@@ -380,15 +488,34 @@ KX_GameObject::UpdateMaterialData(
{
int mesh = 0;
if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0) {
- RAS_MaterialBucket::Set::iterator mit = m_meshes[mesh]->GetFirstMaterial();
+ list<RAS_MeshMaterial>::iterator mit = m_meshes[mesh]->GetFirstMaterial();
+
for(; mit != m_meshes[mesh]->GetLastMaterial(); ++mit)
{
- RAS_IPolyMaterial* poly = (*mit)->GetPolyMaterial();
+ RAS_IPolyMaterial* poly = mit->m_bucket->GetPolyMaterial();
+
if(poly->GetFlag() & RAS_BLENDERMAT )
{
- SetObjectColor(rgba);
KX_BlenderMaterial *m = static_cast<KX_BlenderMaterial*>(poly);
- m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha);
+
+ if (matname_hash == NULL)
+ {
+ m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha);
+ // if mesh has only one material attached to it then use original hack with no need to edit vertices (better performance)
+ SetObjectColor(rgba);
+ }
+ else
+ {
+ if (matname_hash == poly->GetMaterialNameHash())
+ {
+ m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha);
+ m_meshes[mesh]->SetVertexColor(poly,rgba);
+
+ // no break here, because one blender material can be split into several game engine materials
+ // (e.g. one uvsphere material is split into one material at poles with ras_mode TRIANGLE and one material for the body
+ // if here was a break then would miss some vertices if material was split
+ }
+ }
}
}
}
@@ -401,56 +528,75 @@ KX_GameObject::GetVisible(
return m_bVisible;
}
+static void setVisible_recursive(SG_Node* node, bool v)
+{
+ NodeList& children = node->GetSGChildren();
+
+ for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit)
+ {
+ SG_Node* childnode = (*childit);
+ KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject());
+ if (clientgameobj != NULL) // This is a GameObject
+ clientgameobj->SetVisible(v, 0);
+
+ // if the childobj is NULL then this may be an inverse parent link
+ // so a non recursive search should still look down this node.
+ setVisible_recursive(childnode, v);
+ }
+}
+
+
void
KX_GameObject::SetVisible(
- bool v
+ bool v,
+ bool recursive
)
{
m_bVisible = v;
+ if (recursive)
+ setVisible_recursive(m_pSGNode, v);
}
-// used by Python, and the actuatorshould _not_ be misused by the
-// scene!
-void
-KX_GameObject::MarkVisible(
- bool visible
+bool
+KX_GameObject::GetCulled(
+ void
)
{
- /* If explicit visibility settings are used, this is
- * determined on this level. Maybe change this to mesh level
- * later on? */
-
- double* fl = GetOpenGLMatrixPtr()->getPointer();
- for (size_t i=0;i<m_meshes.size();i++)
- {
- m_meshes[i]->MarkVisible(fl,this,visible,m_bUseObjectColor,m_objectColor);
- }
+ return m_bCulled;
}
+void
+KX_GameObject::SetCulled(
+ bool c
+ )
+{
+ m_bCulled = c;
+}
-// Always use the flag?
-void
-KX_GameObject::MarkVisible(
- void
+
+void
+KX_GameObject::SetLayer(
+ int l
)
{
- double* fl = GetOpenGLMatrixPtr()->getPointer();
- for (size_t i=0;i<m_meshes.size();i++)
- {
- m_meshes[i]->MarkVisible(fl,
- this,
- m_bVisible,
- m_bUseObjectColor,
- m_objectColor
- );
- }
+ m_layer = l;
}
+int
+KX_GameObject::GetLayer(
+ void
+ )
+{
+ return m_layer;
+}
void KX_GameObject::addLinearVelocity(const MT_Vector3& lin_vel,bool local)
{
- if (m_pPhysicsController1)
- m_pPhysicsController1->SetLinearVelocity(lin_vel + m_pPhysicsController1->GetLinearVelocity(),local);
+ if (m_pPhysicsController1)
+ {
+ MT_Vector3 lv = local ? NodeGetWorldOrientation() * lin_vel : lin_vel;
+ m_pPhysicsController1->SetLinearVelocity(lv + m_pPhysicsController1->GetLinearVelocity(), 0);
+ }
}
@@ -492,62 +638,205 @@ void KX_GameObject::SetObjectColor(const MT_Vector4& rgbavec)
m_objectColor = rgbavec;
}
+void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac)
+{
+ MT_Matrix3x3 orimat;
+ MT_Vector3 vect,ori,z,x,y;
+ MT_Scalar len;
+ // check on valid node in case a python controller holds a reference to a deleted object
+ if (!GetSGNode())
+ return;
-MT_Vector3 KX_GameObject::GetLinearVelocity()
-{
- MT_Vector3 velocity(0.0,0.0,0.0);
+ vect = dir;
+ len = vect.length();
+ if (MT_fuzzyZero(len))
+ {
+ cout << "alignAxisToVect() Error: Null vector!\n";
+ return;
+ }
+
+ if (fac<=0.0) {
+ return;
+ }
+ // normalize
+ vect /= len;
+ orimat = GetSGNode()->GetWorldOrientation();
+ switch (axis)
+ {
+ case 0: //x axis
+ ori = MT_Vector3(orimat[0][2], orimat[1][2], orimat[2][2]); //pivot axis
+ if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON) //is the vector paralell to the pivot?
+ ori = MT_Vector3(orimat[0][1], orimat[1][1], orimat[2][1]); //change the pivot!
+ if (fac == 1.0) {
+ x = vect;
+ } else {
+ x = (vect * fac) + ((orimat * MT_Vector3(1.0, 0.0, 0.0)) * (1-fac));
+ len = x.length();
+ if (MT_fuzzyZero(len)) x = vect;
+ else x /= len;
+ }
+ y = ori.cross(x);
+ z = x.cross(y);
+ break;
+ case 1: //y axis
+ ori = MT_Vector3(orimat[0][0], orimat[1][0], orimat[2][0]);
+ if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON)
+ ori = MT_Vector3(orimat[0][2], orimat[1][2], orimat[2][2]);
+ if (fac == 1.0) {
+ y = vect;
+ } else {
+ y = (vect * fac) + ((orimat * MT_Vector3(0.0, 1.0, 0.0)) * (1-fac));
+ len = y.length();
+ if (MT_fuzzyZero(len)) y = vect;
+ else y /= len;
+ }
+ z = ori.cross(y);
+ x = y.cross(z);
+ break;
+ case 2: //z axis
+ ori = MT_Vector3(orimat[0][1], orimat[1][1], orimat[2][1]);
+ if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON)
+ ori = MT_Vector3(orimat[0][0], orimat[1][0], orimat[2][0]);
+ if (fac == 1.0) {
+ z = vect;
+ } else {
+ z = (vect * fac) + ((orimat * MT_Vector3(0.0, 0.0, 1.0)) * (1-fac));
+ len = z.length();
+ if (MT_fuzzyZero(len)) z = vect;
+ else z /= len;
+ }
+ x = ori.cross(z);
+ y = z.cross(x);
+ break;
+ default: //wrong input?
+ cout << "alignAxisToVect(): Wrong axis '" << axis <<"'\n";
+ return;
+ }
+ x.normalize(); //normalize the vectors
+ y.normalize();
+ z.normalize();
+ orimat = MT_Matrix3x3( x[0],y[0],z[0],
+ x[1],y[1],z[1],
+ x[2],y[2],z[2]);
+ if (GetSGNode()->GetSGParent() != NULL)
+ {
+ // the object is a child, adapt its local orientation so that
+ // the global orientation is aligned as we want.
+ MT_Matrix3x3 invori = GetSGNode()->GetSGParent()->GetWorldOrientation().inverse();
+ NodeSetLocalOrientation(invori*orimat);
+ }
+ else
+ NodeSetLocalOrientation(orimat);
+}
+
+MT_Scalar KX_GameObject::GetMass()
+{
+ if (m_pPhysicsController1)
+ {
+ return m_pPhysicsController1->GetMass();
+ }
+ return 0.0;
+}
+
+MT_Vector3 KX_GameObject::GetLinearVelocity(bool local)
+{
+ MT_Vector3 velocity(0.0,0.0,0.0), locvel;
+ MT_Matrix3x3 ori;
if (m_pPhysicsController1)
{
velocity = m_pPhysicsController1->GetLinearVelocity();
+
+ if (local)
+ {
+ ori = GetSGNode()->GetWorldOrientation();
+
+ locvel = velocity * ori;
+ return locvel;
+ }
}
- return velocity;
-
+ return velocity;
+}
+
+MT_Vector3 KX_GameObject::GetAngularVelocity(bool local)
+{
+ MT_Vector3 velocity(0.0,0.0,0.0), locvel;
+ MT_Matrix3x3 ori;
+ if (m_pPhysicsController1)
+ {
+ velocity = m_pPhysicsController1->GetAngularVelocity();
+
+ if (local)
+ {
+ ori = GetSGNode()->GetWorldOrientation();
+
+ locvel = velocity * ori;
+ return locvel;
+ }
+ }
+ return velocity;
}
+MT_Vector3 KX_GameObject::GetVelocity(const MT_Point3& point)
+{
+ if (m_pPhysicsController1)
+ {
+ return m_pPhysicsController1->GetVelocity(point);
+ }
+ return MT_Vector3(0.0,0.0,0.0);
+}
// scenegraph node stuff
void KX_GameObject::NodeSetLocalPosition(const MT_Point3& trans)
{
- if (m_pPhysicsController1)
+ // check on valid node in case a python controller holds a reference to a deleted object
+ if (!GetSGNode())
+ return;
+
+ if (m_pPhysicsController1 && !GetSGNode()->GetSGParent())
{
+ // don't update physic controller if the object is a child:
+ // 1) the transformation will not be right
+ // 2) in this case, the physic controller is necessarily a static object
+ // that is updated from the normal kinematic synchronization
m_pPhysicsController1->setPosition(trans);
}
- if (GetSGNode())
- GetSGNode()->SetLocalPosition(trans);
+ GetSGNode()->SetLocalPosition(trans);
}
void KX_GameObject::NodeSetLocalOrientation(const MT_Matrix3x3& rot)
{
- if (m_pPhysicsController1)
- {
- m_pPhysicsController1->setOrientation(rot.getRotation());
- }
- if (GetSGNode())
- GetSGNode()->SetLocalOrientation(rot);
- else
+ // check on valid node in case a python controller holds a reference to a deleted object
+ if (!GetSGNode())
+ return;
+
+ if (m_pPhysicsController1 && !GetSGNode()->GetSGParent())
{
- int i;
- i=0;
+ // see note above
+ m_pPhysicsController1->setOrientation(rot);
}
+ GetSGNode()->SetLocalOrientation(rot);
}
void KX_GameObject::NodeSetLocalScale(const MT_Vector3& scale)
{
- if (m_pPhysicsController1)
+ // check on valid node in case a python controller holds a reference to a deleted object
+ if (!GetSGNode())
+ return;
+
+ if (m_pPhysicsController1 && !GetSGNode()->GetSGParent())
{
+ // see note above
m_pPhysicsController1->setScaling(scale);
}
-
- if (GetSGNode())
- GetSGNode()->SetLocalScale(scale);
+ GetSGNode()->SetLocalScale(scale);
}
@@ -555,9 +844,44 @@ void KX_GameObject::NodeSetLocalScale(const MT_Vector3& scale)
void KX_GameObject::NodeSetRelativeScale(const MT_Vector3& scale)
{
if (GetSGNode())
+ {
GetSGNode()->RelativeScale(scale);
+ if (m_pPhysicsController1 && (!GetSGNode()->GetSGParent()))
+ {
+ // see note above
+ // we can use the local scale: it's the same thing for a root object
+ // and the world scale is not yet updated
+ MT_Vector3 newscale = GetSGNode()->GetLocalScale();
+ m_pPhysicsController1->setScaling(newscale);
+ }
+ }
}
+void KX_GameObject::NodeSetWorldPosition(const MT_Point3& trans)
+{
+ SG_Node* parent = m_pSGNode->GetSGParent();
+ if (parent != NULL)
+ {
+ // Make sure the objects have some scale
+ MT_Vector3 scale = parent->GetWorldScaling();
+ if (fabs(scale[0]) < FLT_EPSILON ||
+ fabs(scale[1]) < FLT_EPSILON ||
+ fabs(scale[2]) < FLT_EPSILON)
+ {
+ return;
+ }
+ scale[0] = 1.0/scale[0];
+ scale[1] = 1.0/scale[1];
+ scale[2] = 1.0/scale[2];
+ MT_Matrix3x3 invori = parent->GetWorldOrientation().inverse();
+ MT_Vector3 newpos = invori*(trans-parent->GetWorldPosition())*scale;
+ NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2]));
+ }
+ else
+ {
+ NodeSetLocalPosition(trans);
+ }
+}
void KX_GameObject::NodeUpdateGS(double time,bool bInitiator)
@@ -570,6 +894,13 @@ void KX_GameObject::NodeUpdateGS(double time,bool bInitiator)
const MT_Matrix3x3& KX_GameObject::NodeGetWorldOrientation() const
{
+ static MT_Matrix3x3 defaultOrientation = MT_Matrix3x3( 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0);
+
+ // check on valid node in case a python controller holds a reference to a deleted object
+ if (!GetSGNode())
+ return defaultOrientation;
return GetSGNode()->GetWorldOrientation();
}
@@ -577,6 +908,12 @@ const MT_Matrix3x3& KX_GameObject::NodeGetWorldOrientation() const
const MT_Vector3& KX_GameObject::NodeGetWorldScaling() const
{
+ static MT_Vector3 defaultScaling = MT_Vector3(1.0, 1.0, 1.0);
+
+ // check on valid node in case a python controller holds a reference to a deleted object
+ if (!GetSGNode())
+ return defaultScaling;
+
return GetSGNode()->GetWorldScaling();
}
@@ -584,6 +921,12 @@ const MT_Vector3& KX_GameObject::NodeGetWorldScaling() const
const MT_Point3& KX_GameObject::NodeGetWorldPosition() const
{
+ static MT_Point3 defaultPosition = MT_Point3(0.0, 0.0, 0.0);
+
+ // check on valid node in case a python controller holds a reference to a deleted object
+ if (!GetSGNode())
+ return defaultPosition;
+
return GetSGNode()->GetWorldPosition();
}
@@ -604,7 +947,7 @@ void KX_GameObject::Resume(void)
}
}
-void KX_GameObject::Suspend(void)
+void KX_GameObject::Suspend()
{
if ((!m_ignore_activity_culling)
&& (!m_suspended)) {
@@ -623,25 +966,44 @@ void KX_GameObject::Suspend(void)
PyMethodDef KX_GameObject::Methods[] = {
- {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS},
- {"setPosition", (PyCFunction) KX_GameObject::sPySetPosition, METH_VARARGS},
- {"getPosition", (PyCFunction) KX_GameObject::sPyGetPosition, METH_VARARGS},
- {"getOrientation", (PyCFunction) KX_GameObject::sPyGetOrientation, METH_VARARGS},
- {"setOrientation", (PyCFunction) KX_GameObject::sPySetOrientation, METH_VARARGS},
+ {"getPosition", (PyCFunction) KX_GameObject::sPyGetPosition, METH_NOARGS},
+ {"setPosition", (PyCFunction) KX_GameObject::sPySetPosition, METH_O},
+ {"setWorldPosition", (PyCFunction) KX_GameObject::sPySetWorldPosition, METH_O},
{"getLinearVelocity", (PyCFunction) KX_GameObject::sPyGetLinearVelocity, METH_VARARGS},
+ {"setLinearVelocity", (PyCFunction) KX_GameObject::sPySetLinearVelocity, METH_VARARGS},
+ {"getAngularVelocity", (PyCFunction) KX_GameObject::sPyGetAngularVelocity, METH_VARARGS},
+ {"setAngularVelocity", (PyCFunction) KX_GameObject::sPySetAngularVelocity, METH_VARARGS},
{"getVelocity", (PyCFunction) KX_GameObject::sPyGetVelocity, METH_VARARGS},
- {"getMass", (PyCFunction) KX_GameObject::sPyGetMass, METH_VARARGS},
- {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_VARARGS},
+ {"getMass", (PyCFunction) KX_GameObject::sPyGetMass, METH_NOARGS},
+ {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_NOARGS},
+ {"getOrientation", (PyCFunction) KX_GameObject::sPyGetOrientation, METH_NOARGS},
+ {"setOrientation", (PyCFunction) KX_GameObject::sPySetOrientation, METH_O},
+ {"getVisible",(PyCFunction) KX_GameObject::sPyGetVisible, METH_NOARGS},
+ {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS},
+ {"getState",(PyCFunction) KX_GameObject::sPyGetState, METH_NOARGS},
+ {"setState",(PyCFunction) KX_GameObject::sPySetState, METH_O},
+ {"alignAxisToVect",(PyCFunction) KX_GameObject::sPyAlignAxisToVect, METH_VARARGS},
+ {"getAxisVect",(PyCFunction) KX_GameObject::sPyGetAxisVect, METH_O},
+ {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics,METH_NOARGS},
+ {"restoreDynamics", (PyCFunction)KX_GameObject::sPyRestoreDynamics,METH_NOARGS},
+ {"enableRigidBody", (PyCFunction)KX_GameObject::sPyEnableRigidBody,METH_NOARGS},
+ {"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_NOARGS},
{"applyImpulse", (PyCFunction) KX_GameObject::sPyApplyImpulse, METH_VARARGS},
- {"setCollisionMargin", (PyCFunction) KX_GameObject::sPySetCollisionMargin, METH_VARARGS},
- {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics,METH_VARARGS},
- {"restoreDynamics", (PyCFunction)KX_GameObject::sPyRestoreDynamics,METH_VARARGS},
- {"enableRigidBody", (PyCFunction)KX_GameObject::sPyEnableRigidBody,METH_VARARGS},
- {"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_VARARGS},
- {"getParent", (PyCFunction)KX_GameObject::sPyGetParent,METH_VARARGS},
+ {"setCollisionMargin", (PyCFunction) KX_GameObject::sPySetCollisionMargin, METH_O},
+ {"getParent", (PyCFunction)KX_GameObject::sPyGetParent,METH_NOARGS},
+ {"setParent", (PyCFunction)KX_GameObject::sPySetParent,METH_O},
+ {"removeParent", (PyCFunction)KX_GameObject::sPyRemoveParent,METH_NOARGS},
+ {"getChildren", (PyCFunction)KX_GameObject::sPyGetChildren,METH_NOARGS},
+ {"getChildrenRecursive", (PyCFunction)KX_GameObject::sPyGetChildrenRecursive,METH_NOARGS},
{"getMesh", (PyCFunction)KX_GameObject::sPyGetMesh,METH_VARARGS},
- {"getPhysicsId", (PyCFunction)KX_GameObject::sPyGetPhysicsId,METH_VARARGS},
+ {"getPhysicsId", (PyCFunction)KX_GameObject::sPyGetPhysicsId,METH_NOARGS},
+ {"getPropertyNames", (PyCFunction)KX_GameObject::sPyGetPropertyNames,METH_NOARGS},
+ {"replaceMesh",(PyCFunction) KX_GameObject::sPyReplaceMesh, METH_O},
+ {"endObject",(PyCFunction) KX_GameObject::sPyEndObject, METH_NOARGS},
+ KX_PYMETHODTABLE(KX_GameObject, rayCastTo),
+ KX_PYMETHODTABLE(KX_GameObject, rayCast),
KX_PYMETHODTABLE(KX_GameObject, getDistanceTo),
+ KX_PYMETHODTABLE(KX_GameObject, getVectTo),
{NULL,NULL} //Sentinel
};
@@ -663,19 +1025,40 @@ bool KX_GameObject::ConvertPythonVectorArgs(PyObject* args,
}
*/
-
-PyObject* KX_GameObject::sPySetPosition(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PyReplaceMesh(PyObject* self, PyObject* value)
{
- return ((KX_GameObject*) self)->PySetPosition(self, args, kwds);
+ KX_Scene *scene = KX_GetActiveScene();
+ char* meshname;
+ void* mesh_pt;
+
+ meshname = PyString_AsString(value);
+ if (meshname==NULL) {
+ PyErr_SetString(PyExc_ValueError, "Expected a mesh name");
+ return NULL;
+ }
+ mesh_pt = SCA_ILogicBrick::m_sCurrentLogicManager->GetMeshByName(STR_String(meshname));
+
+ if (mesh_pt==NULL) {
+ PyErr_SetString(PyExc_ValueError, "The mesh name given does not exist");
+ return NULL;
+ }
+ scene->ReplaceMesh(this, (class RAS_MeshObject*)mesh_pt);
+
+ Py_RETURN_NONE;
}
+
+PyObject* KX_GameObject::PyEndObject(PyObject* self)
+{
+
+ KX_Scene *scene = KX_GetActiveScene();
+ scene->DelayedRemoveObject(this);
+ Py_RETURN_NONE;
+
+}
-PyObject* KX_GameObject::PyGetPosition(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PyGetPosition(PyObject* self)
{
return PyObjectFrom(NodeGetWorldPosition());
}
@@ -729,7 +1112,7 @@ PyObject* KX_GameObject::_getattr(const STR_String& attr)
parent->AddRef();
return parent;
}
- Py_Return;
+ Py_RETURN_NONE;
}
if (attr == "visible")
@@ -746,27 +1129,53 @@ PyObject* KX_GameObject::_getattr(const STR_String& attr)
if (attr == "name")
return PyString_FromString(m_name.ReadPtr());
+ if (attr == "timeOffset") {
+ if (m_pSGNode->GetSGParent()->IsSlowParent()) {
+ return PyFloat_FromDouble(static_cast<KX_SlowParentRelation *>(m_pSGNode->GetSGParent()->GetParentRelation())->GetTimeOffset());
+ } else {
+ return PyFloat_FromDouble(0.0);
+ }
+ }
+
_getattr_up(SCA_IObject);
}
int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr method
{
- if (attr == "mass")
+ if (attr == "mass") {
+ PyErr_SetString(PyExc_AttributeError, "attribute \"mass\" is read only");
return 1;
+ }
- if (attr == "parent")
+ if (attr == "parent") {
+ PyErr_SetString(PyExc_AttributeError, "attribute \"mass\" is read only\nUse setParent()");
return 1;
+ }
if (PyInt_Check(value))
{
int val = PyInt_AsLong(value);
if (attr == "visible")
{
- SetVisible(val != 0);
+ SetVisible(val != 0, false);
+ UpdateBuckets(false);
return 0;
}
}
+
+ if (PyFloat_Check(value))
+ {
+ MT_Scalar val = PyFloat_AsDouble(value);
+ if (attr == "timeOffset") {
+ if (m_pSGNode->GetSGParent() && m_pSGNode->GetSGParent()->IsSlowParent()) {
+ static_cast<KX_SlowParentRelation *>(m_pSGNode->GetSGParent()->GetParentRelation())->SetTimeOffset(val);
+ return 0;
+ } else {
+ return 0;
+ }
+ }
+ }
if (PySequence_Check(value))
{
@@ -778,6 +1187,7 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr
if (PyMatTo(value, rot))
{
NodeSetLocalOrientation(rot);
+ NodeUpdateGS(0.f,true);
return 0;
}
return 1;
@@ -790,6 +1200,7 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr
{
rot.setRotation(qrot);
NodeSetLocalOrientation(rot);
+ NodeUpdateGS(0.f,true);
return 0;
}
return 1;
@@ -802,11 +1213,12 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr
{
rot.setEuler(erot);
NodeSetLocalOrientation(rot);
+ NodeUpdateGS(0.f,true);
return 0;
}
return 1;
}
-
+ PyErr_SetString(PyExc_AttributeError, "could not set the orientation from a 3x3 matrix, quaternion or euler sequence");
return 1;
}
@@ -816,6 +1228,7 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr
if (PyVecTo(value, pos))
{
NodeSetLocalPosition(pos);
+ NodeUpdateGS(0.f,true);
return 0;
}
return 1;
@@ -827,6 +1240,7 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr
if (PyVecTo(value, scale))
{
NodeSetLocalScale(scale);
+ NodeUpdateGS(0.f,true);
return 0;
}
return 1;
@@ -842,44 +1256,117 @@ int KX_GameObject::_setattr(const STR_String& attr, PyObject *value) // _setattr
}
}
+ /* Need to have parent settable here too */
+
return SCA_IObject::_setattr(attr, value);
}
-PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self, PyObject* args)
{
// only can get the velocity if we have a physics object connected to us...
- return PyObjectFrom(GetLinearVelocity());
+ int local = 0;
+ if (PyArg_ParseTuple(args,"|i",&local))
+ {
+ return PyObjectFrom(GetLinearVelocity((local!=0)));
+ }
+ else
+ {
+ return NULL;
+ }
}
-
-
-PyObject* KX_GameObject::PySetVisible(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PySetLinearVelocity(PyObject* self, PyObject* args)
{
- int visible = 1;
+ int local = 0;
+ PyObject* pyvect;
- if (PyArg_ParseTuple(args,"i",&visible))
+ if (PyArg_ParseTuple(args,"O|i",&pyvect,&local)) {
+ MT_Vector3 velocity;
+ if (PyVecTo(pyvect, velocity)) {
+ setLinearVelocity(velocity, (local!=0));
+ Py_RETURN_NONE;
+ }
+ }
+ return NULL;
+}
+
+PyObject* KX_GameObject::PyGetAngularVelocity(PyObject* self, PyObject* args)
+{
+ // only can get the velocity if we have a physics object connected to us...
+ int local = 0;
+ if (PyArg_ParseTuple(args,"|i",&local))
{
- MarkVisible(visible!=0);
- m_bVisible = (visible!=0);
+ return PyObjectFrom(GetAngularVelocity((local!=0)));
}
else
{
- return NULL;
+ return NULL;
}
- Py_Return;
+}
+
+PyObject* KX_GameObject::PySetAngularVelocity(PyObject* self, PyObject* args)
+{
+ int local = 0;
+ PyObject* pyvect;
+ if (PyArg_ParseTuple(args,"O|i",&pyvect,&local)) {
+ MT_Vector3 velocity;
+ if (PyVecTo(pyvect, velocity)) {
+ setAngularVelocity(velocity, (local!=0));
+ Py_RETURN_NONE;
+ }
+ }
+ return NULL;
+}
+
+PyObject* KX_GameObject::PySetVisible(PyObject* self, PyObject* args)
+{
+ int visible, recursive = 0;
+ if (!PyArg_ParseTuple(args,"i|i",&visible, &recursive))
+ return NULL;
+
+ SetVisible(visible ? true:false, recursive ? true:false);
+ UpdateBuckets(recursive ? true:false);
+ Py_RETURN_NONE;
+
+}
+
+PyObject* KX_GameObject::PyGetVisible(PyObject* self)
+{
+ return PyInt_FromLong(m_bVisible);
+}
+
+PyObject* KX_GameObject::PyGetState(PyObject* self)
+{
+ int state = 0;
+ state |= GetState();
+ return PyInt_FromLong(state);
+}
+
+PyObject* KX_GameObject::PySetState(PyObject* self, PyObject* value)
+{
+ int state_i = PyInt_AsLong(value);
+ unsigned int state = 0;
+
+ if (state_i == -1 && PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "expected an int bit field");
+ return NULL;
+ }
+
+ state |= state_i;
+ if ((state & ((1<<30)-1)) == 0) {
+ PyErr_SetString(PyExc_AttributeError, "The state bitfield was not between 0 and 30 (1<<0 and 1<<29)");
+ return NULL;
+ }
+ SetState(state);
+
+ Py_RETURN_NONE;
}
-PyObject* KX_GameObject::PyGetVelocity(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PyGetVelocity(PyObject* self, PyObject* args)
{
// only can get the velocity if we have a physics object connected to us...
MT_Vector3 velocity(0.0,0.0,0.0);
@@ -892,6 +1379,9 @@ PyObject* KX_GameObject::PyGetVelocity(PyObject* self,
if (pypos)
PyVecTo(pypos, point);
}
+ else {
+ return NULL;
+ }
if (m_pPhysicsController1)
{
@@ -903,26 +1393,14 @@ PyObject* KX_GameObject::PyGetVelocity(PyObject* self,
-PyObject* KX_GameObject::PyGetMass(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PyGetMass(PyObject* self)
{
- PyObject* pymass = NULL;
-
- float mass = GetPhysicsController()->GetMass();
- pymass = PyFloat_FromDouble(mass);
-
- if (pymass)
- return pymass;
-
- Py_Return;
+ return PyFloat_FromDouble(GetPhysicsController()->GetMass());
}
-PyObject* KX_GameObject::PyGetReactionForce(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PyGetReactionForce(PyObject* self)
{
// only can get the velocity if we have a physics object connected to us...
return PyObjectFrom(GetPhysicsController()->getReactionForce());
@@ -930,32 +1408,25 @@ PyObject* KX_GameObject::PyGetReactionForce(PyObject* self,
-PyObject* KX_GameObject::PyEnableRigidBody(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PyEnableRigidBody(PyObject* self)
{
-
GetPhysicsController()->setRigidBody(true);
- Py_Return;
+ Py_RETURN_NONE;
}
-PyObject* KX_GameObject::PyDisableRigidBody(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PyDisableRigidBody(PyObject* self)
{
GetPhysicsController()->setRigidBody(false);
- Py_Return;
+ Py_RETURN_NONE;
}
-PyObject* KX_GameObject::PyGetParent(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PyGetParent(PyObject* self)
{
KX_GameObject* parent = this->GetParent();
if (parent)
@@ -963,69 +1434,128 @@ PyObject* KX_GameObject::PyGetParent(PyObject* self,
parent->AddRef();
return parent;
}
- Py_Return;
+ Py_RETURN_NONE;
+}
+
+PyObject* KX_GameObject::PySetParent(PyObject* self, PyObject* value)
+{
+ if (!PyObject_TypeCheck(value, &KX_GameObject::Type)) {
+ PyErr_SetString(PyExc_TypeError, "expected a KX_GameObject type");
+ return NULL;
+ }
+
+ // The object we want to set as parent
+ CValue *m_ob = (CValue*)value;
+ KX_GameObject *obj = ((KX_GameObject*)m_ob);
+ KX_Scene *scene = KX_GetActiveScene();
+
+ this->SetParent(scene, obj);
+
+ Py_RETURN_NONE;
}
+PyObject* KX_GameObject::PyRemoveParent(PyObject* self)
+{
+ KX_Scene *scene = KX_GetActiveScene();
+ this->RemoveParent(scene);
+ Py_RETURN_NONE;
+}
-PyObject* KX_GameObject::PyGetMesh(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+static void walk_children(SG_Node* node, CListValue* list, bool recursive)
{
- int mesh = 0;
+ NodeList& children = node->GetSGChildren();
- if (PyArg_ParseTuple(args, "|i", &mesh))
+ for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit)
{
- if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0)
+ SG_Node* childnode = (*childit);
+ CValue* childobj = (CValue*)childnode->GetSGClientObject();
+ if (childobj != NULL) // This is a GameObject
{
- KX_MeshProxy* meshproxy = new KX_MeshProxy(m_meshes[mesh]);
- return meshproxy;
+ // add to the list
+ list->Add(childobj->AddRef());
+ }
+
+ // if the childobj is NULL then this may be an inverse parent link
+ // so a non recursive search should still look down this node.
+ if (recursive || childobj==NULL) {
+ walk_children(childnode, list, recursive);
}
}
- Py_Return;
}
+PyObject* KX_GameObject::PyGetChildren(PyObject* self)
+{
+ CListValue* list = new CListValue();
+ walk_children(m_pSGNode, list, 0);
+ return list;
+}
+PyObject* KX_GameObject::PyGetChildrenRecursive(PyObject* self)
+{
+ CListValue* list = new CListValue();
+ walk_children(m_pSGNode, list, 1);
+ return list;
+}
-
-
-PyObject* KX_GameObject::PySetCollisionMargin(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PyGetMesh(PyObject* self, PyObject* args)
{
- float collisionMargin;
- if (PyArg_ParseTuple(args, "f", &collisionMargin))
+ int mesh = 0;
+
+ if (!PyArg_ParseTuple(args, "|i", &mesh))
+ return NULL; // python sets a simple error
+
+ if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0)
{
- if (m_pPhysicsController1)
- {
- m_pPhysicsController1->setMargin(collisionMargin);
- Py_Return;
- }
+ KX_MeshProxy* meshproxy = new KX_MeshProxy(m_meshes[mesh]);
+ return meshproxy;
+ }
+
+ Py_RETURN_NONE;
+}
+
+
+
+
+PyObject* KX_GameObject::PySetCollisionMargin(PyObject* self, PyObject* value)
+{
+ float collisionMargin = PyFloat_AsDouble(value);
+
+ if (collisionMargin==-1 && PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "expected a float");
+ return NULL;
}
+ if (m_pPhysicsController1)
+ {
+ m_pPhysicsController1->setMargin(collisionMargin);
+ Py_RETURN_NONE;
+ }
+ PyErr_SetString(PyExc_RuntimeError, "This object has no physics controller");
return NULL;
}
-PyObject* KX_GameObject::PyApplyImpulse(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, PyObject* args)
{
PyObject* pyattach;
PyObject* pyimpulse;
+
+ if (!m_pPhysicsController1) {
+ PyErr_SetString(PyExc_RuntimeError, "This object has no physics controller");
+ return NULL;
+ }
+
if (PyArg_ParseTuple(args, "OO", &pyattach, &pyimpulse))
{
MT_Point3 attach;
MT_Vector3 impulse;
- if (m_pPhysicsController1)
+ if (PyVecTo(pyattach, attach) && PyVecTo(pyimpulse, impulse))
{
- if (PyVecTo(pyattach, attach) && PyVecTo(pyimpulse, impulse))
- {
- m_pPhysicsController1->applyImpulse(attach, impulse);
- Py_Return;
- }
+ m_pPhysicsController1->applyImpulse(attach, impulse);
+ Py_RETURN_NONE;
}
}
@@ -1035,102 +1565,109 @@ PyObject* KX_GameObject::PyApplyImpulse(PyObject* self,
-PyObject* KX_GameObject::PySuspendDynamics(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PySuspendDynamics(PyObject* self)
{
- if (m_bSuspendDynamics)
- {
- Py_Return;
- }
-
- if (m_pPhysicsController1)
- {
- m_pPhysicsController1->SuspendDynamics();
- }
- m_bSuspendDynamics = true;
-
- Py_Return;
+ SuspendDynamics();
+ Py_RETURN_NONE;
}
-PyObject* KX_GameObject::PyRestoreDynamics(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PyRestoreDynamics(PyObject* self)
{
-
- if (!m_bSuspendDynamics)
- {
- Py_Return;
- }
-
- if (m_pPhysicsController1)
- {
- m_pPhysicsController1->RestoreDynamics();
- }
- m_bSuspendDynamics = false;
-
- Py_Return;
+ RestoreDynamics();
+ Py_RETURN_NONE;
}
-PyObject* KX_GameObject::PyGetOrientation(PyObject* self,
- PyObject* args,
- PyObject* kwds) //keywords
+PyObject* KX_GameObject::PyGetOrientation(PyObject* self) //keywords
{
return PyObjectFrom(NodeGetWorldOrientation());
}
-PyObject* KX_GameObject::PySetOrientation(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PySetOrientation(PyObject* self, PyObject* value)
{
- PyObject* pylist;
-
- if (PyArg_ParseTuple(args,"O",&pylist))
+ MT_Matrix3x3 matrix;
+ if (PyObject_IsMT_Matrix(value, 3) && PyMatTo(value, matrix))
{
- MT_Matrix3x3 matrix;
- if (PyObject_IsMT_Matrix(pylist, 3) && PyMatTo(pylist, matrix))
- {
- NodeSetLocalOrientation(matrix);
- Py_Return;
- }
+ NodeSetLocalOrientation(matrix);
+ NodeUpdateGS(0.f,true);
+ Py_RETURN_NONE;
+ }
+
+ MT_Quaternion quat;
+ if (PyVecTo(value, quat))
+ {
+ matrix.setRotation(quat);
+ NodeSetLocalOrientation(matrix);
+ NodeUpdateGS(0.f,true);
+ Py_RETURN_NONE;
+ }
+ return NULL;
+}
+
+PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* self, PyObject* args)
+{
+ PyObject* pyvect;
+ int axis = 2; //z axis is the default
+ float fac = 1.0;
- MT_Quaternion quat;
- if (PyVecTo(pylist, quat))
+ if (PyArg_ParseTuple(args,"O|if",&pyvect,&axis, &fac))
+ {
+ MT_Vector3 vect;
+ if (PyVecTo(pyvect, vect))
{
- matrix.setRotation(quat);
- NodeSetLocalOrientation(matrix);
- Py_Return;
+ if (fac<=0.0) Py_RETURN_NONE; // Nothing to do.
+ if (fac> 1.0) fac= 1.0;
+
+ AlignAxisToVect(vect,axis,fac);
+ NodeUpdateGS(0.f,true);
+ Py_RETURN_NONE;
}
}
return NULL;
}
+PyObject* KX_GameObject::PyGetAxisVect(PyObject* self, PyObject* value)
+{
+ MT_Vector3 vect;
+ if (PyVecTo(value, vect))
+ {
+ return PyObjectFrom(NodeGetWorldOrientation() * vect);
+ }
+ return NULL;
+}
-
-PyObject* KX_GameObject::PySetPosition(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PySetPosition(PyObject* self, PyObject* value)
{
MT_Point3 pos;
- if (PyVecArgTo(args, pos))
+ if (PyVecTo(value, pos))
{
NodeSetLocalPosition(pos);
NodeUpdateGS(0.f,true);
- Py_Return;
+ Py_RETURN_NONE;
}
-
+
return NULL;
}
-PyObject* KX_GameObject::PyGetPhysicsId(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_GameObject::PySetWorldPosition(PyObject* self, PyObject* value)
+{
+ MT_Point3 pos;
+ if (PyVecTo(value, pos))
+ {
+ NodeSetWorldPosition(pos);
+ NodeUpdateGS(0.f,true);
+ Py_RETURN_NONE;
+ }
+
+ return NULL;
+}
+
+PyObject* KX_GameObject::PyGetPhysicsId(PyObject* self)
{
KX_IPhysicsController* ctrl = GetPhysicsController();
uint_ptr physid=0;
@@ -1141,6 +1678,11 @@ PyObject* KX_GameObject::PyGetPhysicsId(PyObject* self,
return PyInt_FromLong((long)physid);
}
+PyObject* KX_GameObject::PyGetPropertyNames(PyObject* self)
+{
+ return ConvertKeysToPython();
+}
+
KX_PYMETHODDEF_DOC(KX_GameObject, getDistanceTo,
"getDistanceTo(other): get distance to another point/KX_GameObject")
{
@@ -1152,20 +1694,356 @@ KX_PYMETHODDEF_DOC(KX_GameObject, getDistanceTo,
PyErr_Clear();
PyObject *pyother;
- if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &pyother))
+ KX_GameObject *other;
+ if (PyArg_ParseTuple(args, "O", &pyother) && ConvertPythonToGameObject(pyother, &other, false))
{
- KX_GameObject *other = static_cast<KX_GameObject*>(pyother);
return PyFloat_FromDouble(NodeGetWorldPosition().distance(other->NodeGetWorldPosition()));
}
return NULL;
}
+KX_PYMETHODDEF_DOC(KX_GameObject, getVectTo,
+"getVectTo(other): get vector and the distance to another point/KX_GameObject\n"
+"Returns a 3-tuple with (distance,worldVector,localVector)\n")
+{
+ MT_Point3 toPoint, fromPoint;
+ MT_Vector3 toDir, locToDir;
+ MT_Scalar distance;
+
+ PyObject *returnValue;
+ PyObject *pyother;
+
+ if (!PyVecArgTo(args, toPoint))
+ {
+ PyErr_Clear();
+
+ KX_GameObject *other;
+ if (PyArg_ParseTuple(args, "O", &pyother) && ConvertPythonToGameObject(pyother, &other, false))
+ {
+ toPoint = other->NodeGetWorldPosition();
+ } else
+ {
+ PyErr_SetString(PyExc_TypeError, "Expected a 3D Vector or GameObject type");
+ return NULL;
+ }
+ }
+
+ fromPoint = NodeGetWorldPosition();
+ toDir = toPoint-fromPoint;
+ distance = toDir.length();
+
+ if (MT_fuzzyZero(distance))
+ {
+ //cout << "getVectTo() Error: Null vector!\n";
+ locToDir = toDir = MT_Vector3(0.0,0.0,0.0);
+ distance = 0.0;
+ } else {
+ toDir.normalize();
+ locToDir = toDir * NodeGetWorldOrientation();
+ }
+
+ returnValue = PyTuple_New(3);
+ if (returnValue) { // very unlikely to fail, python sets a memory error here.
+ PyTuple_SET_ITEM(returnValue, 0, PyFloat_FromDouble(distance));
+ PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(toDir));
+ PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(locToDir));
+ }
+ return returnValue;
+}
+
+bool KX_GameObject::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data)
+{
+ KX_GameObject* hitKXObj = client->m_gameobject;
+
+ // if X-ray option is selected, the unwnted objects were not tested, so get here only with true hit
+ // if not, all objects were tested and the front one may not be the correct one.
+ if (m_xray || m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL)
+ {
+ m_pHitObject = hitKXObj;
+ return true;
+ }
+ // return true to stop RayCast::RayTest from looping, the above test was decisive
+ // We would want to loop only if we want to get more than one hit point
+ return true;
+}
+
+/* this function is used to pre-filter the object before casting the ray on them.
+ This is useful for "X-Ray" option when we want to see "through" unwanted object.
+ */
+bool KX_GameObject::NeedRayCast(KX_ClientObjectInfo* client)
+{
+ KX_GameObject* hitKXObj = client->m_gameobject;
+
+ if (client->m_type > KX_ClientObjectInfo::ACTOR)
+ {
+ // Unknown type of object, skip it.
+ // Should not occur as the sensor objects are filtered in RayTest()
+ printf("Invalid client type %d found in ray casting\n", client->m_type);
+ return false;
+ }
+
+ // if X-Ray option is selected, skip object that don't match the criteria as we see through them
+ // if not, test all objects because we don't know yet which one will be on front
+ if (!m_xray || m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL)
+ {
+ return true;
+ }
+ // skip the object
+ return false;
+}
+
+KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo,
+"rayCastTo(other,dist,prop): look towards another point/KX_GameObject and return first object hit within dist that matches prop\n"
+" prop = property name that object must have; can be omitted => detect any object\n"
+" dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to other\n"
+" other = 3-tuple or object reference")
+{
+ MT_Point3 toPoint;
+ PyObject* pyarg;
+ float dist = 0.0f;
+ char *propName = NULL;
+
+ if (!PyArg_ParseTuple(args,"O|fs", &pyarg, &dist, &propName)) {
+ return NULL; // python sets simple error
+ }
+
+ if (!PyVecTo(pyarg, toPoint))
+ {
+ KX_GameObject *other;
+ PyErr_Clear();
+
+ if (ConvertPythonToGameObject(pyarg, &other, false))
+ {
+ toPoint = other->NodeGetWorldPosition();
+ } else
+ {
+ PyErr_SetString(PyExc_TypeError, "the first argument to rayCastTo must be a vector or a KX_GameObject");
+ return NULL;
+ }
+ }
+ MT_Point3 fromPoint = NodeGetWorldPosition();
+ if (dist != 0.0f)
+ {
+ MT_Vector3 toDir = toPoint-fromPoint;
+ toDir.normalize();
+ toPoint = fromPoint + (dist) * toDir;
+ }
+
+ PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment();
+ KX_IPhysicsController *spc = GetPhysicsController();
+ KX_GameObject *parent = GetParent();
+ if (!spc && parent)
+ spc = parent->GetPhysicsController();
+ if (parent)
+ parent->Release();
+
+ m_pHitObject = NULL;
+ if (propName)
+ m_testPropName = propName;
+ else
+ m_testPropName.SetLength(0);
+ KX_RayCast::Callback<KX_GameObject> callback(this,spc);
+ KX_RayCast::RayTest(pe, fromPoint, toPoint, callback);
+
+ if (m_pHitObject)
+ {
+ m_pHitObject->AddRef();
+ return m_pHitObject;
+ }
+ Py_RETURN_NONE;
+}
+
+KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
+ "rayCast(to,from,dist,prop,face,xray,poly): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) of contact point with object within dist that matches prop.\n"
+ " If no hit, return (None,None,None) or (None,None,None,None).\n"
+" to = 3-tuple or object reference for destination of ray (if object, use center of object)\n"
+" from = 3-tuple or object reference for origin of ray (if object, use center of object)\n"
+" Can be None or omitted => start from self object center\n"
+" dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to to\n"
+" prop = property name that object must have; can be omitted => detect any object\n"
+" face = normal option: 1=>return face normal; 0 or omitted => normal is oriented towards origin\n"
+" xray = X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object\n"
+" poly = polygon option: 1=>return value is a 4-tuple and the 4th element is a KX_PolyProxy object\n"
+" which can be None if hit object has no mesh or if there is no hit\n"
+" If 0 or omitted, return value is a 3-tuple\n"
+"Note: The object on which you call this method matters: the ray will ignore it.\n"
+" prop and xray option interact as follow:\n"
+" prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray\n"
+" prop off, xray on : idem\n"
+" prop on, xray off: return closest hit if it matches prop, no hit otherwise\n"
+" prop on, xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray\n")
+{
+ MT_Point3 toPoint;
+ MT_Point3 fromPoint;
+ PyObject* pyto;
+ PyObject* pyfrom = NULL;
+ float dist = 0.0f;
+ char *propName = NULL;
+ KX_GameObject *other;
+ int face=0, xray=0, poly=0;
+
+ if (!PyArg_ParseTuple(args,"O|Ofsiii", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly)) {
+ return NULL; // Python sets a simple error
+ }
+
+ if (!PyVecTo(pyto, toPoint))
+ {
+ PyErr_Clear();
+
+ if (ConvertPythonToGameObject(pyto, &other, false))
+ {
+ toPoint = other->NodeGetWorldPosition();
+ } else
+ {
+ PyErr_SetString(PyExc_TypeError, "the first argument to rayCast must be a vector or a KX_GameObject");
+ return NULL;
+ }
+ }
+ if (!pyfrom || pyfrom == Py_None)
+ {
+ fromPoint = NodeGetWorldPosition();
+ }
+ else if (!PyVecTo(pyfrom, fromPoint))
+ {
+ PyErr_Clear();
+
+ if (ConvertPythonToGameObject(pyfrom, &other, false))
+ {
+ fromPoint = other->NodeGetWorldPosition();
+ } else
+ {
+ PyErr_SetString(PyExc_TypeError, "the second optional argument to rayCast must be a vector or a KX_GameObject");
+ return NULL;
+ }
+ }
+
+ if (dist != 0.0f) {
+ MT_Vector3 toDir = toPoint-fromPoint;
+ if (MT_fuzzyZero(toDir.length2())) {
+ return Py_BuildValue("OOO", Py_None, Py_None, Py_None);
+ }
+ toDir.normalize();
+ toPoint = fromPoint + (dist) * toDir;
+ } else if (MT_fuzzyZero((toPoint-fromPoint).length2())) {
+ return Py_BuildValue("OOO", Py_None, Py_None, Py_None);
+ }
+
+ PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment();
+ KX_IPhysicsController *spc = GetPhysicsController();
+ KX_GameObject *parent = GetParent();
+ if (!spc && parent)
+ spc = parent->GetPhysicsController();
+ if (parent)
+ parent->Release();
+
+ m_pHitObject = NULL;
+ if (propName)
+ m_testPropName = propName;
+ else
+ m_testPropName.SetLength(0);
+ m_xray = xray;
+ // to get the hit results
+ KX_RayCast::Callback<KX_GameObject> callback(this,spc,NULL,face);
+ KX_RayCast::RayTest(pe, fromPoint, toPoint, callback);
+
+ if (m_pHitObject)
+ {
+ PyObject* returnValue = (poly) ? PyTuple_New(4) : PyTuple_New(3);
+ if (returnValue) { // unlikely this would ever fail, if it does python sets an error
+ PyTuple_SET_ITEM(returnValue, 0, m_pHitObject->AddRef());
+ PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(callback.m_hitPoint));
+ PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(callback.m_hitNormal));
+ if (poly)
+ {
+ if (callback.m_hitMesh)
+ {
+ // if this field is set, then we can trust that m_hitPolygon is a valid polygon
+ RAS_Polygon* poly = callback.m_hitMesh->GetPolygon(callback.m_hitPolygon);
+ KX_PolyProxy* polyproxy = new KX_PolyProxy(callback.m_hitMesh, poly);
+ PyTuple_SET_ITEM(returnValue, 3, polyproxy);
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ PyTuple_SET_ITEM(returnValue, 3, Py_None);
+ }
+ }
+ }
+ return returnValue;
+ }
+ // no hit
+ if (poly)
+ return Py_BuildValue("OOOO", Py_None, Py_None, Py_None, Py_None);
+ else
+ return Py_BuildValue("OOO", Py_None, Py_None, Py_None);
+}
+
/* ---------------------------------------------------------------------
* Some stuff taken from the header
* --------------------------------------------------------------------- */
void KX_GameObject::Relink(GEN_Map<GEN_HashedPtr, void*> *map_parameter)
{
- /* intentionally empty ? */
+ // we will relink the sensors and actuators that use object references
+ // if the object is part of the replicated hierarchy, use the new
+ // object reference instead
+ SCA_SensorList& sensorlist = GetSensors();
+ SCA_SensorList::iterator sit;
+ for (sit=sensorlist.begin(); sit != sensorlist.end(); sit++)
+ {
+ (*sit)->Relink(map_parameter);
+ }
+ SCA_ActuatorList& actuatorlist = GetActuators();
+ SCA_ActuatorList::iterator ait;
+ for (ait=actuatorlist.begin(); ait != actuatorlist.end(); ait++)
+ {
+ (*ait)->Relink(map_parameter);
+ }
}
+bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok)
+{
+ if (value==NULL) {
+ PyErr_SetString(PyExc_TypeError, "Error in ConvertPythonToGameObject, python pointer NULL, should never happen");
+ *object = NULL;
+ return false;
+ }
+
+ if (value==Py_None) {
+ *object = NULL;
+
+ if (py_none_ok) {
+ return true;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Expected KX_GameObject or a string for a name of a KX_GameObject, None is invalid");
+ return false;
+ }
+ return (py_none_ok ? true : false);
+ }
+
+ if (PyString_Check(value)) {
+ *object = (KX_GameObject *)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String( PyString_AsString(value) ));
+
+ if (*object) {
+ return true;
+ } else {
+ PyErr_SetString(PyExc_ValueError, "Requested name did not match any KX_GameObject");
+ return false;
+ }
+ }
+
+ if (PyObject_TypeCheck(value, &KX_GameObject::Type)) {
+ *object = static_cast<KX_GameObject*>(value);
+ return true;
+ }
+
+ *object = NULL;
+
+ if (py_none_ok) {
+ PyErr_SetString(PyExc_TypeError, "Expect a KX_GameObject, a string or None");
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Expect a KX_GameObject or a string");
+ }
+
+ return false;
+}
diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h
index c82ee9cfdab..20b15787d27 100644
--- a/source/gameengine/Ketsji/KX_GameObject.h
+++ b/source/gameengine/Ketsji/KX_GameObject.h
@@ -44,17 +44,21 @@
#include "MT_CmMatrix4x4.h"
#include "GEN_Map.h"
#include "GEN_HashedPtr.h"
-
-#define KX_FIXED_FRAME_PER_SEC 25.0f
-#define KX_FIXED_SEC_PER_FRAME (1.0f / KX_FIXED_FRAME_PER_SEC)
+#include "KX_Scene.h"
+#include "KX_KetsjiEngine.h" /* for m_anim_framerate */
+#include "KX_IPhysicsController.h" /* for suspend/resume */
+#include "DNA_object_types.h"
+#include "SCA_LogicManager.h" /* for ConvertPythonToGameObject to search object names */
#define KX_OB_DYNAMIC 1
//Forward declarations.
struct KX_ClientObjectInfo;
+class KX_RayCast;
class RAS_MeshObject;
class KX_IPhysicsController;
-
+class PHY_IPhysicsEnvironment;
+struct Object;
/**
* KX_GameObject is the main class for dynamic objects.
@@ -68,17 +72,28 @@ protected:
KX_ClientObjectInfo* m_pClient_info;
STR_String m_name;
STR_String m_text;
+ int m_layer;
std::vector<RAS_MeshObject*> m_meshes;
+ struct Object* m_pBlenderObject;
+ struct Object* m_pBlenderGroupObject;
bool m_bSuspendDynamics;
bool m_bUseObjectColor;
+ bool m_bIsNegativeScaling;
MT_Vector4 m_objectColor;
- // Is this object set to be visible? Only useful for the
- // visibility subsystem right now.
- bool m_bVisible;
+ // visible = user setting
+ // culled = while rendering, depending on camera
+ bool m_bVisible;
+ bool m_bCulled;
KX_IPhysicsController* m_pPhysicsController1;
+ // used for ray casting
+ PHY_IPhysicsEnvironment* m_pPhysicsEnvironment;
+ STR_String m_testPropName;
+ bool m_xray;
+ KX_GameObject* m_pHitObject;
+
SG_Node* m_pSGNode;
MT_CmMatrix4x4 m_OpenGL_4x4Matrix;
@@ -125,6 +140,15 @@ public:
GetParent(
);
+ /**
+ * Sets the parent of this object to a game object
+ */
+ void SetParent(KX_Scene *scene, KX_GameObject *obj);
+
+ /**
+ * Removes the parent of this object to a game object
+ */
+ void RemoveParent(KX_Scene *scene);
/**
* Construct a game object. This class also inherits the
@@ -235,8 +259,42 @@ public:
/**
* Return the linear velocity of the game object.
*/
- MT_Vector3
+ MT_Vector3
GetLinearVelocity(
+ bool local=false
+ );
+
+ /**
+ * Return the linear velocity of a given point in world coordinate
+ * but relative to center of object ([0,0,0]=center of object)
+ */
+ MT_Vector3
+ GetVelocity(
+ const MT_Point3& position
+ );
+
+ /**
+ * Return the mass of the object
+ */
+ MT_Scalar
+ GetMass();
+
+ /**
+ * Return the angular velocity of the game object.
+ */
+ MT_Vector3
+ GetAngularVelocity(
+ bool local=false
+ );
+
+ /**
+ * Align the object to a given normal.
+ */
+ void
+ AlignAxisToVect(
+ const MT_Vector3& vect,
+ int axis = 2,
+ float fac = 1.0
);
/**
@@ -259,6 +317,19 @@ public:
/**
+ * @return a pointer to the physics environment in use during the game, for rayCasting
+ */
+ PHY_IPhysicsEnvironment* GetPhysicsEnvironment()
+ {
+ return m_pPhysicsEnvironment;
+ }
+
+ void SetPhysicsEnvironment(PHY_IPhysicsEnvironment* physicsEnvironment)
+ {
+ m_pPhysicsEnvironment = physicsEnvironment;
+ }
+
+ /**
* @return a pointer to the physics controller owned by this class.
*/
@@ -270,6 +341,14 @@ public:
m_pPhysicsController1 = physicscontroller;
}
+ virtual class RAS_Deformer* GetDeformer()
+ {
+ return 0;
+ }
+ virtual void SetDeformer(class RAS_Deformer* deformer)
+ {
+
+ }
/**
* @section Coordinate system manipulation functions
@@ -283,6 +362,9 @@ public:
void NodeSetRelativeScale( const MT_Vector3& scale );
+ // adapt local position so that world position is set to desired position
+ void NodeSetWorldPosition(const MT_Point3& trans);
+
void
NodeUpdateGS(
double time,
@@ -320,6 +402,37 @@ public:
}
/**
+ * @section blender object accessor functions.
+ */
+
+ struct Object* GetBlenderObject( )
+ {
+ return m_pBlenderObject;
+ }
+
+ void SetBlenderObject( struct Object* obj)
+ {
+ m_pBlenderObject = obj;
+ }
+
+ struct Object* GetBlenderGroupObject( )
+ {
+ return m_pBlenderGroupObject;
+ }
+
+ void SetBlenderGroupObject( struct Object* obj)
+ {
+ m_pBlenderGroupObject = obj;
+ }
+
+ bool IsDupliGroup()
+ {
+ return (m_pBlenderObject &&
+ (m_pBlenderObject->transflag & OB_DUPLIGROUP) &&
+ m_pBlenderObject->dup_group != NULL) ? true : false;
+ }
+
+ /**
* Set the Scene graph node for this game object.
* warning - it is your responsibility to make sure
* all controllers look at this new node. You must
@@ -337,7 +450,18 @@ public:
{
return m_bDyna;
}
-
+
+ /**
+ * Check if this object has a vertex parent relationship
+ */
+ bool IsVertexParent( )
+ {
+ return (m_pSGNode && m_pSGNode->GetSGParent() && m_pSGNode->GetSGParent()->IsVertexParent());
+ }
+
+ bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
+ bool NeedRayCast(KX_ClientObjectInfo* client);
+
/**
* @section Physics accessors for this node.
@@ -408,20 +532,29 @@ public:
);
/**
+ * Function to set IPO option at start of IPO
+ */
+ void
+ InitIPO(
+ bool ipo_as_force,
+ bool ipo_add,
+ bool ipo_local
+ );
+
+ /**
* Odd function to update an ipo. ???
*/
void
UpdateIPO(
float curframetime,
- bool recurse,
- bool ipo_as_force,
- bool force_ipo_local
+ bool recurse
);
/**
* Updates Material Ipo data
*/
void
UpdateMaterialData(
+ dword matname_hash,
MT_Vector4 rgba,
MT_Vector3 specrgb,
MT_Scalar hard,
@@ -434,18 +567,23 @@ public:
/**
* @section Mesh accessor functions.
*/
+
+ /**
+ * Update buckets to indicate that there is a new
+ * user of this object's meshes.
+ */
+ void
+ AddMeshUser(
+ );
/**
- * Run through the meshes associated with this
- * object and bucketize them. See RAS_Mesh for
- * more details on this function. Interesting to
- * note that polygon bucketizing seems to happen on a per
- * object basis. Which may explain why there is such
- * a big performance gain when all static objects
- * are joined into 1.
+ * Update buckets with data about the mesh after
+ * creating or duplicating the object, changing
+ * visibility, object color, .. .
*/
void
- Bucketize(
+ UpdateBuckets(
+ bool recursive
);
/**
@@ -506,42 +644,74 @@ public:
ResetDebugColor(
);
- /**
- * Set the visibility of the meshes associated with this
- * object.
+ /**
+ * Was this object marked visible? (only for the explicit
+ * visibility system).
*/
- void
- MarkVisible(
- bool visible
+ bool
+ GetVisible(
+ void
);
- /**
- * Set the visibility according to the visibility flag.
+ /**
+ * Set visibility flag of this object
*/
- void
- MarkVisible(
void
+ SetVisible(
+ bool b,
+ bool recursive
);
/**
- * Was this object marked visible? (only for the ewxplicit
- * visibility system).
+ * Was this object culled?
*/
bool
- GetVisible(
+ GetCulled(
void
);
/**
- * Set visibility flag of this object
+ * Set culled flag of this object
*/
void
- SetVisible(
- bool b
+ SetCulled(
+ bool c
);
+ /**
+ * Change the layer of the object (when it is added in another layer
+ * than the original layer)
+ */
+ void
+ SetLayer(
+ int l
+ );
+
+ /**
+ * Get the object layer
+ */
+ int
+ GetLayer(
+ void
+ );
/**
+ * Get the negative scaling state
+ */
+ bool
+ IsNegativeScaling(
+ void
+ ) { return m_bIsNegativeScaling; }
+
+ /**
+ * Is this a light?
+ */
+ virtual bool
+ IsLight(
+ void
+ ) { return false; }
+
+ /**
* @section Logic bubbling methods.
*/
@@ -555,6 +725,32 @@ public:
*/
void Resume(void);
+ void SuspendDynamics(void) {
+ if (m_bSuspendDynamics)
+ {
+ return;
+ }
+
+ if (m_pPhysicsController1)
+ {
+ m_pPhysicsController1->SuspendDynamics();
+ }
+ m_bSuspendDynamics = true;
+ }
+
+ void RestoreDynamics(void) {
+ if (!m_bSuspendDynamics)
+ {
+ return;
+ }
+
+ if (m_pPhysicsController1)
+ {
+ m_pPhysicsController1->RestoreDynamics();
+ }
+ m_bSuspendDynamics = false;
+ }
+
KX_ClientObjectInfo* getClientInfo() { return m_pClient_info; }
/**
* @section Python interface functions.
@@ -573,39 +769,45 @@ public:
PyObject *value
); // _setattr method
- PyObject*
- PySetPosition(
- PyObject* self,
- PyObject* args,
- PyObject* kwds
- );
-
- static
- PyObject*
- sPySetPosition(
- PyObject* self,
- PyObject* args,
- PyObject* kwds
- );
-
- KX_PYMETHOD(KX_GameObject,GetPosition);
- KX_PYMETHOD(KX_GameObject,GetLinearVelocity);
- KX_PYMETHOD(KX_GameObject,GetVelocity);
- KX_PYMETHOD(KX_GameObject,GetMass);
- KX_PYMETHOD(KX_GameObject,GetReactionForce);
- KX_PYMETHOD(KX_GameObject,GetOrientation);
- KX_PYMETHOD(KX_GameObject,SetOrientation);
- KX_PYMETHOD(KX_GameObject,SetVisible);
- KX_PYMETHOD(KX_GameObject,SuspendDynamics);
- KX_PYMETHOD(KX_GameObject,RestoreDynamics);
- KX_PYMETHOD(KX_GameObject,EnableRigidBody);
- KX_PYMETHOD(KX_GameObject,DisableRigidBody);
- KX_PYMETHOD(KX_GameObject,ApplyImpulse);
- KX_PYMETHOD(KX_GameObject,SetCollisionMargin);
- KX_PYMETHOD(KX_GameObject,GetMesh);
- KX_PYMETHOD(KX_GameObject,GetParent);
- KX_PYMETHOD(KX_GameObject,GetPhysicsId);
+ KX_PYMETHOD_NOARGS(KX_GameObject,GetPosition);
+ KX_PYMETHOD_O(KX_GameObject,SetPosition);
+ KX_PYMETHOD_O(KX_GameObject,SetWorldPosition);
+ KX_PYMETHOD_VARARGS(KX_GameObject,GetLinearVelocity);
+ KX_PYMETHOD_VARARGS(KX_GameObject,SetLinearVelocity);
+ KX_PYMETHOD_VARARGS(KX_GameObject,GetAngularVelocity);
+ KX_PYMETHOD_VARARGS(KX_GameObject,SetAngularVelocity);
+ KX_PYMETHOD_VARARGS(KX_GameObject,GetVelocity);
+ KX_PYMETHOD_NOARGS(KX_GameObject,GetMass);
+ KX_PYMETHOD_NOARGS(KX_GameObject,GetReactionForce);
+ KX_PYMETHOD_NOARGS(KX_GameObject,GetOrientation);
+ KX_PYMETHOD_O(KX_GameObject,SetOrientation);
+ KX_PYMETHOD_NOARGS(KX_GameObject,GetVisible);
+ KX_PYMETHOD_VARARGS(KX_GameObject,SetVisible);
+ KX_PYMETHOD_NOARGS(KX_GameObject,GetState);
+ KX_PYMETHOD_O(KX_GameObject,SetState);
+ KX_PYMETHOD_VARARGS(KX_GameObject,AlignAxisToVect);
+ KX_PYMETHOD_O(KX_GameObject,GetAxisVect);
+ KX_PYMETHOD_NOARGS(KX_GameObject,SuspendDynamics);
+ KX_PYMETHOD_NOARGS(KX_GameObject,RestoreDynamics);
+ KX_PYMETHOD_NOARGS(KX_GameObject,EnableRigidBody);
+ KX_PYMETHOD_NOARGS(KX_GameObject,DisableRigidBody);
+ KX_PYMETHOD_VARARGS(KX_GameObject,ApplyImpulse);
+ KX_PYMETHOD_O(KX_GameObject,SetCollisionMargin);
+ KX_PYMETHOD_NOARGS(KX_GameObject,GetParent);
+ KX_PYMETHOD_O(KX_GameObject,SetParent);
+ KX_PYMETHOD_NOARGS(KX_GameObject,RemoveParent);
+ KX_PYMETHOD_NOARGS(KX_GameObject,GetChildren);
+ KX_PYMETHOD_NOARGS(KX_GameObject,GetChildrenRecursive);
+ KX_PYMETHOD_VARARGS(KX_GameObject,GetMesh);
+ KX_PYMETHOD_NOARGS(KX_GameObject,GetPhysicsId);
+ KX_PYMETHOD_NOARGS(KX_GameObject,GetPropertyNames);
+ KX_PYMETHOD_O(KX_GameObject,ReplaceMesh);
+ KX_PYMETHOD_NOARGS(KX_GameObject,EndObject);
+ KX_PYMETHOD_DOC(KX_GameObject,rayCastTo);
+ KX_PYMETHOD_DOC(KX_GameObject,rayCast);
KX_PYMETHOD_DOC(KX_GameObject,getDistanceTo);
+ KX_PYMETHOD_DOC(KX_GameObject,getVectTo);
+
private :
/**
@@ -623,5 +825,8 @@ private :
};
+/* utility conversion function */
+bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok);
+
#endif //__KX_GAMEOBJECT
diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.cpp b/source/gameengine/Ketsji/KX_IPO_SGController.cpp
index bb4b75c6c4a..67d54cf0b0b 100644
--- a/source/gameengine/Ketsji/KX_IPO_SGController.cpp
+++ b/source/gameengine/Ketsji/KX_IPO_SGController.cpp
@@ -48,20 +48,24 @@ typedef unsigned long uint_ptr;
#include "KX_ScalarInterpolator.h"
#include "KX_GameObject.h"
#include "KX_IPhysicsController.h"
+#include "DNA_ipo_types.h"
+#include "BLI_arithb.h"
// All objects should start on frame 1! Will we ever need an object to
// start on another frame, the 1.0 should change.
KX_IpoSGController::KX_IpoSGController()
-: m_modify_position(false),
- m_modify_orientation(false),
- m_modify_scaling(false),
- m_ipo_as_force(false),
- m_force_ipo_acts_local(false),
+: m_ipo_as_force(false),
+ m_ipo_add(false),
+ m_ipo_local(false),
m_modified(true),
- m_ipotime(1.0)
+ m_ipo_start_initialized(false),
+ m_ipotime(1.0),
+ m_ipo_start_euler(0.0,0.0,0.0),
+ m_ipo_euler_initialized(false)
{
m_game_object = NULL;
-
+ for (int i=0; i < KX_MAX_IPO_CHANNELS; i++)
+ m_ipo_channels_active[i] = false;
}
@@ -74,8 +78,23 @@ void KX_IpoSGController::SetOption(
m_ipo_as_force = (value != 0);
m_modified = true;
break;
- case SG_CONTR_IPO_FORCES_ACT_LOCAL:
- m_force_ipo_acts_local = (value != 0);
+ case SG_CONTR_IPO_IPO_ADD:
+ m_ipo_add = (value != 0);
+ m_modified = true;
+ break;
+ case SG_CONTR_IPO_RESET:
+ if (m_ipo_start_initialized && value) {
+ m_ipo_start_initialized = false;
+ m_modified = true;
+ }
+ break;
+ case SG_CONTR_IPO_LOCAL:
+ if (value/* && ((SG_Node*)m_pObject)->GetSGParent() == NULL*/) {
+ // only accept local Ipo if the object has no parent
+ m_ipo_local = true;
+ } else {
+ m_ipo_local = false;
+ }
m_modified = true;
break;
default:
@@ -112,35 +131,200 @@ bool KX_IpoSGController::Update(double currentTime)
}
SG_Spatial* ob = (SG_Spatial*)m_pObject;
-
- if (m_modify_position) {
- if (m_ipo_as_force) {
-
- if (m_game_object && ob) {
- m_game_object->GetPhysicsController()->ApplyForce(m_force_ipo_acts_local ?
+
+ //initialization on the first frame of the IPO
+ if (! m_ipo_start_initialized && currentTime > 0.0) {
+ m_ipo_start_point = ob->GetLocalPosition();
+ m_ipo_start_orient = ob->GetLocalOrientation();
+ m_ipo_start_scale = ob->GetLocalScale();
+ m_ipo_start_initialized = true;
+ if (!m_ipo_euler_initialized) {
+ // do it only once to avoid angle discontinuities
+ m_ipo_start_orient.getEuler(m_ipo_start_euler[0], m_ipo_start_euler[1], m_ipo_start_euler[2]);
+ m_ipo_euler_initialized = true;
+ }
+ }
+
+ //modifies position?
+ if (m_ipo_channels_active[OB_LOC_X] || m_ipo_channels_active[OB_LOC_Y] || m_ipo_channels_active[OB_LOC_Z] || m_ipo_channels_active[OB_DLOC_X] || m_ipo_channels_active[OB_DLOC_Y] || m_ipo_channels_active[OB_DLOC_Z])
+ {
+ if (m_ipo_as_force == true)
+ {
+ if (m_game_object && ob && m_game_object->GetPhysicsController())
+ {
+ m_game_object->GetPhysicsController()->ApplyForce(m_ipo_local ?
ob->GetWorldOrientation() * m_ipo_xform.GetPosition() :
m_ipo_xform.GetPosition(), false);
}
-
- } else {
- ob->SetLocalPosition(m_ipo_xform.GetPosition());
+ }
+ else
+ {
+ // Local ipo should be defined with the object position at (0,0,0)
+ // Local transform is applied to the object based on initial position
+ MT_Point3 newPosition(0.0,0.0,0.0);
+
+ if (!m_ipo_add)
+ newPosition = ob->GetLocalPosition();
+ //apply separate IPO channels if there is any data in them
+ //Loc and dLoc act by themselves or are additive
+ //LocX and dLocX
+ if (m_ipo_channels_active[OB_LOC_X]) {
+ newPosition[0] = (m_ipo_channels_active[OB_DLOC_X] ? m_ipo_xform.GetPosition()[0] + m_ipo_xform.GetDeltaPosition()[0] : m_ipo_xform.GetPosition()[0]);
+ }
+ else if (m_ipo_channels_active[OB_DLOC_X] && m_ipo_start_initialized) {
+ newPosition[0] = (((!m_ipo_add)?m_ipo_start_point[0]:0.0) + m_ipo_xform.GetDeltaPosition()[0]);
+ }
+ //LocY and dLocY
+ if (m_ipo_channels_active[OB_LOC_Y]) {
+ newPosition[1] = (m_ipo_channels_active[OB_DLOC_Y] ? m_ipo_xform.GetPosition()[1] + m_ipo_xform.GetDeltaPosition()[1] : m_ipo_xform.GetPosition()[1]);
+ }
+ else if (m_ipo_channels_active[OB_DLOC_Y] && m_ipo_start_initialized) {
+ newPosition[1] = (((!m_ipo_add)?m_ipo_start_point[1]:0.0) + m_ipo_xform.GetDeltaPosition()[1]);
+ }
+ //LocZ and dLocZ
+ if (m_ipo_channels_active[OB_LOC_Z]) {
+ newPosition[2] = (m_ipo_channels_active[OB_DLOC_Z] ? m_ipo_xform.GetPosition()[2] + m_ipo_xform.GetDeltaPosition()[2] : m_ipo_xform.GetPosition()[2]);
+ }
+ else if (m_ipo_channels_active[OB_DLOC_Z] && m_ipo_start_initialized) {
+ newPosition[2] = (((!m_ipo_add)?m_ipo_start_point[2]:0.0) + m_ipo_xform.GetDeltaPosition()[2]);
+ }
+ if (m_ipo_add) {
+ if (m_ipo_local)
+ newPosition = m_ipo_start_point + m_ipo_start_scale*(m_ipo_start_orient*newPosition);
+ else
+ newPosition = m_ipo_start_point + newPosition;
+ }
+ ob->SetLocalPosition(newPosition);
}
}
- if (m_modify_orientation) {
+ //modifies orientation?
+ if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z] || m_ipo_channels_active[OB_DROT_X] || m_ipo_channels_active[OB_DROT_Y] || m_ipo_channels_active[OB_DROT_Z]) {
if (m_ipo_as_force) {
if (m_game_object && ob) {
- m_game_object->ApplyTorque(m_force_ipo_acts_local ?
+ m_game_object->ApplyTorque(m_ipo_local ?
ob->GetWorldOrientation() * m_ipo_xform.GetEulerAngles() :
m_ipo_xform.GetEulerAngles(), false);
}
+ } else if (m_ipo_add) {
+ if (m_ipo_start_initialized) {
+ double yaw=0, pitch=0, roll=0; //delta Euler angles
- } else {
- ob->SetLocalOrientation(MT_Matrix3x3(m_ipo_xform.GetEulerAngles()));
+ //RotX and dRotX
+ if (m_ipo_channels_active[OB_ROT_X])
+ yaw += m_ipo_xform.GetEulerAngles()[0];
+ if (m_ipo_channels_active[OB_DROT_X])
+ yaw += m_ipo_xform.GetDeltaEulerAngles()[0];
+
+ //RotY dRotY
+ if (m_ipo_channels_active[OB_ROT_Y])
+ pitch += m_ipo_xform.GetEulerAngles()[1];
+ if (m_ipo_channels_active[OB_DROT_Y])
+ pitch += m_ipo_xform.GetDeltaEulerAngles()[1];
+
+ //RotZ and dRotZ
+ if (m_ipo_channels_active[OB_ROT_Z])
+ roll += m_ipo_xform.GetEulerAngles()[2];
+ if (m_ipo_channels_active[OB_DROT_Z])
+ roll += m_ipo_xform.GetDeltaEulerAngles()[2];
+
+ MT_Matrix3x3 rotation(MT_Vector3(yaw, pitch, roll));
+ if (m_ipo_local)
+ rotation = m_ipo_start_orient * rotation;
+ else
+ rotation = rotation * m_ipo_start_orient;
+ ob->SetLocalOrientation(rotation);
+ }
+ } else if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z]) {
+ if (m_ipo_euler_initialized) {
+ // assume all channel absolute
+ // All 3 channels should be specified but if they are not, we will take
+ // the value at the start of the game to avoid angle sign reversal
+ double yaw=m_ipo_start_euler[0], pitch=m_ipo_start_euler[1], roll=m_ipo_start_euler[2];
+
+ //RotX and dRotX
+ if (m_ipo_channels_active[OB_ROT_X]) {
+ yaw = (m_ipo_channels_active[OB_DROT_X] ? (m_ipo_xform.GetEulerAngles()[0] + m_ipo_xform.GetDeltaEulerAngles()[0]) : m_ipo_xform.GetEulerAngles()[0] );
+ }
+ else if (m_ipo_channels_active[OB_DROT_X]) {
+ yaw += m_ipo_xform.GetDeltaEulerAngles()[0];
+ }
+
+ //RotY dRotY
+ if (m_ipo_channels_active[OB_ROT_Y]) {
+ pitch = (m_ipo_channels_active[OB_DROT_Y] ? (m_ipo_xform.GetEulerAngles()[1] + m_ipo_xform.GetDeltaEulerAngles()[1]) : m_ipo_xform.GetEulerAngles()[1] );
+ }
+ else if (m_ipo_channels_active[OB_DROT_Y]) {
+ pitch += m_ipo_xform.GetDeltaEulerAngles()[1];
+ }
+
+ //RotZ and dRotZ
+ if (m_ipo_channels_active[OB_ROT_Z]) {
+ roll = (m_ipo_channels_active[OB_DROT_Z] ? (m_ipo_xform.GetEulerAngles()[2] + m_ipo_xform.GetDeltaEulerAngles()[2]) : m_ipo_xform.GetEulerAngles()[2] );
+ }
+ else if (m_ipo_channels_active[OB_DROT_Z]) {
+ roll += m_ipo_xform.GetDeltaEulerAngles()[2];
+ }
+ ob->SetLocalOrientation(MT_Vector3(yaw, pitch, roll));
+ }
+ } else if (m_ipo_start_initialized) {
+ // only DROT, treat as Add
+ double yaw=0, pitch=0, roll=0; //delta Euler angles
+
+ //dRotX
+ if (m_ipo_channels_active[OB_DROT_X])
+ yaw = m_ipo_xform.GetDeltaEulerAngles()[0];
+
+ //dRotY
+ if (m_ipo_channels_active[OB_DROT_Y])
+ pitch = m_ipo_xform.GetDeltaEulerAngles()[1];
+
+ //dRotZ
+ if (m_ipo_channels_active[OB_DROT_Z])
+ roll = m_ipo_xform.GetDeltaEulerAngles()[2];
+
+ // dRot are always local
+ MT_Matrix3x3 rotation(MT_Vector3(yaw, pitch, roll));
+ rotation = m_ipo_start_orient * rotation;
+ ob->SetLocalOrientation(rotation);
+ }
+ }
+ //modifies scale?
+ if (m_ipo_channels_active[OB_SIZE_X] || m_ipo_channels_active[OB_SIZE_Y] || m_ipo_channels_active[OB_SIZE_Z] || m_ipo_channels_active[OB_DSIZE_X] || m_ipo_channels_active[OB_DSIZE_Y] || m_ipo_channels_active[OB_DSIZE_Z]) {
+ //default is no scale change
+ MT_Vector3 newScale(1.0,1.0,1.0);
+ if (!m_ipo_add)
+ newScale = ob->GetLocalScale();
+
+ if (m_ipo_channels_active[OB_SIZE_X]) {
+ newScale[0] = (m_ipo_channels_active[OB_DSIZE_X] ? (m_ipo_xform.GetScaling()[0] + m_ipo_xform.GetDeltaScaling()[0]) : m_ipo_xform.GetScaling()[0]);
+ }
+ else if (m_ipo_channels_active[OB_DSIZE_X] && m_ipo_start_initialized) {
+ newScale[0] = (m_ipo_xform.GetDeltaScaling()[0] + ((!m_ipo_add)?m_ipo_start_scale[0]:0.0));
+ }
+
+ //RotY dRotY
+ if (m_ipo_channels_active[OB_SIZE_Y]) {
+ newScale[1] = (m_ipo_channels_active[OB_DSIZE_Y] ? (m_ipo_xform.GetScaling()[1] + m_ipo_xform.GetDeltaScaling()[1]): m_ipo_xform.GetScaling()[1]);
+ }
+ else if (m_ipo_channels_active[OB_DSIZE_Y] && m_ipo_start_initialized) {
+ newScale[1] = (m_ipo_xform.GetDeltaScaling()[1] + ((!m_ipo_add)?m_ipo_start_scale[1]:0.0));
}
+
+ //RotZ and dRotZ
+ if (m_ipo_channels_active[OB_SIZE_Z]) {
+ newScale[2] = (m_ipo_channels_active[OB_DSIZE_Z] ? (m_ipo_xform.GetScaling()[2] + m_ipo_xform.GetDeltaScaling()[2]) : m_ipo_xform.GetScaling()[2]);
+ }
+ else if (m_ipo_channels_active[OB_DSIZE_Z] && m_ipo_start_initialized) {
+ newScale[2] = (m_ipo_xform.GetDeltaScaling()[2] + ((!m_ipo_add)?m_ipo_start_scale[2]:1.0));
+ }
+
+ if (m_ipo_add) {
+ newScale = m_ipo_start_scale * newScale;
+ }
+
+ ob->SetLocalScale(newScale);
}
- if (m_modify_scaling)
- ob->SetLocalScale(m_ipo_xform.GetScaling());
m_modified=false;
}
diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.h b/source/gameengine/Ketsji/KX_IPO_SGController.h
index a010e8e3e6c..031b74294ce 100644
--- a/source/gameengine/Ketsji/KX_IPO_SGController.h
+++ b/source/gameengine/Ketsji/KX_IPO_SGController.h
@@ -35,27 +35,49 @@
#include "KX_IPOTransform.h"
#include "KX_IInterpolator.h"
+#define KX_MAX_IPO_CHANNELS 19 //note- [0] is not used
+
class KX_IpoSGController : public SG_Controller
{
KX_IPOTransform m_ipo_xform;
T_InterpolatorList m_interpolators;
- /* Why not bools? */
- short m_modify_position : 1;
- short m_modify_orientation : 1;
- short m_modify_scaling : 1;
+
+ /** Flag for each IPO channel that can be applied to a game object */
+ bool m_ipo_channels_active[KX_MAX_IPO_CHANNELS];
/** Interpret the ipo as a force rather than a displacement? */
bool m_ipo_as_force;
- /** Ipo-as-force acts in local rather than in global coordinates? */
- bool m_force_ipo_acts_local;
+ /** Add Ipo curve to current loc/rot/scale */
+ bool m_ipo_add;
+ /** Ipo must be applied in local coordinate rather than in global coordinates (used for force and Add mode)*/
+ bool m_ipo_local;
+
/** Were settings altered since the last update? */
bool m_modified;
/** Local time of this ipo.*/
double m_ipotime;
+ /** Location of the object when the IPO is first fired (for local transformations) */
+ class MT_Point3 m_ipo_start_point;
+
+ /** Orientation of the object when the IPO is first fired (for local transformations) */
+ class MT_Matrix3x3 m_ipo_start_orient;
+
+ /** Scale of the object when the IPO is first fired (for local transformations) */
+ class MT_Vector3 m_ipo_start_scale;
+
+ /** if IPO initial position has been set for local normal IPO */
+ bool m_ipo_start_initialized;
+
+ /** Euler angles at the start of the game, needed for incomplete ROT Ipo curves */
+ class MT_Vector3 m_ipo_start_euler;
+
+ /** true is m_ipo_start_euler has been initialized */
+ bool m_ipo_euler_initialized;
+
/** A reference to the original game object. */
class KX_GameObject* m_game_object;
@@ -77,16 +99,12 @@ public:
/** Set reference to the corresponding game object. */
void SetGameObject(class KX_GameObject*);
- void SetModifyPosition(bool modifypos) {
- m_modify_position=modifypos;
- }
- void SetModifyOrientation(bool modifyorient) {
- m_modify_orientation=modifyorient;
- }
- void SetModifyScaling(bool modifyscale) {
- m_modify_scaling=modifyscale;
+ void SetIPOChannelActive(int index, bool value) {
+ //indexes found in makesdna\DNA_ipo_types.h
+ m_ipo_channels_active[index] = value;
}
+
KX_IPOTransform& GetIPOTransform()
{
return m_ipo_xform;
@@ -102,3 +120,4 @@ public:
#endif //__IPO_SGCONTROLLER_H
+
diff --git a/source/gameengine/Ketsji/KX_IPhysicsController.h b/source/gameengine/Ketsji/KX_IPhysicsController.h
index 009db40d3e8..4ea283e9f98 100644
--- a/source/gameengine/Ketsji/KX_IPhysicsController.h
+++ b/source/gameengine/Ketsji/KX_IPhysicsController.h
@@ -64,20 +64,22 @@ public:
virtual void ApplyTorque(const MT_Vector3& torque,bool local)=0;
virtual void ApplyForce(const MT_Vector3& force,bool local)=0;
virtual MT_Vector3 GetLinearVelocity()=0;
+ virtual MT_Vector3 GetAngularVelocity()=0;
virtual MT_Vector3 GetVelocity(const MT_Point3& pos)=0;
virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local)=0;
virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local)=0;
virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) = 0;
virtual void getOrientation(MT_Quaternion& orn)=0;
- virtual void setOrientation(const MT_Quaternion& orn)=0;
+ virtual void setOrientation(const MT_Matrix3x3& orn)=0;
+ //virtual void setOrientation(const MT_Quaternion& orn)=0;
virtual void setPosition(const MT_Point3& pos)=0;
virtual void setScaling(const MT_Vector3& scaling)=0;
virtual MT_Scalar GetMass()=0;
virtual MT_Vector3 getReactionForce()=0;
virtual void setRigidBody(bool rigid)=0;
- virtual void SuspendDynamics()=0;
+ virtual void SuspendDynamics(bool ghost=false)=0;
virtual void RestoreDynamics()=0;
virtual SG_Controller* GetReplica(class SG_Node* destnode)=0;
@@ -86,7 +88,11 @@ public:
m_bDyna = isDynamic;
}
+ bool IsDyna(void) {
+ return m_bDyna;
+ }
+ virtual MT_Scalar GetRadius()=0;
virtual void SetSumoTransform(bool nondynaonly)=0;
// todo: remove next line !
virtual void SetSimulatedTime(double time)=0;
diff --git a/source/gameengine/Ketsji/KX_ISceneConverter.h b/source/gameengine/Ketsji/KX_ISceneConverter.h
index cb749801827..3709fa8c784 100644
--- a/source/gameengine/Ketsji/KX_ISceneConverter.h
+++ b/source/gameengine/Ketsji/KX_ISceneConverter.h
@@ -32,6 +32,8 @@
#include "STR_String.h"
#include "KX_Python.h"
+struct Scene;
+
class KX_ISceneConverter
{
@@ -52,6 +54,8 @@ public:
class RAS_IRenderTools* rendertools,
class RAS_ICanvas* canvas)=0;
+ virtual void RemoveScene(class KX_Scene *scene)=0;
+
virtual void SetAlwaysUseExpandFraming(bool to_what) = 0;
virtual void SetNewFileName(const STR_String& filename) = 0;
@@ -72,6 +76,11 @@ public:
virtual void SetMaterials(bool val) =0;
virtual bool GetMaterials()=0;
+ // use blender glsl materials
+ virtual void SetGLSLMaterials(bool val) =0;
+ virtual bool GetGLSLMaterials()=0;
+
+ virtual struct Scene* GetBlenderSceneForName(const STR_String& name)=0;
};
#endif //__KX_ISCENECONVERTER_H
diff --git a/source/gameengine/Ketsji/KX_IpoActuator.cpp b/source/gameengine/Ketsji/KX_IpoActuator.cpp
index 3af1316ba5d..f5e17118ffb 100644
--- a/source/gameengine/Ketsji/KX_IpoActuator.cpp
+++ b/source/gameengine/Ketsji/KX_IpoActuator.cpp
@@ -37,6 +37,7 @@
#include "KX_IpoActuator.h"
#include "KX_GameObject.h"
+#include "FloatValue.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -59,49 +60,17 @@ STR_String KX_IpoActuator::S_KX_ACT_IPO_FROM_PROP_STRING = "FromProp";
/* ------------------------------------------------------------------------- */
/* Native functions */
/* ------------------------------------------------------------------------- */
-/** Another poltergeist? This seems to be a very transient class... */
-class CIpoAction : public CAction
-{
- float m_curtime;
- bool m_recurse;
- KX_GameObject* m_gameobj;
- bool m_ipo_as_force;
- bool m_force_ipo_local;
-
-public:
- CIpoAction(KX_GameObject* gameobj,
- float curtime,
- bool recurse,
- bool ipo_as_force,
- bool force_ipo_local) :
- m_curtime(curtime) ,
- m_recurse(recurse),
- m_gameobj(gameobj),
- m_ipo_as_force(ipo_as_force),
- m_force_ipo_local(force_ipo_local)
- {
- /* intentionally empty */
- };
-
- virtual void Execute() const
- {
- m_gameobj->UpdateIPO(
- m_curtime,
- m_recurse,
- m_ipo_as_force,
- m_force_ipo_local);
- };
-
-};
KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj,
const STR_String& propname,
+ const STR_String& framePropname,
float starttime,
float endtime,
bool recurse,
int acttype,
bool ipo_as_force,
- bool force_ipo_local,
+ bool ipo_add,
+ bool ipo_local,
PyTypeObject* T)
: SCA_IActuator(gameobj,T),
m_bNegativeEvent(false),
@@ -111,8 +80,10 @@ KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj,
m_localtime(starttime),
m_direction(1),
m_propname(propname),
+ m_framepropname(framePropname),
m_ipo_as_force(ipo_as_force),
- m_force_ipo_local(force_ipo_local),
+ m_ipo_add(ipo_add),
+ m_ipo_local(ipo_local),
m_type((IpoActType)acttype)
{
m_starttime = -2.0*fabs(m_endframe - m_startframe) - 1.0;
@@ -160,18 +131,17 @@ bool KX_IpoActuator::ClampLocalTime()
void KX_IpoActuator::SetStartTime(float curtime)
{
- float direction = m_startframe < m_endframe ? 1.0 : -1.0;
+ float direction = m_startframe < m_endframe ? 1.0f : -1.0f;
- curtime = curtime - KX_KetsjiEngine::GetSuspendedDelta();
if (m_direction > 0)
- m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_FIXED_FRAME_PER_SEC;
+ m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate();
else
- m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_FIXED_FRAME_PER_SEC;
+ m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate();
}
void KX_IpoActuator::SetLocalTime(float curtime)
{
- float delta_time = ((curtime - m_starttime) - KX_KetsjiEngine::GetSuspendedDelta())*KX_FIXED_FRAME_PER_SEC;
+ float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate();
// negative delta_time is caused by floating point inaccuracy
// perhaps the inaccuracy could be reduced a bit
@@ -195,36 +165,28 @@ bool KX_IpoActuator::Update(double curtime, bool frame)
// maybe there are events for us in the queue !
bool bNegativeEvent = false;
int numevents = 0;
+ bool bIpoStart = false;
+
+ curtime -= KX_KetsjiEngine::GetSuspendedDelta();
if (frame)
{
numevents = m_events.size();
- for (vector<CValue*>::iterator i=m_events.end(); !(i==m_events.begin());)
- {
- --i;
- if ((*i)->GetNumber() == 0.0f)
- bNegativeEvent = true;
-
- (*i)->Release();
- }
- m_events.clear();
-
- if (m_type != KX_ACT_IPO_PLAY)
- {
- if (bNegativeEvent)
- RemoveAllEvents();
- }
+ bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
}
- double start_smaller_then_end = ( m_startframe < m_endframe ? 1.0 : -1.0);
+ float start_smaller_then_end = ( m_startframe < m_endframe ? 1.0f : -1.0f);
bool result=true;
if (!bNegativeEvent)
{
- if (m_starttime < -2.0*start_smaller_then_end*(m_endframe - m_startframe))
+ if (m_starttime < -2.0f*start_smaller_then_end*(m_endframe - m_startframe))
{
- m_starttime = curtime - KX_KetsjiEngine::GetSuspendedDelta();
+ // start for all Ipo, initial start for LOOP_STOP
+ m_starttime = curtime;
m_bIpoPlaying = true;
+ bIpoStart = true;
}
}
@@ -235,17 +197,10 @@ bool KX_IpoActuator::Update(double curtime, bool frame)
{
// Check if playing forwards. result = ! finished
- if (!bNegativeEvent)
- {
- if (start_smaller_then_end > 0.0)
- result = (m_localtime < m_endframe && !(m_localtime == m_startframe && bNegativeEvent));
- else
- result = (m_localtime > m_endframe && !(m_localtime == m_startframe && bNegativeEvent));
- }
+ if (start_smaller_then_end > 0.f)
+ result = (m_localtime < m_endframe && m_bIpoPlaying);
else
- {
- result = (m_bIpoPlaying && (m_localtime < m_endframe));
- }
+ result = (m_localtime > m_endframe && m_bIpoPlaying);
if (result)
{
@@ -253,18 +208,13 @@ bool KX_IpoActuator::Update(double curtime, bool frame)
/* Perform clamping */
ClampLocalTime();
-
- CIpoAction ipoaction(
- (KX_GameObject*)GetParent(),
- m_localtime,
- m_recurse,
- m_ipo_as_force,
- m_force_ipo_local);
- GetParent()->Execute(ipoaction);
+
+ if (bIpoStart)
+ ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local);
+ ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse);
} else
{
m_localtime=m_startframe;
- SetStartTime(curtime);
m_direction=1;
}
break;
@@ -272,7 +222,7 @@ bool KX_IpoActuator::Update(double curtime, bool frame)
case KX_ACT_IPO_PINGPONG:
{
result = true;
- if (bNegativeEvent && ((m_localtime == m_startframe )|| (m_localtime == m_endframe)))
+ if (bNegativeEvent && !m_bIpoPlaying)
result = false;
else
SetLocalTime(curtime);
@@ -283,39 +233,35 @@ bool KX_IpoActuator::Update(double curtime, bool frame)
m_direction = -m_direction;
}
- CIpoAction ipoaction(
- (KX_GameObject*) GetParent(),
- m_localtime,
- m_recurse,
- m_ipo_as_force,
- m_force_ipo_local);
- GetParent()->Execute(ipoaction);
+ if (bIpoStart && m_direction > 0)
+ ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local);
+ ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse);
break;
}
case KX_ACT_IPO_FLIPPER:
{
- result = !(bNegativeEvent && (m_localtime == m_startframe));
+ if (bNegativeEvent && !m_bIpoPlaying)
+ result = false;
if (numevents)
{
+ float oldDirection = m_direction;
if (bNegativeEvent)
m_direction = -1;
else
m_direction = 1;
- SetStartTime(curtime);
+ if (m_direction != oldDirection)
+ // changing direction, reset start time
+ SetStartTime(curtime);
}
SetLocalTime(curtime);
if (ClampLocalTime() && m_localtime == m_startframe)
result = false;
-
- CIpoAction ipoaction(
- (KX_GameObject*) GetParent(),
- m_localtime,
- m_recurse,
- m_ipo_as_force,
- m_force_ipo_local);
- GetParent()->Execute(ipoaction);
+
+ if (bIpoStart)
+ ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local);
+ ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse);
break;
}
@@ -329,18 +275,26 @@ bool KX_IpoActuator::Update(double curtime, bool frame)
m_bNegativeEvent = false;
numevents = 0;
}
- SetStartTime(curtime);
+ if (!m_bIpoPlaying)
+ {
+ // Ipo was stopped, make sure we will restart from where it stopped
+ SetStartTime(curtime);
+ if (!bNegativeEvent)
+ // positive signal will restart the Ipo
+ m_bIpoPlaying = true;
+ }
+
} // fall through to loopend, and quit the ipo animation immediatly
}
case KX_ACT_IPO_LOOPEND:
{
if (numevents){
- if (bNegativeEvent){
+ if (bNegativeEvent && m_bIpoPlaying){
m_bNegativeEvent = true;
}
}
- if (bNegativeEvent && m_localtime == m_startframe){
+ if (bNegativeEvent && !m_bIpoPlaying){
result = false;
}
else
@@ -353,8 +307,12 @@ bool KX_IpoActuator::Update(double curtime, bool frame)
if (!m_bNegativeEvent){
/* Perform wraparound */
SetLocalTime(curtime);
- m_localtime = m_startframe + fmod(m_localtime, m_startframe - m_endframe);
+ if (start_smaller_then_end > 0.f)
+ m_localtime = m_startframe + fmod(m_localtime - m_startframe, m_endframe - m_startframe);
+ else
+ m_localtime = m_startframe - fmod(m_startframe - m_localtime, m_startframe - m_endframe);
SetStartTime(curtime);
+ bIpoStart = true;
}
else
{
@@ -366,13 +324,9 @@ bool KX_IpoActuator::Update(double curtime, bool frame)
}
}
- CIpoAction ipoaction(
- (KX_GameObject*) GetParent(),
- m_localtime,
- m_recurse,
- m_ipo_as_force,
- m_force_ipo_local);
- GetParent()->Execute(ipoaction);
+ if (m_bIpoPlaying && bIpoStart)
+ ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local);
+ ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse);
break;
}
@@ -392,14 +346,9 @@ bool KX_IpoActuator::Update(double curtime, bool frame)
{
m_localtime = propval->GetNumber();
- CIpoAction ipoaction(
- (KX_GameObject*) GetParent(),
- m_localtime,
- m_recurse,
- m_ipo_as_force,
- m_force_ipo_local);
- GetParent()->Execute(ipoaction);
-
+ if (bIpoStart)
+ ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local);
+ ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse);
} else
{
result = false;
@@ -410,9 +359,26 @@ bool KX_IpoActuator::Update(double curtime, bool frame)
default:
result = false;
}
-
- if (!result && m_type != KX_ACT_IPO_LOOPSTOP)
- m_starttime = -2.0*start_smaller_then_end*(m_endframe - m_startframe) - 1.0;
+
+ /* Set the property if its defined */
+ if (m_framepropname[0] != '\0') {
+ CValue* propowner = GetParent();
+ CValue* oldprop = propowner->GetProperty(m_framepropname);
+ CValue* newval = new CFloatValue(m_localtime);
+ if (oldprop) {
+ oldprop->SetValue(newval);
+ } else {
+ propowner->SetProperty(m_framepropname, newval);
+ }
+ newval->Release();
+ }
+
+ if (!result)
+ {
+ if (m_type != KX_ACT_IPO_LOOPSTOP)
+ m_starttime = -2.0*start_smaller_then_end*(m_endframe - m_startframe) - 1.0;
+ m_bIpoPlaying = false;
+ }
return result;
}
@@ -474,30 +440,20 @@ PyParentObject KX_IpoActuator::Parents[] = {
};
PyMethodDef KX_IpoActuator::Methods[] = {
- {"set", (PyCFunction) KX_IpoActuator::sPySet,
- METH_VARARGS, Set_doc},
- {"setProperty", (PyCFunction) KX_IpoActuator::sPySetProperty,
- METH_VARARGS, SetProperty_doc},
- {"setStart", (PyCFunction) KX_IpoActuator::sPySetStart,
- METH_VARARGS, SetStart_doc},
- {"getStart", (PyCFunction) KX_IpoActuator::sPyGetStart,
- METH_VARARGS, GetStart_doc},
- {"setEnd", (PyCFunction) KX_IpoActuator::sPySetEnd,
- METH_VARARGS, SetEnd_doc},
- {"getEnd", (PyCFunction) KX_IpoActuator::sPyGetEnd,
- METH_VARARGS, GetEnd_doc},
- {"setIpoAsForce", (PyCFunction) KX_IpoActuator::sPySetIpoAsForce,
- METH_VARARGS, SetIpoAsForce_doc},
- {"getIpoAsForce", (PyCFunction) KX_IpoActuator::sPyGetIpoAsForce,
- METH_VARARGS, GetIpoAsForce_doc},
- {"setType", (PyCFunction) KX_IpoActuator::sPySetType,
- METH_VARARGS, SetType_doc},
- {"getType", (PyCFunction) KX_IpoActuator::sPyGetType,
- METH_VARARGS, GetType_doc},
- {"setForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPySetForceIpoActsLocal,
- METH_VARARGS, SetForceIpoActsLocal_doc},
- {"getForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPyGetForceIpoActsLocal,
- METH_VARARGS, GetForceIpoActsLocal_doc},
+ {"set", (PyCFunction) KX_IpoActuator::sPySet, METH_VARARGS, (PY_METHODCHAR)Set_doc},
+ {"setProperty", (PyCFunction) KX_IpoActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc},
+ {"setStart", (PyCFunction) KX_IpoActuator::sPySetStart, METH_VARARGS, (PY_METHODCHAR)SetStart_doc},
+ {"getStart", (PyCFunction) KX_IpoActuator::sPyGetStart, METH_NOARGS, (PY_METHODCHAR)GetStart_doc},
+ {"setEnd", (PyCFunction) KX_IpoActuator::sPySetEnd, METH_VARARGS, (PY_METHODCHAR)SetEnd_doc},
+ {"getEnd", (PyCFunction) KX_IpoActuator::sPyGetEnd, METH_NOARGS, (PY_METHODCHAR)GetEnd_doc},
+ {"setIpoAsForce", (PyCFunction) KX_IpoActuator::sPySetIpoAsForce, METH_VARARGS, (PY_METHODCHAR)SetIpoAsForce_doc},
+ {"getIpoAsForce", (PyCFunction) KX_IpoActuator::sPyGetIpoAsForce, METH_NOARGS, (PY_METHODCHAR)GetIpoAsForce_doc},
+ {"setIpoAdd", (PyCFunction) KX_IpoActuator::sPySetIpoAdd, METH_VARARGS, (PY_METHODCHAR)SetIpoAdd_doc},
+ {"getIpoAdd", (PyCFunction) KX_IpoActuator::sPyGetIpoAdd, METH_NOARGS, (PY_METHODCHAR)GetIpoAdd_doc},
+ {"setType", (PyCFunction) KX_IpoActuator::sPySetType, METH_VARARGS, (PY_METHODCHAR)SetType_doc},
+ {"getType", (PyCFunction) KX_IpoActuator::sPyGetType, METH_NOARGS, (PY_METHODCHAR)GetType_doc},
+ {"setForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPySetForceIpoActsLocal, METH_VARARGS, (PY_METHODCHAR)SetForceIpoActsLocal_doc},
+ {"getForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPyGetForceIpoActsLocal, METH_NOARGS, (PY_METHODCHAR)GetForceIpoActsLocal_doc},
{NULL,NULL} //Sentinel
};
@@ -508,12 +464,12 @@ PyObject* KX_IpoActuator::_getattr(const STR_String& attr) {
/* set --------------------------------------------------------------------- */
-char KX_IpoActuator::Set_doc[] =
-"set(mode, startframe, endframe, force?)\n"
-"\t - mode: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n"
+const char KX_IpoActuator::Set_doc[] =
+"set(type, startframe, endframe, mode?)\n"
+"\t - type: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n"
"\t - startframe: first frame to use (int)\n"
"\t - endframe : last frame to use (int)\n"
-"\t - force? : interpret this ipo as a force? (KX_TRUE, KX_FALSE)"
+"\t - mode? : special mode (0=normal, 1=interpret location as force, 2=additive)"
"\tSet the properties of the actuator.\n";
PyObject* KX_IpoActuator::PySet(PyObject* self,
PyObject* args,
@@ -540,7 +496,8 @@ PyObject* KX_IpoActuator::PySet(PyObject* self,
m_type = modenum;
m_startframe = startFrame;
m_endframe = stopFrame;
- m_ipo_as_force = PyArgToBool(forceToggle);
+ m_ipo_as_force = forceToggle == 1;
+ m_ipo_add = forceToggle == 2;
break;
default:
; /* error */
@@ -550,7 +507,7 @@ PyObject* KX_IpoActuator::PySet(PyObject* self,
}
/* set property ----------------------------------------------------------- */
-char KX_IpoActuator::SetProperty_doc[] =
+const char KX_IpoActuator::SetProperty_doc[] =
"setProperty(propname)\n"
"\t - propname: name of the property (string)\n"
"\tSet the property to be used in FromProp mode.\n";
@@ -570,7 +527,7 @@ PyObject* KX_IpoActuator::PySetProperty(PyObject* self,
}
/* 4. setStart: */
-char KX_IpoActuator::SetStart_doc[] =
+const char KX_IpoActuator::SetStart_doc[] =
"setStart(frame)\n"
"\t - frame: first frame to use (int)\n"
"\tSet the frame from which the ipo starts playing.\n";
@@ -587,17 +544,15 @@ PyObject* KX_IpoActuator::PySetStart(PyObject* self,
Py_Return;
}
/* 5. getStart: */
-char KX_IpoActuator::GetStart_doc[] =
+const char KX_IpoActuator::GetStart_doc[] =
"getStart()\n"
"\tReturns the frame from which the ipo starts playing.\n";
-PyObject* KX_IpoActuator::PyGetStart(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_IpoActuator::PyGetStart(PyObject* self) {
return PyFloat_FromDouble(m_startframe);
}
/* 6. setEnd: */
-char KX_IpoActuator::SetEnd_doc[] =
+const char KX_IpoActuator::SetEnd_doc[] =
"setEnd(frame)\n"
"\t - frame: last frame to use (int)\n"
"\tSet the frame at which the ipo stops playing.\n";
@@ -614,17 +569,15 @@ PyObject* KX_IpoActuator::PySetEnd(PyObject* self,
Py_Return;
}
/* 7. getEnd: */
-char KX_IpoActuator::GetEnd_doc[] =
+const char KX_IpoActuator::GetEnd_doc[] =
"getEnd()\n"
"\tReturns the frame at which the ipo stops playing.\n";
-PyObject* KX_IpoActuator::PyGetEnd(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_IpoActuator::PyGetEnd(PyObject* self) {
return PyFloat_FromDouble(m_endframe);
}
/* 6. setIpoAsForce: */
-char KX_IpoActuator::SetIpoAsForce_doc[] =
+const char KX_IpoActuator::SetIpoAsForce_doc[] =
"setIpoAsForce(force?)\n"
"\t - force? : interpret this ipo as a force? (KX_TRUE, KX_FALSE)\n"
"\tSet whether to interpret the ipo as a force rather than a displacement.\n";
@@ -638,21 +591,49 @@ PyObject* KX_IpoActuator::PySetIpoAsForce(PyObject* self,
}
m_ipo_as_force = PyArgToBool(boolArg);
+ if (m_ipo_as_force)
+ m_ipo_add = false;
Py_Return;
}
/* 7. getIpoAsForce: */
-char KX_IpoActuator::GetIpoAsForce_doc[] =
+const char KX_IpoActuator::GetIpoAsForce_doc[] =
"getIpoAsForce()\n"
"\tReturns whether to interpret the ipo as a force rather than a displacement.\n";
-PyObject* KX_IpoActuator::PyGetIpoAsForce(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_IpoActuator::PyGetIpoAsForce(PyObject* self) {
return BoolToPyArg(m_ipo_as_force);
}
+/* 6. setIpoAsForce: */
+const char KX_IpoActuator::SetIpoAdd_doc[] =
+"setIpoAdd(add?)\n"
+"\t - add? : add flag (KX_TRUE, KX_FALSE)\n"
+"\tSet whether to interpret the ipo as additive rather than absolute.\n";
+PyObject* KX_IpoActuator::PySetIpoAdd(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int boolArg;
+
+ if (!PyArg_ParseTuple(args, "i", &boolArg)) {
+ return NULL;
+ }
+
+ m_ipo_add = PyArgToBool(boolArg);
+ if (m_ipo_add)
+ m_ipo_as_force = false;
+
+ Py_Return;
+}
+/* 7. getIpoAsForce: */
+const char KX_IpoActuator::GetIpoAdd_doc[] =
+"getIpoAsAdd()\n"
+"\tReturns whether to interpret the ipo as additive rather than absolute.\n";
+PyObject* KX_IpoActuator::PyGetIpoAdd(PyObject* self) {
+ return BoolToPyArg(m_ipo_add);
+}
+
/* 8. setType: */
-char KX_IpoActuator::SetType_doc[] =
+const char KX_IpoActuator::SetType_doc[] =
"setType(mode)\n"
"\t - mode: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n"
"\tSet the operation mode of the actuator.\n";
@@ -673,17 +654,15 @@ PyObject* KX_IpoActuator::PySetType(PyObject* self,
Py_Return;
}
/* 9. getType: */
-char KX_IpoActuator::GetType_doc[] =
+const char KX_IpoActuator::GetType_doc[] =
"getType()\n"
"\tReturns the operation mode of the actuator.\n";
-PyObject* KX_IpoActuator::PyGetType(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_IpoActuator::PyGetType(PyObject* self) {
return PyInt_FromLong(m_type);
}
/* 10. setForceIpoActsLocal: */
-char KX_IpoActuator::SetForceIpoActsLocal_doc[] =
+const char KX_IpoActuator::SetForceIpoActsLocal_doc[] =
"setForceIpoActsLocal(local?)\n"
"\t - local? : Apply the ipo-as-force in the object's local\n"
"\t coordinates? (KX_TRUE, KX_FALSE)\n"
@@ -698,19 +677,17 @@ PyObject* KX_IpoActuator::PySetForceIpoActsLocal(PyObject* self,
return NULL;
}
- m_force_ipo_local = PyArgToBool(boolArg);
+ m_ipo_local = PyArgToBool(boolArg);
Py_Return;
}
/* 11. getForceIpoActsLocal: */
-char KX_IpoActuator::GetForceIpoActsLocal_doc[] =
+const char KX_IpoActuator::GetForceIpoActsLocal_doc[] =
"getForceIpoActsLocal()\n"
"\tReturn whether to apply the force in the object's local\n"
"\tcoordinates rather than the world global coordinates.\n";
-PyObject* KX_IpoActuator::PyGetForceIpoActsLocal(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
- return BoolToPyArg(m_force_ipo_local);
+PyObject* KX_IpoActuator::PyGetForceIpoActsLocal(PyObject* self) {
+ return BoolToPyArg(m_ipo_local);
}
diff --git a/source/gameengine/Ketsji/KX_IpoActuator.h b/source/gameengine/Ketsji/KX_IpoActuator.h
index 79e8daa3f87..8e5baed0530 100644
--- a/source/gameengine/Ketsji/KX_IpoActuator.h
+++ b/source/gameengine/Ketsji/KX_IpoActuator.h
@@ -72,11 +72,17 @@ protected:
/** Name of the property (only used in from_prop mode). */
STR_String m_propname;
+ /** Name of the property where we write the current frame number */
+ STR_String m_framepropname;
+
/** Interpret the ipo as a force? */
bool m_ipo_as_force;
- /** Apply a force-ipo locally? */
- bool m_force_ipo_local;
+ /** Add Ipo curve to current loc/rot/scale */
+ bool m_ipo_add;
+
+ /** The Ipo curve is applied in local coordinates */
+ bool m_ipo_local;
bool m_bIpoPlaying;
@@ -108,12 +114,14 @@ public:
KX_IpoActuator(SCA_IObject* gameobj,
const STR_String& propname,
+ const STR_String& framePropname,
float starttime,
float endtime,
bool recurse,
int acttype,
bool ipo_as_force,
- bool force_ipo_local,
+ bool ipo_add,
+ bool ipo_local,
PyTypeObject* T=&Type);
virtual ~KX_IpoActuator() {};
@@ -139,15 +147,17 @@ public:
KX_PYMETHOD_DOC(KX_IpoActuator,SetProperty);
/* KX_PYMETHOD_DOC(KX_IpoActuator,SetKey2Key); */
KX_PYMETHOD_DOC(KX_IpoActuator,SetStart);
- KX_PYMETHOD_DOC(KX_IpoActuator,GetStart);
+ KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetStart);
KX_PYMETHOD_DOC(KX_IpoActuator,SetEnd);
- KX_PYMETHOD_DOC(KX_IpoActuator,GetEnd);
+ KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetEnd);
KX_PYMETHOD_DOC(KX_IpoActuator,SetIpoAsForce);
- KX_PYMETHOD_DOC(KX_IpoActuator,GetIpoAsForce);
+ KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetIpoAsForce);
+ KX_PYMETHOD_DOC(KX_IpoActuator,SetIpoAdd);
+ KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetIpoAdd);
KX_PYMETHOD_DOC(KX_IpoActuator,SetType);
- KX_PYMETHOD_DOC(KX_IpoActuator,GetType);
+ KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetType);
KX_PYMETHOD_DOC(KX_IpoActuator,SetForceIpoActsLocal);
- KX_PYMETHOD_DOC(KX_IpoActuator,GetForceIpoActsLocal);
+ KX_PYMETHOD_DOC_NOARGS(KX_IpoActuator,GetForceIpoActsLocal);
};
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
index 64bfa90d4d6..8bcda4479e1 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -55,6 +55,7 @@
#include "KX_Scene.h"
#include "MT_CmMatrix4x4.h"
#include "KX_Camera.h"
+#include "KX_Light.h"
#include "KX_PythonInit.h"
#include "KX_PyConstraintBinding.h"
#include "PHY_IPhysicsEnvironment.h"
@@ -71,6 +72,7 @@
#include "KX_TimeCategoryLogger.h"
#include "RAS_FramingManager.h"
+#include "stdio.h"
// If define: little test for Nzc: guarded drawing. If the canvas is
// not valid, skip rendering this frame.
@@ -91,9 +93,10 @@ const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = {
};
double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE;
-
+double KX_KetsjiEngine::m_anim_framerate = 25.0;
double KX_KetsjiEngine::m_suspendedtime = 0.0;
double KX_KetsjiEngine::m_suspendeddelta = 0.0;
+double KX_KetsjiEngine::m_average_framerate = 0.0;
/**
@@ -116,7 +119,6 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_bInitialized(false),
m_activecam(0),
m_bFixedTime(false),
- m_game2ipo(false),
m_firstframe(true),
@@ -133,6 +135,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_overrideCam(false),
m_overrideCamUseOrtho(false),
+ m_overrideCamNear(0.0),
+ m_overrideCamFar(0.0),
m_stereo(false),
m_curreye(0),
@@ -146,6 +150,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_showBackground(false),
m_show_debug_properties(false),
+ m_game2ipo(false),
+
// Default behavior is to hide the cursor every frame.
m_hideCursor(false),
@@ -229,7 +235,10 @@ void KX_KetsjiEngine::SetRasterizer(RAS_IRasterizer* rasterizer)
}
-
+/*
+ * At the moment the GameLogic module is imported into 'pythondictionary' after this function is called.
+ * if this function ever changes to assign a copy, make sure the game logic module is imported into this dictionary before hand.
+ */
void KX_KetsjiEngine::SetPythonDictionary(PyObject* pythondictionary)
{
MT_assert(pythondictionary);
@@ -269,30 +278,73 @@ void KX_KetsjiEngine::StartEngine(bool clearIpo)
}
-bool KX_KetsjiEngine::BeginFrame()
+void KX_KetsjiEngine::ClearFrame()
{
- bool result = false;
+ // clear unless we're drawing overlapping stereo
+ if(m_rasterizer->InterlacedStereo() &&
+ m_rasterizer->GetEye() == RAS_IRasterizer::RAS_STEREO_RIGHTEYE)
+ return;
- RAS_Rect vp;
- KX_Scene* firstscene = *m_scenes.begin();
- const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
+ // clear the viewports with the background color of the first scene
+ bool doclear = false;
+ KX_SceneList::iterator sceneit;
+ RAS_Rect clearvp, area, viewport;
- // set the area used for rendering
- m_rasterizer->SetRenderArea();
+ for (sceneit = m_scenes.begin(); sceneit != m_scenes.end(); sceneit++)
+ {
+ KX_Scene* scene = *sceneit;
+ //const RAS_FrameSettings &framesettings = scene->GetFramingType();
+ list<class KX_Camera*>* cameras = scene->GetCameras();
+
+ list<KX_Camera*>::iterator it;
+ for(it = cameras->begin(); it != cameras->end(); it++)
+ {
+ GetSceneViewport(scene, (*it), area, viewport);
+
+ if(!doclear) {
+ clearvp = viewport;
+ doclear = true;
+ }
+ else {
+ if(viewport.GetLeft() < clearvp.GetLeft())
+ clearvp.SetLeft(viewport.GetLeft());
+ if(viewport.GetBottom() < clearvp.GetBottom())
+ clearvp.SetBottom(viewport.GetBottom());
+ if(viewport.GetRight() > clearvp.GetRight())
+ clearvp.SetRight(viewport.GetRight());
+ if(viewport.GetTop() > clearvp.GetTop())
+ clearvp.SetTop(viewport.GetTop());
+
+ }
+ }
+ }
+
+ if(doclear) {
+ KX_Scene* firstscene = *m_scenes.begin();
+ SetBackGround(firstscene->GetWorldInfo());
+
+ m_canvas->SetViewPort(clearvp.GetLeft(), clearvp.GetBottom(),
+ clearvp.GetRight(), clearvp.GetTop());
+ m_rasterizer->ClearColorBuffer();
+ }
+}
- RAS_FramingManager::ComputeViewport(framesettings, m_canvas->GetDisplayArea(), vp);
+bool KX_KetsjiEngine::BeginFrame()
+{
+ // set the area used for rendering (stereo can assign only a subset)
+ m_rasterizer->SetRenderArea();
if (m_canvas->BeginDraw())
{
- result = true;
+ ClearFrame();
+
+ m_rasterizer->BeginFrame(m_drawingmode , m_kxsystem->GetTimeInSeconds());
+ m_rendertools->BeginFrame(m_rasterizer);
- m_canvas->SetViewPort(vp.GetLeft(), vp.GetBottom(), vp.GetRight(), vp.GetTop());
- SetBackGround( firstscene->GetWorldInfo() );
- m_rasterizer->BeginFrame( m_drawingmode , m_kxsystem->GetTimeInSeconds());
- m_rendertools->BeginFrame( m_rasterizer);
+ return true;
}
- return result;
+ return false;
}
@@ -304,6 +356,12 @@ void KX_KetsjiEngine::EndFrame()
{
RenderDebugProperties();
}
+
+ m_average_framerate = m_logger->GetAverage();
+ if (m_average_framerate < 1e-6)
+ m_average_framerate = 1e-6;
+ m_average_framerate = 1.0/m_average_framerate;
+
// Go to next profiling measurement, time spend after this call is shown in the next frame.
m_logger->NextMeasurement(m_kxsystem->GetTimeInSeconds());
@@ -315,8 +373,6 @@ void KX_KetsjiEngine::EndFrame()
m_canvas->EndDraw();
-
-
}
//#include "PIL_time.h"
@@ -414,7 +470,7 @@ else
m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
// set Python hooks for each scene
PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
- PHY_SetActiveScene(scene);
+ KX_SetActiveScene(scene);
scene->GetPhysicsEnvironment()->endFrame();
@@ -512,7 +568,7 @@ else
// set Python hooks for each scene
PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment());
- PHY_SetActiveScene(scene);
+ KX_SetActiveScene(scene);
m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
scene->UpdateParents(m_clockTime);
@@ -595,7 +651,7 @@ void KX_KetsjiEngine::Render()
);
}
// clear the -whole- viewport
- m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER);
+ m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
}
m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE);
@@ -613,25 +669,25 @@ void KX_KetsjiEngine::Render()
// pass the scene's worldsettings to the rasterizer
SetWorldSettings(scene->GetWorldInfo());
+ // shadow buffers
+ RenderShadowBuffers(scene);
+
// Avoid drawing the scene with the active camera twice when it's viewport is enabled
- if(!cam->GetViewport())
+ if(cam && !cam->GetViewport())
{
if (scene->IsClearingZBuffer())
m_rasterizer->ClearDepthBuffer();
m_rendertools->SetAuxilaryClientInfo(scene);
- //Initialize scene viewport.
- SetupRenderFrame(scene, cam);
-
// do the rendering
RenderFrame(scene, cam);
}
- set<class KX_Camera*>* cameras = scene->GetCameras();
+ list<class KX_Camera*>* cameras = scene->GetCameras();
// Draw the scene once for each camera with an enabled viewport
- set<KX_Camera*>::iterator it = cameras->begin();
+ list<KX_Camera*>::iterator it = cameras->begin();
while(it != cameras->end())
{
if((*it)->GetViewport())
@@ -641,9 +697,6 @@ void KX_KetsjiEngine::Render()
m_rendertools->SetAuxilaryClientInfo(scene);
- //Initialize scene viewport.
- SetupRenderFrame(scene, (*it));
-
// do the rendering
RenderFrame(scene, (*it));
}
@@ -676,10 +729,6 @@ void KX_KetsjiEngine::Render()
//pass the scene, for picking and raycasting (shadows)
m_rendertools->SetAuxilaryClientInfo(scene);
- //Initialize scene viewport.
- //SetupRenderFrame(scene);
- SetupRenderFrame(scene, cam);
-
// do the rendering
//RenderFrame(scene);
RenderFrame(scene, cam);
@@ -839,8 +888,13 @@ void KX_KetsjiEngine::SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat)
m_overrideCamViewMat = mat;
}
-
-void KX_KetsjiEngine::SetupRenderFrame(KX_Scene *scene, KX_Camera* cam)
+void KX_KetsjiEngine::SetCameraOverrideClipping(float near, float far)
+{
+ m_overrideCamNear = near;
+ m_overrideCamFar = far;
+}
+
+void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport)
{
// In this function we make sure the rasterizer settings are upto
// date. We compute the viewport so that logic
@@ -848,14 +902,26 @@ void KX_KetsjiEngine::SetupRenderFrame(KX_Scene *scene, KX_Camera* cam)
// Note we postpone computation of the projection matrix
// so that we are using the latest camera position.
+ if (cam->GetViewport()) {
+ RAS_Rect userviewport;
- RAS_Rect viewport;
+ userviewport.SetLeft(cam->GetViewportLeft());
+ userviewport.SetBottom(cam->GetViewportBottom());
+ userviewport.SetRight(cam->GetViewportRight());
+ userviewport.SetTop(cam->GetViewportTop());
- if (cam->GetViewport()) {
- viewport.SetLeft(cam->GetViewportLeft());
- viewport.SetBottom(cam->GetViewportBottom());
- viewport.SetRight(cam->GetViewportRight());
- viewport.SetTop(cam->GetViewportTop());
+ // Don't do bars on user specified viewport
+ RAS_FrameSettings settings = scene->GetFramingType();
+ if(settings.FrameType() == RAS_FrameSettings::e_frame_bars)
+ settings.SetFrameType(RAS_FrameSettings::e_frame_extend);
+
+ RAS_FramingManager::ComputeViewport(
+ scene->GetFramingType(),
+ userviewport,
+ viewport
+ );
+
+ area = userviewport;
}
else if ( m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho ) {
RAS_FramingManager::ComputeViewport(
@@ -863,42 +929,95 @@ void KX_KetsjiEngine::SetupRenderFrame(KX_Scene *scene, KX_Camera* cam)
m_canvas->GetDisplayArea(),
viewport
);
+
+ area = m_canvas->GetDisplayArea();
} else {
viewport.SetLeft(0);
viewport.SetBottom(0);
viewport.SetRight(int(m_canvas->GetWidth()));
viewport.SetTop(int(m_canvas->GetHeight()));
+
+ area = m_canvas->GetDisplayArea();
}
- // store the computed viewport in the scene
+}
- scene->SetSceneViewport(viewport);
+void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
+{
+ CListValue *objectlist = scene->GetObjectList();
+ int i, drawmode;
- // set the viewport for this frame and scene
- m_canvas->SetViewPort(
- viewport.GetLeft(),
- viewport.GetBottom(),
- viewport.GetRight(),
- viewport.GetTop()
- );
+ m_rendertools->SetAuxilaryClientInfo(scene);
-}
+ for(i=0; i<objectlist->GetCount(); i++) {
+ KX_GameObject *gameobj = (KX_GameObject*)objectlist->GetValue(i);
+
+ if(!gameobj->IsLight())
+ continue;
+
+ KX_LightObject *light = (KX_LightObject*)gameobj;
+
+ light->Update();
+
+ if(m_drawingmode == RAS_IRasterizer::KX_TEXTURED && light->HasShadowBuffer()) {
+ /* make temporary camera */
+ RAS_CameraData camdata = RAS_CameraData();
+ KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, false);
+ cam->SetName("__shadow__cam__");
+
+ MT_Transform camtrans;
+
+ /* switch drawmode for speed */
+ drawmode = m_rasterizer->GetDrawingMode();
+ m_rasterizer->SetDrawingMode(RAS_IRasterizer::KX_SHADOW);
+
+ /* binds framebuffer object, sets up camera .. */
+ light->BindShadowBuffer(m_rasterizer, cam, camtrans);
+ /* update scene */
+ scene->UpdateMeshTransformations();
+ scene->CalculateVisibleMeshes(m_rasterizer, cam, light->GetShadowLayer());
+
+ /* render */
+ m_rasterizer->ClearDepthBuffer();
+ scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
+
+ /* unbind framebuffer object, restore drawmode, free camera */
+ light->UnbindShadowBuffer(m_rasterizer);
+ m_rasterizer->SetDrawingMode(drawmode);
+ cam->Release();
+ }
+ }
+}
// update graphics
void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
{
- float left, right, bottom, top, nearfrust, farfrust;
+ bool override_camera;
+ RAS_Rect viewport, area;
+ float left, right, bottom, top, nearfrust, farfrust, focallength;
const float ortho = 100.0;
// KX_Camera* cam = scene->GetActiveCamera();
if (!cam)
return;
+
+ GetSceneViewport(scene, cam, area, viewport);
+
+ // store the computed viewport in the scene
+ scene->SetSceneViewport(viewport);
+
+ // set the viewport for this frame and scene
+ m_canvas->SetViewPort(viewport.GetLeft(), viewport.GetBottom(),
+ viewport.GetRight(), viewport.GetTop());
// see KX_BlenderMaterial::Activate
//m_rasterizer->SetAmbient();
m_rasterizer->DisplayFog();
- if (m_overrideCam && (scene->GetName() == m_overrideSceneName) && m_overrideCamUseOrtho) {
+ override_camera = m_overrideCam && (scene->GetName() == m_overrideSceneName);
+ override_camera = override_camera && (cam->GetName() == "__default__cam__");
+
+ if (override_camera && m_overrideCamUseOrtho) {
MT_CmMatrix4x4 projmat = m_overrideCamProjMat;
m_rasterizer->SetProjectionMatrix(projmat);
} else if (cam->hasValidProjectionMatrix() && !cam->GetViewport() )
@@ -908,11 +1027,17 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
{
RAS_FrameFrustum frustum;
float lens = cam->GetLens();
+ bool orthographic = !cam->GetCameraData()->m_perspective;
nearfrust = cam->GetCameraNear();
farfrust = cam->GetCameraFar();
+ focallength = cam->GetFocalLength();
- if (!cam->GetCameraData()->m_perspective)
- {
+ if(override_camera) {
+ nearfrust = m_overrideCamNear;
+ farfrust = m_overrideCamFar;
+ }
+
+ if (orthographic) {
lens *= ortho;
nearfrust = (nearfrust + 1.0)*ortho;
farfrust *= ortho;
@@ -920,8 +1045,8 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
RAS_FramingManager::ComputeFrustum(
scene->GetFramingType(),
- m_canvas->GetDisplayArea(),
- scene->GetSceneViewport(),
+ area,
+ viewport,
lens,
nearfrust,
farfrust,
@@ -936,8 +1061,8 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
farfrust = frustum.camfar;
MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix(
- left, right, bottom, top, nearfrust, farfrust);
-
+ left, right, bottom, top, nearfrust, farfrust, focallength);
+
cam->SetProjectionMatrix(projmat);
// Otherwise the projection matrix for each eye will be the same...
@@ -963,13 +1088,18 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
scene->CalculateVisibleMeshes(m_rasterizer,cam);
scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
+
+ PostRenderFrame();
+}
+void KX_KetsjiEngine::PostRenderFrame()
+{
+ m_rendertools->PushMatrix();
+ m_rendertools->Render2DFilters(m_canvas);
m_rendertools->MotionBlur(m_rasterizer);
-
+ m_rendertools->PopMatrix();
}
-
-
void KX_KetsjiEngine::StopEngine()
{
if (m_bInitialized)
@@ -985,7 +1115,7 @@ void KX_KetsjiEngine::StopEngine()
for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
{
KX_Scene* scene = *sceneit;
- delete scene;
+ m_sceneconverter->RemoveScene(scene);
}
m_scenes.clear();
@@ -1039,6 +1169,8 @@ void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
scene->SetActiveCamera(activecam);
scene->GetObjectList()->Add(activecam->AddRef());
scene->GetRootParentList()->Add(activecam->AddRef());
+ //done with activecam
+ activecam->Release();
}
scene->UpdateParents(0.0);
@@ -1111,19 +1243,49 @@ void KX_KetsjiEngine::RenderDebugProperties()
CValue* propobj = (*it)->m_obj;
STR_String objname = propobj->GetName();
STR_String propname = (*it)->m_name;
- CValue* propval = propobj->GetProperty(propname);
- if (propval)
+ if (propname == "__state__")
{
- STR_String text = propval->GetText();
- debugtxt = objname + "." + propname + " = " + text;
+ // reserve name for object state
+ KX_GameObject* gameobj = static_cast<KX_GameObject*>(propobj);
+ unsigned int state = gameobj->GetState();
+ debugtxt = objname + "." + propname + " = ";
+ bool first = true;
+ for (int statenum=1;state;state >>= 1, statenum++)
+ {
+ if (state & 1)
+ {
+ if (!first)
+ {
+ debugtxt += ",";
+ }
+ debugtxt += STR_String(statenum);
+ first = false;
+ }
+ }
m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
- debugtxt.Ptr(),
- xcoord,
- ycoord,
- m_canvas->GetWidth(),
- m_canvas->GetHeight());
+ debugtxt.Ptr(),
+ xcoord,
+ ycoord,
+ m_canvas->GetWidth(),
+ m_canvas->GetHeight());
ycoord += 14;
}
+ else
+ {
+ CValue* propval = propobj->GetProperty(propname);
+ if (propval)
+ {
+ STR_String text = propval->GetText();
+ debugtxt = objname + "." + propname + " = " + text;
+ m_rendertools->RenderText2D(RAS_IRenderTools::RAS_TEXT_PADDED,
+ debugtxt.Ptr(),
+ xcoord,
+ ycoord,
+ m_canvas->GetWidth(),
+ m_canvas->GetHeight());
+ ycoord += 14;
+ }
+ }
}
}
}
@@ -1207,7 +1369,7 @@ void KX_KetsjiEngine::RemoveScheduledScenes()
KX_Scene* scene = *sceneit;
if (scene->GetName()==scenename)
{
- delete scene;
+ m_sceneconverter->RemoveScene(scene);
m_scenes.erase(sceneit);
break;
}
@@ -1221,12 +1383,13 @@ void KX_KetsjiEngine::RemoveScheduledScenes()
KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename)
{
-
+ Scene *scene = m_sceneconverter->GetBlenderSceneForName(scenename);
KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice,
m_mousedevice,
m_networkdevice,
m_audiodevice,
- scenename);
+ scenename,
+ scene);
m_sceneconverter->ConvertScene(scenename,
tmpscene,
@@ -1305,7 +1468,7 @@ void KX_KetsjiEngine::ReplaceScheduledScenes()
KX_Scene* scene = *sceneit;
if (scene->GetName() == oldscenename)
{
- delete scene;
+ m_sceneconverter->RemoveScene(scene);
KX_Scene* tmpscene = CreateScene(newscenename);
m_scenes[i]=tmpscene;
PostProcessScene(tmpscene);
@@ -1372,6 +1535,26 @@ void KX_KetsjiEngine::SetTicRate(double ticrate)
m_ticrate = ticrate;
}
+double KX_KetsjiEngine::GetAnimFrameRate()
+{
+ return m_anim_framerate;
+}
+
+double KX_KetsjiEngine::GetClockTime(void) const
+{
+ return m_clockTime;
+}
+
+void KX_KetsjiEngine::SetAnimFrameRate(double framerate)
+{
+ m_anim_framerate = framerate;
+}
+
+double KX_KetsjiEngine::GetAverageFrameRate()
+{
+ return m_average_framerate;
+}
+
void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties)
{
m_show_framerate = frameRate;
@@ -1464,3 +1647,4 @@ void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const
}
+
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h
index e727452423b..4184202c518 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.h
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h
@@ -103,6 +103,7 @@ private:
double m_remainingTime;
static double m_ticrate;
+ static double m_anim_framerate; /* for animation playback only - ipo and action */
static double m_suspendedtime;
static double m_suspendeddelta;
@@ -123,6 +124,8 @@ private:
bool m_overrideCamUseOrtho;
MT_CmMatrix4x4 m_overrideCamProjMat;
MT_CmMatrix4x4 m_overrideCamViewMat;
+ float m_overrideCamNear;
+ float m_overrideCamFar;
bool m_stereo;
int m_curreye;
@@ -148,6 +151,8 @@ private:
/** Labels for profiling display. */
static const char m_profileLabels[tc_numCategories][15];
+ /** Last estimated framerate */
+ static double m_average_framerate;
/** Show the framerate on the game display? */
bool m_show_framerate;
/** Show profiling info on the game display? */
@@ -174,9 +179,10 @@ private:
/** Blue component of framing bar color. */
float m_overrideFrameColorB;
- void SetupRenderFrame(KX_Scene *scene, KX_Camera* cam);
void RenderFrame(KX_Scene* scene, KX_Camera* cam);
+ void PostRenderFrame();
void RenderDebugProperties();
+ void RenderShadowBuffers(KX_Scene *scene);
void SetBackGround(KX_WorldInfo* worldinfo);
void SetWorldSettings(KX_WorldInfo* worldinfo);
void DoSound(KX_Scene* scene);
@@ -198,6 +204,8 @@ public:
void SetSceneConverter(KX_ISceneConverter* sceneconverter);
void SetGame2IpoMode(bool game2ipo,int startFrame);
+ RAS_IRasterizer* GetRasterizer(){return m_rasterizer;};
+
///returns true if an update happened to indicate -> Render
bool NextFrame();
void Render();
@@ -221,6 +229,8 @@ public:
void SuspendScene(const STR_String& scenename);
void ResumeScene(const STR_String& scenename);
+ void GetSceneViewport(KX_Scene* scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport);
+
void SetDrawType(int drawingtype);
void SetCameraZoom(float camzoom);
@@ -229,6 +239,7 @@ public:
void SetCameraOverrideUseOrtho(bool useOrtho);
void SetCameraOverrideProjectionMatrix(const MT_CmMatrix4x4& mat);
void SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat);
+ void SetCameraOverrideClipping(float near, float far);
/**
* Sets display of all frames.
@@ -243,6 +254,11 @@ public:
bool GetUseFixedTime(void) const;
/**
+ * Returns current render frame clock time
+ */
+ double GetClockTime(void) const;
+
+ /**
* Returns the difference between the local time of the scene (when it
* was running and not suspended) and the "curtime"
*/
@@ -258,6 +274,20 @@ public:
static void SetTicRate(double ticrate);
/**
+ * Gets the framerate for playing animations. (actions and ipos)
+ */
+ static double GetAnimFrameRate();
+ /**
+ * Sets the framerate for playing animations. (actions and ipos)
+ */
+ static void SetAnimFrameRate(double framerate);
+
+ /**
+ * Gets the last estimated average framerate
+ */
+ static double GetAverageFrameRate();
+
+ /**
* Activates or deactivates timing information display.
* @param frameRate Display for frame rate on or off.
* @param profile Display for individual components on or off.
@@ -334,8 +364,10 @@ protected:
KX_Scene* CreateScene(const STR_String& scenename);
bool BeginFrame();
+ void ClearFrame();
void EndFrame();
};
#endif //__KX_KETSJI_ENGINE
+
diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp
index 3ae09c01270..e0f171e78e0 100644
--- a/source/gameengine/Ketsji/KX_Light.cpp
+++ b/source/gameengine/Ketsji/KX_Light.cpp
@@ -36,14 +36,19 @@
#endif
#include "KX_Light.h"
+#include "KX_Camera.h"
+#include "RAS_IRasterizer.h"
#include "RAS_IRenderTools.h"
#include "KX_PyMath.h"
+#include "DNA_object_types.h"
+#include "GPU_material.h"
KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,
class RAS_IRenderTools* rendertools,
const RAS_LightObject& lightobj,
+ bool glsl,
PyTypeObject* T
)
:
@@ -53,11 +58,19 @@ KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,
m_lightobj = lightobj;
m_lightobj.m_worldmatrix = GetOpenGLMatrixPtr();
m_rendertools->AddLight(&m_lightobj);
+ m_glsl = glsl;
+ m_blenderscene = ((KX_Scene*)sgReplicationInfo)->GetBlenderScene();
};
KX_LightObject::~KX_LightObject()
{
+ GPULamp *lamp;
+
+ if((lamp = GetGPULamp())) {
+ float obmat[4][4] = {{0}};
+ GPU_lamp_update(lamp, 0, obmat);
+ }
m_rendertools->RemoveLight(&m_lightobj);
}
@@ -67,7 +80,7 @@ CValue* KX_LightObject::GetReplica()
{
KX_LightObject* replica = new KX_LightObject(*this);
-
+
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
@@ -75,9 +88,90 @@ CValue* KX_LightObject::GetReplica()
replica->m_lightobj.m_worldmatrix = replica->GetOpenGLMatrixPtr();
m_rendertools->AddLight(&replica->m_lightobj);
+
return replica;
}
+GPULamp *KX_LightObject::GetGPULamp()
+{
+ if(m_glsl)
+ return GPU_lamp_from_blender(m_blenderscene, GetBlenderObject(), GetBlenderGroupObject());
+ else
+ return false;
+}
+
+void KX_LightObject::Update()
+{
+ GPULamp *lamp;
+
+ if((lamp = GetGPULamp())) {
+ float obmat[4][4];
+ double *dobmat = GetOpenGLMatrixPtr()->getPointer();
+
+ for(int i=0; i<4; i++)
+ for(int j=0; j<4; j++, dobmat++)
+ obmat[i][j] = (float)*dobmat;
+
+ GPU_lamp_update(lamp, m_lightobj.m_layer, obmat);
+ }
+}
+
+bool KX_LightObject::HasShadowBuffer()
+{
+ GPULamp *lamp;
+
+ if((lamp = GetGPULamp()))
+ return GPU_lamp_has_shadow_buffer(lamp);
+ else
+ return false;
+}
+
+int KX_LightObject::GetShadowLayer()
+{
+ GPULamp *lamp;
+
+ if((lamp = GetGPULamp()))
+ return GPU_lamp_shadow_layer(lamp);
+ else
+ return 0;
+}
+
+void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_Transform& camtrans)
+{
+ GPULamp *lamp;
+ float viewmat[4][4], winmat[4][4];
+ int winsize;
+
+ /* bind framebuffer */
+ lamp = GetGPULamp();
+ GPU_lamp_shadow_buffer_bind(lamp, viewmat, &winsize, winmat);
+
+ /* setup camera transformation */
+ MT_Matrix4x4 modelviewmat((float*)viewmat);
+ MT_Matrix4x4 projectionmat((float*)winmat);
+
+ MT_Transform trans = MT_Transform((float*)viewmat);
+ camtrans.invert(trans);
+
+ cam->SetModelviewMatrix(modelviewmat);
+ cam->SetProjectionMatrix(projectionmat);
+
+ cam->NodeSetLocalPosition(camtrans.getOrigin());
+ cam->NodeSetLocalOrientation(camtrans.getBasis());
+ cam->NodeUpdateGS(0,true);
+
+ /* setup rasterizer transformations */
+ ras->SetProjectionMatrix(projectionmat);
+ ras->SetViewMatrix(modelviewmat, cam->NodeGetWorldPosition(),
+ cam->GetCameraLocation(), cam->GetCameraOrientation());
+}
+
+void KX_LightObject::UnbindShadowBuffer(RAS_IRasterizer *ras)
+{
+ GPULamp *lamp = GetGPULamp();
+ GPU_lamp_shadow_buffer_unbind(lamp);
+}
+
PyObject* KX_LightObject::_getattr(const STR_String& attr)
{
if (attr == "layer")
@@ -223,7 +317,7 @@ char KX_LightObject::doc[] = "Module KX_LightObject\n\n"
"\t\tThe effect radius of the light.\n"
"\tcolour -> list [r, g, b].\n"
"\tcolor -> list [r, g, b].\n"
-"\t\tThe colour of the light.\n"
+"\t\tThe color of the light.\n"
"\tlin_attenuation -> float.\n"
"\t\tThe attenuation factor for the light.\n"
"\tspotsize -> float.\n"
diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h
index 236d3e4e12e..e5dbf0b7f4a 100644
--- a/source/gameengine/Ketsji/KX_Light.h
+++ b/source/gameengine/Ketsji/KX_Light.h
@@ -32,22 +32,41 @@
#include "RAS_LightObject.h"
#include "KX_GameObject.h"
+struct GPULamp;
+struct Scene;
+class KX_Camera;
+class RAS_IRasterizer;
+class RAS_IRenderTools;
+class MT_Transform;
+
class KX_LightObject : public KX_GameObject
{
Py_Header;
protected:
RAS_LightObject m_lightobj;
class RAS_IRenderTools* m_rendertools; //needed for registering and replication of lightobj
- static char doc[];
+ bool m_glsl;
+ Scene* m_blenderscene;
+ static char doc[];
public:
- KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,class RAS_IRenderTools* rendertools,const struct RAS_LightObject& lightobj, PyTypeObject *T = &Type);
+ KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,class RAS_IRenderTools* rendertools,const struct RAS_LightObject& lightobj, bool glsl, PyTypeObject *T = &Type);
virtual ~KX_LightObject();
virtual CValue* GetReplica();
RAS_LightObject* GetLightData() { return &m_lightobj;}
+
+ /* GLSL shadow */
+ struct GPULamp *GetGPULamp();
+ bool HasShadowBuffer();
+ int GetShadowLayer();
+ void BindShadowBuffer(class RAS_IRasterizer *ras, class KX_Camera *cam, class MT_Transform& camtrans);
+ void UnbindShadowBuffer(class RAS_IRasterizer *ras);
+ void Update();
virtual PyObject* _getattr(const STR_String& attr); /* lens, near, far, projection_matrix */
virtual int _setattr(const STR_String& attr, PyObject *pyvalue);
+
+ virtual bool IsLight(void) { return true; }
};
#endif //__KX_LIGHT
diff --git a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp
index c0757a32b9c..85d514bd22f 100644
--- a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp
+++ b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp
@@ -3,6 +3,8 @@
#include "KX_ScalarInterpolator.h"
#include "KX_GameObject.h"
+#include "BLO_sys_types.h" // for intptr_t support
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -37,6 +39,7 @@ bool KX_MaterialIpoController::Update(double currentTime)
//kxgameobj->SetObjectColor(m_rgba);
kxgameobj->UpdateMaterialData(
+ m_matname_hash,
m_rgba,
m_specrgb,
m_hard,
@@ -75,10 +78,10 @@ SG_Controller* KX_MaterialIpoController::GetReplica(class SG_Node* destnode)
iporeplica->AddInterpolator(copyipo);
MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget();
- long orgbase = (long)this;
- long orgloc = (long)scaal;
- long offset = orgloc-orgbase;
- long newaddrbase = (long)iporeplica + offset;
+ intptr_t orgbase = (intptr_t)this;
+ intptr_t orgloc = (intptr_t)scaal;
+ intptr_t offset = orgloc-orgbase;
+ intptr_t newaddrbase = (intptr_t)iporeplica + offset;
MT_Scalar* blaptr = (MT_Scalar*) newaddrbase;
copyipo->SetNewTarget((MT_Scalar*)blaptr);
}
diff --git a/source/gameengine/Ketsji/KX_MaterialIpoController.h b/source/gameengine/Ketsji/KX_MaterialIpoController.h
index e76ddeefb04..4d2e258bf94 100644
--- a/source/gameengine/Ketsji/KX_MaterialIpoController.h
+++ b/source/gameengine/Ketsji/KX_MaterialIpoController.h
@@ -7,6 +7,8 @@
#include "SG_Spatial.h"
#include "KX_IInterpolator.h"
+#include "STR_String.h" //typedef dword
+
class KX_MaterialIpoController : public SG_Controller
{
public:
@@ -23,10 +25,12 @@ private:
bool m_modified;
double m_ipotime;
+ dword m_matname_hash;
public:
- KX_MaterialIpoController() :
+ KX_MaterialIpoController(dword matname_hash) :
m_modified(true),
- m_ipotime(0.0)
+ m_ipotime(0.0),
+ m_matname_hash(matname_hash)
{}
virtual ~KX_MaterialIpoController();
virtual SG_Controller* GetReplica(class SG_Node* destnode);
diff --git a/source/gameengine/Ketsji/KX_MeshProxy.cpp b/source/gameengine/Ketsji/KX_MeshProxy.cpp
index 5c8fef1fca0..5cc102248f2 100644
--- a/source/gameengine/Ketsji/KX_MeshProxy.cpp
+++ b/source/gameengine/Ketsji/KX_MeshProxy.cpp
@@ -35,6 +35,7 @@
#include "RAS_MeshObject.h"
#include "KX_VertexProxy.h"
+#include "KX_PolyProxy.h"
#include "KX_PolygonMaterial.h"
#include "KX_BlenderMaterial.h"
@@ -42,6 +43,8 @@
#include "KX_PyMath.h"
#include "KX_ConvertPhysicsObject.h"
+#include "PyObjectPlus.h"
+
PyTypeObject KX_MeshProxy::Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
@@ -71,10 +74,12 @@ PyParentObject KX_MeshProxy::Parents[] = {
PyMethodDef KX_MeshProxy::Methods[] = {
{"getNumMaterials", (PyCFunction)KX_MeshProxy::sPyGetNumMaterials,METH_VARARGS},
+{"getNumPolygons", (PyCFunction)KX_MeshProxy::sPyGetNumPolygons,METH_NOARGS},
{"getMaterialName", (PyCFunction)KX_MeshProxy::sPyGetMaterialName,METH_VARARGS},
{"getTextureName", (PyCFunction)KX_MeshProxy::sPyGetTextureName,METH_VARARGS},
{"getVertexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetVertexArrayLength,METH_VARARGS},
{"getVertex", (PyCFunction)KX_MeshProxy::sPyGetVertex,METH_VARARGS},
+{"getPolygon", (PyCFunction)KX_MeshProxy::sPyGetPolygon,METH_VARARGS},
KX_PYMETHODTABLE(KX_MeshProxy, reinstancePhysicsMesh),
//{"getIndexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetIndexArrayLength,METH_VARARGS},
@@ -93,10 +98,11 @@ KX_MeshProxy::_getattr(const STR_String& attr)
if (attr == "materials")
{
PyObject *materials = PyList_New(0);
- RAS_MaterialBucket::Set::iterator mit = m_meshobj->GetFirstMaterial();
+ list<RAS_MeshMaterial>::iterator mit = m_meshobj->GetFirstMaterial();
for(; mit != m_meshobj->GetLastMaterial(); ++mit)
{
- RAS_IPolyMaterial *polymat = (*mit)->GetPolyMaterial();
+ RAS_IPolyMaterial *polymat = mit->m_bucket->GetPolyMaterial();
+
if(polymat->GetFlag() & RAS_BLENDERMAT)
{
KX_BlenderMaterial *mat = static_cast<KX_BlenderMaterial*>(polymat);
@@ -146,6 +152,12 @@ PyObject* KX_MeshProxy::PyGetNumMaterials(PyObject* self,
return PyInt_FromLong(num);
}
+PyObject* KX_MeshProxy::PyGetNumPolygons(PyObject* self)
+{
+ int num = m_meshobj->NumPolygons();
+ return PyInt_FromLong(num);
+}
+
PyObject* KX_MeshProxy::PyGetMaterialName(PyObject* self,
PyObject* args,
PyObject* kwds)
@@ -157,6 +169,9 @@ PyObject* KX_MeshProxy::PyGetMaterialName(PyObject* self,
{
matname = m_meshobj->GetMaterialName(matid);
}
+ else {
+ return NULL;
+ }
return PyString_FromString(matname.Ptr());
@@ -174,6 +189,9 @@ PyObject* KX_MeshProxy::PyGetTextureName(PyObject* self,
{
matname = m_meshobj->GetTextureName(matid);
}
+ else {
+ return NULL;
+ }
return PyString_FromString(matname.Ptr());
@@ -189,11 +207,14 @@ PyObject* KX_MeshProxy::PyGetVertexArrayLength(PyObject* self,
if (PyArg_ParseTuple(args,"i",&matid))
{
- RAS_IPolyMaterial* mat = m_meshobj->GetMaterialBucket(matid)->GetPolyMaterial();
+ RAS_MeshMaterial *mmat = m_meshobj->GetMeshMaterial(matid);
+ RAS_IPolyMaterial* mat = mmat->m_bucket->GetPolyMaterial();
+
if (mat)
- {
- length = m_meshobj->GetVertexArrayLength(mat);
- }
+ length = m_meshobj->NumVertices(mat);
+ }
+ else {
+ return NULL;
}
return PyInt_FromLong(length);
@@ -217,14 +238,39 @@ PyObject* KX_MeshProxy::PyGetVertex(PyObject* self,
vertexob = new KX_VertexProxy(this, vertex);
}
}
+ else {
+ return NULL;
+ }
return vertexob;
}
+PyObject* KX_MeshProxy::PyGetPolygon(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ int polyindex= 1;
+ PyObject* polyob = NULL;
+
+ if (!PyArg_ParseTuple(args,"i",&polyindex))
+ return NULL;
+
+ RAS_Polygon* polygon = m_meshobj->GetPolygon(polyindex);
+ if (polygon)
+ {
+ polyob = new KX_PolyProxy(m_meshobj, polygon);
+ }
+ else
+ {
+ PyErr_SetString(PyExc_AttributeError, "Invalid polygon index");
+ }
+ return polyob;
+}
+
KX_PYMETHODDEF_DOC(KX_MeshProxy, reinstancePhysicsMesh,
"Reinstance the physics mesh.")
{
//this needs to be reviewed, it is dependend on Sumo/Solid. Who is using this ?
- return Py_None;//Py_Success(KX_ReInstanceShapeFromMesh(m_meshobj));
+ Py_RETURN_NONE;//(KX_ReInstanceShapeFromMesh(m_meshobj)) ? Py_RETURN_TRUE : Py_RETURN_FALSE;
}
diff --git a/source/gameengine/Ketsji/KX_MeshProxy.h b/source/gameengine/Ketsji/KX_MeshProxy.h
index 7c6202c15a4..3335c349673 100644
--- a/source/gameengine/Ketsji/KX_MeshProxy.h
+++ b/source/gameengine/Ketsji/KX_MeshProxy.h
@@ -57,10 +57,12 @@ public:
KX_PYMETHOD(KX_MeshProxy,GetNumMaterials);
KX_PYMETHOD(KX_MeshProxy,GetMaterialName);
KX_PYMETHOD(KX_MeshProxy,GetTextureName);
+ KX_PYMETHOD_NOARGS(KX_MeshProxy,GetNumPolygons);
// both take materialid (int)
KX_PYMETHOD(KX_MeshProxy,GetVertexArrayLength);
KX_PYMETHOD(KX_MeshProxy,GetVertex);
+ KX_PYMETHOD(KX_MeshProxy,GetPolygon);
KX_PYMETHOD_DOC(KX_MeshProxy, reinstancePhysicsMesh);
};
diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
index 60b90138abe..28279b9a6b8 100644
--- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
+++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
@@ -62,43 +62,54 @@ KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager* eventmgr,
int focusmode,
RAS_ICanvas* canvas,
KX_Scene* kxscene,
+ KX_KetsjiEngine *kxengine,
SCA_IObject* gameobj,
PyTypeObject* T)
: SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj, T),
m_focusmode(focusmode),
m_gp_canvas(canvas),
- m_kxscene(kxscene)
+ m_kxscene(kxscene),
+ m_kxengine(kxengine)
{
+ Init();
+}
- m_mouse_over_in_previous_frame = false;
+void KX_MouseFocusSensor::Init()
+{
+ m_mouse_over_in_previous_frame = (m_invert)?true:false;
m_positive_event = false;
m_hitObject = 0;
-
+ m_reset = true;
}
bool KX_MouseFocusSensor::Evaluate(CValue* event)
{
bool result = false;
bool obHasFocus = false;
+ bool reset = m_reset && m_level;
// cout << "evaluate focus mouse sensor "<<endl;
-
+ m_reset = false;
if (m_focusmode) {
/* Focus behaviour required. Test mouse-on. The rest is
* equivalent to handling a key. */
obHasFocus = ParentObjectHasFocus();
if (!obHasFocus) {
+ m_positive_event = false;
if (m_mouse_over_in_previous_frame) {
- m_positive_event = false;
- result = true;
+ result = true;
}
} else {
+ m_positive_event = true;
if (!m_mouse_over_in_previous_frame) {
- m_positive_event = true;
result = true;
}
}
+ if (reset) {
+ // force an event
+ result = true;
+ }
} else {
/* No focus behaviour required: revert to the basic mode. This
* mode is never used, because the converter never makes this
@@ -113,16 +124,10 @@ bool KX_MouseFocusSensor::Evaluate(CValue* event)
return result;
}
-bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data)
+bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, KX_RayCast* result, void * const data)
{
KX_GameObject* hitKXObj = client_info->m_gameobject;
- if (client_info->m_type > KX_ClientObjectInfo::ACTOR)
- {
- // false hit
- return false;
- }
-
/* Is this me? In the ray test, there are a lot of extra checks
* for aliasing artefacts from self-hits. That doesn't happen
* here, so a simple test suffices. Or does the camera also get
@@ -133,8 +138,8 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo* client_info, MT_Point3& hi
if ((m_focusmode == 2) || hitKXObj == thisObj)
{
m_hitObject = hitKXObj;
- m_hitPosition = hit_point;
- m_hitNormal = hit_normal;
+ m_hitPosition = result->m_hitPoint;
+ m_hitNormal = result->m_hitNormal;
return true;
}
@@ -149,8 +154,6 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void)
m_hitObject = 0;
m_hitPosition = MT_Vector3(0,0,0);
m_hitNormal = MT_Vector3(1,0,0);
- MT_Point3 resultpoint;
- MT_Vector3 resultnormal;
/* All screen handling in the gameengine is done by GL,
* specifically the model/view and projection parts. The viewport
@@ -192,11 +195,14 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void)
* calculations don't bomb. Maybe we should explicitly guard for
* division by 0.0...*/
- /**
- * Get the scenes current viewport.
- */
+ KX_Camera* cam = m_kxscene->GetActiveCamera();
+
+ /* get the scenes current viewport. we recompute it because there
+ * may be multiple cameras and m_kxscene->GetSceneViewport() only
+ * has the one that was last drawn */
- const RAS_Rect & viewport = m_kxscene->GetSceneViewport();
+ RAS_Rect area, viewport;
+ m_kxengine->GetSceneViewport(m_kxscene, cam, area, viewport);
float height = float(viewport.m_y2 - viewport.m_y1 + 1);
float width = float(viewport.m_x2 - viewport.m_x1 + 1);
@@ -204,9 +210,9 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void)
float x_lb = float(viewport.m_x1);
float y_lb = float(viewport.m_y1);
- KX_Camera* cam = m_kxscene->GetActiveCamera();
/* There's some strangeness I don't fully get here... These values
* _should_ be wrong! */
+
/* old: */
float nearclip = 0.0;
@@ -271,7 +277,8 @@ bool KX_MouseFocusSensor::ParentObjectHasFocus(void)
bool result = false;
- result = KX_RayCast::RayTest(physics_controller, physics_environment, frompoint3, topoint3, resultpoint, resultnormal, KX_RayCast::Callback<KX_MouseFocusSensor>(this));
+ KX_RayCast::Callback<KX_MouseFocusSensor> callback(this,physics_controller);
+ KX_RayCast::RayTest(physics_environment, frompoint3, topoint3, callback);
result = (m_hitObject!=0);
@@ -313,14 +320,12 @@ PyParentObject KX_MouseFocusSensor::Parents[] = {
};
PyMethodDef KX_MouseFocusSensor::Methods[] = {
- {"getRayTarget", (PyCFunction) KX_MouseFocusSensor::sPyGetRayTarget,
- METH_VARARGS, GetRayTarget_doc},
- {"getRaySource", (PyCFunction) KX_MouseFocusSensor::sPyGetRaySource,
- METH_VARARGS, GetRaySource_doc},
- {"getHitObject",(PyCFunction) KX_MouseFocusSensor::sPyGetHitObject,METH_VARARGS, GetHitObject_doc},
- {"getHitPosition",(PyCFunction) KX_MouseFocusSensor::sPyGetHitPosition,METH_VARARGS, GetHitPosition_doc},
- {"getHitNormal",(PyCFunction) KX_MouseFocusSensor::sPyGetHitNormal,METH_VARARGS, GetHitNormal_doc},
- {"getRayDirection",(PyCFunction) KX_MouseFocusSensor::sPyGetRayDirection,METH_VARARGS, GetRayDirection_doc},
+ {"getRayTarget", (PyCFunction) KX_MouseFocusSensor::sPyGetRayTarget, METH_VARARGS, (PY_METHODCHAR)GetRayTarget_doc},
+ {"getRaySource", (PyCFunction) KX_MouseFocusSensor::sPyGetRaySource, METH_VARARGS, (PY_METHODCHAR)GetRaySource_doc},
+ {"getHitObject",(PyCFunction) KX_MouseFocusSensor::sPyGetHitObject,METH_VARARGS, (PY_METHODCHAR)GetHitObject_doc},
+ {"getHitPosition",(PyCFunction) KX_MouseFocusSensor::sPyGetHitPosition,METH_VARARGS, (PY_METHODCHAR)GetHitPosition_doc},
+ {"getHitNormal",(PyCFunction) KX_MouseFocusSensor::sPyGetHitNormal,METH_VARARGS, (PY_METHODCHAR)GetHitNormal_doc},
+ {"getRayDirection",(PyCFunction) KX_MouseFocusSensor::sPyGetRayDirection,METH_VARARGS, (PY_METHODCHAR)GetRayDirection_doc},
{NULL,NULL} //Sentinel
@@ -331,7 +336,7 @@ PyObject* KX_MouseFocusSensor::_getattr(const STR_String& attr) {
}
-char KX_MouseFocusSensor::GetHitObject_doc[] =
+const char KX_MouseFocusSensor::GetHitObject_doc[] =
"getHitObject()\n"
"\tReturns the name of the object that was hit by this ray.\n";
PyObject* KX_MouseFocusSensor::PyGetHitObject(PyObject* self,
@@ -346,7 +351,7 @@ PyObject* KX_MouseFocusSensor::PyGetHitObject(PyObject* self,
}
-char KX_MouseFocusSensor::GetHitPosition_doc[] =
+const char KX_MouseFocusSensor::GetHitPosition_doc[] =
"getHitPosition()\n"
"\tReturns the position (in worldcoordinates) where the object was hit by this ray.\n";
PyObject* KX_MouseFocusSensor::PyGetHitPosition(PyObject* self,
@@ -366,7 +371,7 @@ PyObject* KX_MouseFocusSensor::PyGetHitPosition(PyObject* self,
}
-char KX_MouseFocusSensor::GetRayDirection_doc[] =
+const char KX_MouseFocusSensor::GetRayDirection_doc[] =
"getRayDirection()\n"
"\tReturns the direction from the ray (in worldcoordinates) .\n";
PyObject* KX_MouseFocusSensor::PyGetRayDirection(PyObject* self,
@@ -387,7 +392,7 @@ PyObject* KX_MouseFocusSensor::PyGetRayDirection(PyObject* self,
}
-char KX_MouseFocusSensor::GetHitNormal_doc[] =
+const char KX_MouseFocusSensor::GetHitNormal_doc[] =
"getHitNormal()\n"
"\tReturns the normal (in worldcoordinates) of the object at the location where the object was hit by this ray.\n";
PyObject* KX_MouseFocusSensor::PyGetHitNormal(PyObject* self,
@@ -408,7 +413,7 @@ PyObject* KX_MouseFocusSensor::PyGetHitNormal(PyObject* self,
/* getRayTarget */
-char KX_MouseFocusSensor::GetRayTarget_doc[] =
+const char KX_MouseFocusSensor::GetRayTarget_doc[] =
"getRayTarget()\n"
"\tReturns the target of the ray that seeks the focus object,\n"
"\tin worldcoordinates.";
@@ -425,7 +430,7 @@ PyObject* KX_MouseFocusSensor::PyGetRayTarget(PyObject* self,
}
/* getRayTarget */
-char KX_MouseFocusSensor::GetRaySource_doc[] =
+const char KX_MouseFocusSensor::GetRaySource_doc[] =
"getRaySource()\n"
"\tReturns the source of the ray that seeks the focus object,\n"
"\tin worldcoordinates.";
diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h
index 86f32fbf4be..6731444699b 100644
--- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h
+++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h
@@ -33,6 +33,8 @@
#include "SCA_MouseSensor.h"
+class KX_RayCast;
+
/**
* The mouse focus sensor extends the basic SCA_MouseSensor. It has
* been placed in KX because it needs access to the rasterizer and
@@ -54,6 +56,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor
int focusmode,
RAS_ICanvas* canvas,
KX_Scene* kxscene,
+ KX_KetsjiEngine* kxengine,
SCA_IObject* gameobj,
PyTypeObject* T=&Type );
@@ -68,6 +71,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor
* @attention Overrides default evaluate.
*/
virtual bool Evaluate(CValue* event);
+ virtual void Init();
virtual bool IsPositiveTrigger() {
bool result = m_positive_event;
@@ -75,7 +79,9 @@ class KX_MouseFocusSensor : public SCA_MouseSensor
return result;
};
- bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data);
+ bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
+ bool NeedRayCast(KX_ClientObjectInfo* client) { return true; }
+
/* --------------------------------------------------------------------- */
@@ -138,12 +144,6 @@ class KX_MouseFocusSensor : public SCA_MouseSensor
/**
- * Ref to the engine, for retrieving a reference to the current
- * scene. */
- class KX_KetsjiEngine* m_engine;
-
-
- /**
* The active canvas. The size of this canvas determines a part of
* the start position of the picking ray. */
RAS_ICanvas* m_gp_canvas;
@@ -153,6 +153,9 @@ class KX_MouseFocusSensor : public SCA_MouseSensor
* determines a part of the start location of the picking ray. */
KX_Scene* m_kxscene;
+ /**
+ * The KX engine is needed for computing the viewport */
+ KX_KetsjiEngine* m_kxengine;
};
#endif //__KX_MOUSESENSOR
diff --git a/source/gameengine/Ketsji/KX_NearSensor.cpp b/source/gameengine/Ketsji/KX_NearSensor.cpp
index d893990735f..bae87c28123 100644
--- a/source/gameengine/Ketsji/KX_NearSensor.cpp
+++ b/source/gameengine/Ketsji/KX_NearSensor.cpp
@@ -75,6 +75,21 @@ KX_NearSensor::KX_NearSensor(SCA_EventManager* eventmgr,
SynchronizeTransform();
}
+void KX_NearSensor::SynchronizeTransform()
+{
+ // The near and radar sensors are using a different physical object which is
+ // not linked to the parent object, must synchronize it.
+ if (m_physCtrl)
+ {
+ KX_GameObject* parent = ((KX_GameObject*)GetParent());
+ MT_Vector3 pos = parent->NodeGetWorldPosition();
+ MT_Quaternion orn = parent->NodeGetWorldOrientation().getRotation();
+ m_physCtrl->setPosition(pos.x(),pos.y(),pos.z());
+ m_physCtrl->setOrientation(orn.x(),orn.y(),orn.z(),orn.w());
+ m_physCtrl->calcXform();
+ }
+}
+
void KX_NearSensor::RegisterSumo(KX_TouchEventManager *touchman)
{
if (m_physCtrl)
@@ -83,14 +98,19 @@ void KX_NearSensor::RegisterSumo(KX_TouchEventManager *touchman)
}
}
+void KX_NearSensor::UnregisterSumo(KX_TouchEventManager* touchman)
+{
+ if (m_physCtrl)
+ {
+ touchman->GetPhysicsEnvironment()->removeSensor(m_physCtrl);
+ }
+}
+
CValue* KX_NearSensor::GetReplica()
{
KX_NearSensor* replica = new KX_NearSensor(*this);
replica->m_colliders = new CListValue();
- replica->m_bCollision = false;
- replica->m_bTriggered= false;
- replica->m_hitObject = NULL;
- replica->m_bLastTriggered = false;
+ replica->Init();
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
@@ -123,9 +143,6 @@ CValue* KX_NearSensor::GetReplica()
void KX_NearSensor::ReParent(SCA_IObject* parent)
{
-
- SCA_ISensor::ReParent(parent);
-
m_client_info->m_gameobject = static_cast<KX_GameObject*>(parent);
m_client_info->m_sensors.push_back(this);
@@ -139,6 +156,7 @@ void KX_NearSensor::ReParent(SCA_IObject* parent)
*/
((KX_GameObject*)GetParent())->GetSGNode()->ComputeWorldTransforms(NULL);
SynchronizeTransform();
+ SCA_ISensor::ReParent(parent);
}
@@ -172,13 +190,13 @@ bool KX_NearSensor::Evaluate(CValue* event)
{
if (m_physCtrl)
{
- m_physCtrl->SetMargin(m_ResetMargin);
+ m_physCtrl->SetRadius(m_ResetMargin);
}
} else
{
if (m_physCtrl)
{
- m_physCtrl->SetMargin(m_Margin);
+ m_physCtrl->SetRadius(m_Margin);
}
}
@@ -188,7 +206,36 @@ bool KX_NearSensor::Evaluate(CValue* event)
return result;
}
+// this function is called at broad phase stage to check if the two controller
+// need to interact at all. It is used for Near/Radar sensor that don't need to
+// check collision with object not included in filter
+bool KX_NearSensor::BroadPhaseFilterCollision(void*obj1,void*obj2)
+{
+ KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
+
+ // need the mapping from PHY_IPhysicsController to gameobjects now
+ assert(obj1==m_physCtrl && obj2);
+ KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>((static_cast<PHY_IPhysicsController*>(obj2))->getNewClientInfo());
+ KX_GameObject* gameobj = ( client_info ?
+ client_info->m_gameobject :
+ NULL);
+
+ if (gameobj && (gameobj != parent))
+ {
+ // only take valid colliders
+ if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
+ {
+ if ((m_touchedpropname.Length() == 0) ||
+ (gameobj->GetProperty(m_touchedpropname)))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
bool KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData * coll_data)
{
@@ -205,20 +252,24 @@ bool KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData
client_info->m_gameobject :
NULL);
- if (gameobj && (gameobj != parent))
+ // Add the same check as in SCA_ISensor::Activate(),
+ // we don't want to record collision when the sensor is not active.
+ if (m_links && !m_suspended &&
+ gameobj /* done in BroadPhaseFilterCollision() && (gameobj != parent)*/)
{
if (!m_colliders->SearchValue(gameobj))
m_colliders->Add(gameobj->AddRef());
// only take valid colliders
- if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
- {
- if ((m_touchedpropname.Length() == 0) ||
- (gameobj->GetProperty(m_touchedpropname)))
- {
+ // These checks are done already in BroadPhaseFilterCollision()
+ //if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
+ //{
+ // if ((m_touchedpropname.Length() == 0) ||
+ // (gameobj->GetProperty(m_touchedpropname)))
+ // {
m_bTriggered = true;
m_hitObject = gameobj;
- }
- }
+ // }
+ //}
}
return DT_CONTINUE;
@@ -260,14 +311,10 @@ PyParentObject KX_NearSensor::Parents[] = {
PyMethodDef KX_NearSensor::Methods[] = {
- {"setProperty",
- (PyCFunction) KX_NearSensor::sPySetProperty, METH_VARARGS, SetProperty_doc},
- {"getProperty",
- (PyCFunction) KX_NearSensor::sPyGetProperty, METH_VARARGS, GetProperty_doc},
- {"getHitObject",
- (PyCFunction) KX_NearSensor::sPyGetHitObject, METH_VARARGS, GetHitObject_doc},
- {"getHitObjectList",
- (PyCFunction) KX_NearSensor::sPyGetHitObjectList, METH_VARARGS, GetHitObjectList_doc},
+ {"setProperty", (PyCFunction) KX_NearSensor::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc},
+ {"getProperty", (PyCFunction) KX_NearSensor::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc},
+ {"getHitObject",(PyCFunction) KX_NearSensor::sPyGetHitObject, METH_VARARGS, (PY_METHODCHAR)GetHitObject_doc},
+ {"getHitObjectList", (PyCFunction) KX_NearSensor::sPyGetHitObjectList, METH_VARARGS, (PY_METHODCHAR)GetHitObjectList_doc},
{NULL,NULL} //Sentinel
};
diff --git a/source/gameengine/Ketsji/KX_NearSensor.h b/source/gameengine/Ketsji/KX_NearSensor.h
index 096822f99ed..3f7078ef9fd 100644
--- a/source/gameengine/Ketsji/KX_NearSensor.h
+++ b/source/gameengine/Ketsji/KX_NearSensor.h
@@ -68,13 +68,16 @@ public:
PyTypeObject* T=&Type);
*/
virtual ~KX_NearSensor();
+ virtual void SynchronizeTransform();
virtual CValue* GetReplica();
virtual bool Evaluate(CValue* event);
virtual void ReParent(SCA_IObject* parent);
virtual bool NewHandleCollision(void* obj1,void* obj2,
const PHY_CollData * coll_data);
+ virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2);
virtual void RegisterSumo(KX_TouchEventManager *touchman);
+ virtual void UnregisterSumo(KX_TouchEventManager* touchman);
virtual PyObject* _getattr(const STR_String& attr);
diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp
index 22a406792f9..98e73d4f0d7 100644
--- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp
+++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp
@@ -50,6 +50,7 @@ KX_ObjectActuator(
const MT_Vector3& drot,
const MT_Vector3& linV,
const MT_Vector3& angV,
+ const short damping,
const KX_LocalFlags& flag,
PyTypeObject* T
) :
@@ -60,9 +61,23 @@ KX_ObjectActuator(
m_drot(drot),
m_linear_velocity(linV),
m_angular_velocity(angV),
+ m_linear_length2(0.0),
+ m_current_linear_factor(0.0),
+ m_current_angular_factor(0.0),
+ m_damping(damping),
m_bitLocalFlag (flag),
- m_active_combined_velocity (false)
+ m_active_combined_velocity (false),
+ m_linear_damping_active(false),
+ m_angular_damping_active(false),
+ m_error_accumulator(0.0,0.0,0.0),
+ m_previous_error(0.0,0.0,0.0)
{
+ if (m_bitLocalFlag.ServoControl)
+ {
+ // in servo motion, the force is local if the target velocity is local
+ m_bitLocalFlag.Force = m_bitLocalFlag.LinearVelocity;
+ }
+ UpdateFuzzyFlags();
}
bool KX_ObjectActuator::Update()
@@ -79,51 +94,153 @@ bool KX_ObjectActuator::Update()
// it should reconcile the externally set velocity with it's
// own velocity.
if (m_active_combined_velocity) {
- parent->ResolveCombinedVelocities(
- m_linear_velocity,
- m_angular_velocity,
- (m_bitLocalFlag.LinearVelocity) != 0,
- (m_bitLocalFlag.AngularVelocity) != 0
- );
+ if (parent)
+ parent->ResolveCombinedVelocities(
+ m_linear_velocity,
+ m_angular_velocity,
+ (m_bitLocalFlag.LinearVelocity) != 0,
+ (m_bitLocalFlag.AngularVelocity) != 0
+ );
m_active_combined_velocity = false;
}
+ m_linear_damping_active = false;
+ m_angular_damping_active = false;
+ m_error_accumulator.setValue(0.0,0.0,0.0);
+ m_previous_error.setValue(0.0,0.0,0.0);
return false;
- } else
- if (parent)
+ } else if (parent)
{
- /* Probably better to use some flags, so these MT_zero tests can be */
- /* skipped. */
- if (!MT_fuzzyZero(m_force))
- {
- parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0);
- }
- if (!MT_fuzzyZero(m_torque))
- {
- parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0);
- }
- if (!MT_fuzzyZero(m_dloc))
+ if (m_bitLocalFlag.ServoControl)
{
- parent->ApplyMovement(m_dloc,(m_bitLocalFlag.DLoc) != 0);
- }
- if (!MT_fuzzyZero(m_drot))
- {
- parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0);
- }
- if (!MT_fuzzyZero(m_linear_velocity))
+ // In this mode, we try to reach a target speed using force
+ // As we don't know the friction, we must implement a generic
+ // servo control to achieve the speed in a configurable
+ // v = current velocity
+ // V = target velocity
+ // e = V-v = speed error
+ // dt = time interval since previous update
+ // I = sum(e(t)*dt)
+ // dv = e(t) - e(t-1)
+ // KP, KD, KI : coefficient
+ // F = KP*e+KI*I+KD*dv
+ MT_Scalar mass = parent->GetMass();
+ if (mass < MT_EPSILON)
+ return false;
+ MT_Vector3 v = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
+ MT_Vector3 e = m_linear_velocity - v;
+ MT_Vector3 dv = e - m_previous_error;
+ MT_Vector3 I = m_error_accumulator + e;
+
+ m_force = m_torque.x()*e+m_torque.y()*I+m_torque.z()*dv;
+ // to automatically adapt the PID coefficient to mass;
+ m_force *= mass;
+ if (m_bitLocalFlag.Torque)
+ {
+ if (m_force[0] > m_dloc[0])
+ {
+ m_force[0] = m_dloc[0];
+ I[0] = m_error_accumulator[0];
+ } else if (m_force[0] < m_drot[0])
+ {
+ m_force[0] = m_drot[0];
+ I[0] = m_error_accumulator[0];
+ }
+ }
+ if (m_bitLocalFlag.DLoc)
+ {
+ if (m_force[1] > m_dloc[1])
+ {
+ m_force[1] = m_dloc[1];
+ I[1] = m_error_accumulator[1];
+ } else if (m_force[1] < m_drot[1])
+ {
+ m_force[1] = m_drot[1];
+ I[1] = m_error_accumulator[1];
+ }
+ }
+ if (m_bitLocalFlag.DRot)
+ {
+ if (m_force[2] > m_dloc[2])
+ {
+ m_force[2] = m_dloc[2];
+ I[2] = m_error_accumulator[2];
+ } else if (m_force[2] < m_drot[2])
+ {
+ m_force[2] = m_drot[2];
+ I[2] = m_error_accumulator[2];
+ }
+ }
+ m_previous_error = e;
+ m_error_accumulator = I;
+ parent->ApplyForce(m_force,(m_bitLocalFlag.LinearVelocity) != 0);
+ } else
{
- if (m_bitLocalFlag.AddOrSetLinV) {
- parent->addLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
- } else {
+ if (!m_bitLocalFlag.ZeroForce)
+ {
+ parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0);
+ }
+ if (!m_bitLocalFlag.ZeroTorque)
+ {
+ parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0);
+ }
+ if (!m_bitLocalFlag.ZeroDLoc)
+ {
+ parent->ApplyMovement(m_dloc,(m_bitLocalFlag.DLoc) != 0);
+ }
+ if (!m_bitLocalFlag.ZeroDRot)
+ {
+ parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0);
+ }
+ if (!m_bitLocalFlag.ZeroLinearVelocity)
+ {
+ if (m_bitLocalFlag.AddOrSetLinV) {
+ parent->addLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
+ } else {
+ m_active_combined_velocity = true;
+ if (m_damping > 0) {
+ MT_Vector3 linV;
+ if (!m_linear_damping_active) {
+ // delta and the start speed (depends on the existing speed in that direction)
+ linV = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
+ // keep only the projection along the desired direction
+ m_current_linear_factor = linV.dot(m_linear_velocity)/m_linear_length2;
+ m_linear_damping_active = true;
+ }
+ if (m_current_linear_factor < 1.0)
+ m_current_linear_factor += 1.0/m_damping;
+ if (m_current_linear_factor > 1.0)
+ m_current_linear_factor = 1.0;
+ linV = m_current_linear_factor * m_linear_velocity;
+ parent->setLinearVelocity(linV,(m_bitLocalFlag.LinearVelocity) != 0);
+ } else {
+ parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
+ }
+ }
+ }
+ if (!m_bitLocalFlag.ZeroAngularVelocity)
+ {
m_active_combined_velocity = true;
- parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
+ if (m_damping > 0) {
+ MT_Vector3 angV;
+ if (!m_angular_damping_active) {
+ // delta and the start speed (depends on the existing speed in that direction)
+ angV = parent->GetAngularVelocity(m_bitLocalFlag.AngularVelocity);
+ // keep only the projection along the desired direction
+ m_current_angular_factor = angV.dot(m_angular_velocity)/m_angular_length2;
+ m_angular_damping_active = true;
+ }
+ if (m_current_angular_factor < 1.0)
+ m_current_angular_factor += 1.0/m_damping;
+ if (m_current_angular_factor > 1.0)
+ m_current_angular_factor = 1.0;
+ angV = m_current_angular_factor * m_angular_velocity;
+ parent->setAngularVelocity(angV,(m_bitLocalFlag.AngularVelocity) != 0);
+ } else {
+ parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0);
+ }
}
}
- if (!MT_fuzzyZero(m_angular_velocity))
- {
- parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0);
- m_active_combined_velocity = true;
- }
}
return true;
@@ -187,18 +304,29 @@ PyParentObject KX_ObjectActuator::Parents[] = {
};
PyMethodDef KX_ObjectActuator::Methods[] = {
- {"getForce", (PyCFunction) KX_ObjectActuator::sPyGetForce, METH_VARARGS},
+ {"getForce", (PyCFunction) KX_ObjectActuator::sPyGetForce, METH_NOARGS},
{"setForce", (PyCFunction) KX_ObjectActuator::sPySetForce, METH_VARARGS},
- {"getTorque", (PyCFunction) KX_ObjectActuator::sPyGetTorque, METH_VARARGS},
+ {"getTorque", (PyCFunction) KX_ObjectActuator::sPyGetTorque, METH_NOARGS},
{"setTorque", (PyCFunction) KX_ObjectActuator::sPySetTorque, METH_VARARGS},
- {"getDLoc", (PyCFunction) KX_ObjectActuator::sPyGetDLoc, METH_VARARGS},
+ {"getDLoc", (PyCFunction) KX_ObjectActuator::sPyGetDLoc, METH_NOARGS},
{"setDLoc", (PyCFunction) KX_ObjectActuator::sPySetDLoc, METH_VARARGS},
- {"getDRot", (PyCFunction) KX_ObjectActuator::sPyGetDRot, METH_VARARGS},
+ {"getDRot", (PyCFunction) KX_ObjectActuator::sPyGetDRot, METH_NOARGS},
{"setDRot", (PyCFunction) KX_ObjectActuator::sPySetDRot, METH_VARARGS},
- {"getLinearVelocity", (PyCFunction) KX_ObjectActuator::sPyGetLinearVelocity, METH_VARARGS},
+ {"getLinearVelocity", (PyCFunction) KX_ObjectActuator::sPyGetLinearVelocity, METH_NOARGS},
{"setLinearVelocity", (PyCFunction) KX_ObjectActuator::sPySetLinearVelocity, METH_VARARGS},
- {"getAngularVelocity", (PyCFunction) KX_ObjectActuator::sPyGetAngularVelocity, METH_VARARGS},
+ {"getAngularVelocity", (PyCFunction) KX_ObjectActuator::sPyGetAngularVelocity, METH_NOARGS},
{"setAngularVelocity", (PyCFunction) KX_ObjectActuator::sPySetAngularVelocity, METH_VARARGS},
+ {"setDamping", (PyCFunction) KX_ObjectActuator::sPySetDamping, METH_VARARGS},
+ {"getDamping", (PyCFunction) KX_ObjectActuator::sPyGetDamping, METH_NOARGS},
+ {"setForceLimitX", (PyCFunction) KX_ObjectActuator::sPySetForceLimitX, METH_VARARGS},
+ {"getForceLimitX", (PyCFunction) KX_ObjectActuator::sPyGetForceLimitX, METH_NOARGS},
+ {"setForceLimitY", (PyCFunction) KX_ObjectActuator::sPySetForceLimitY, METH_VARARGS},
+ {"getForceLimitY", (PyCFunction) KX_ObjectActuator::sPyGetForceLimitY, METH_NOARGS},
+ {"setForceLimitZ", (PyCFunction) KX_ObjectActuator::sPySetForceLimitZ, METH_VARARGS},
+ {"getForceLimitZ", (PyCFunction) KX_ObjectActuator::sPyGetForceLimitZ, METH_NOARGS},
+ {"setPID", (PyCFunction) KX_ObjectActuator::sPyGetPID, METH_NOARGS},
+ {"getPID", (PyCFunction) KX_ObjectActuator::sPySetPID, METH_VARARGS},
+
{NULL,NULL} //Sentinel
@@ -212,9 +340,7 @@ PyObject* KX_ObjectActuator::_getattr(const STR_String& attr) {
/* Removed! */
/* 2. getForce */
-PyObject* KX_ObjectActuator::PyGetForce(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_ObjectActuator::PyGetForce(PyObject* self)
{
PyObject *retVal = PyList_New(4);
@@ -238,13 +364,12 @@ PyObject* KX_ObjectActuator::PySetForce(PyObject* self,
}
m_force.setValue(vecArg);
m_bitLocalFlag.Force = PyArgToBool(bToggle);
+ UpdateFuzzyFlags();
Py_Return;
}
/* 4. getTorque */
-PyObject* KX_ObjectActuator::PyGetTorque(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_ObjectActuator::PyGetTorque(PyObject* self)
{
PyObject *retVal = PyList_New(4);
@@ -268,13 +393,12 @@ PyObject* KX_ObjectActuator::PySetTorque(PyObject* self,
}
m_torque.setValue(vecArg);
m_bitLocalFlag.Torque = PyArgToBool(bToggle);
+ UpdateFuzzyFlags();
Py_Return;
}
/* 6. getDLoc */
-PyObject* KX_ObjectActuator::PyGetDLoc(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_ObjectActuator::PyGetDLoc(PyObject* self)
{
PyObject *retVal = PyList_New(4);
@@ -298,13 +422,12 @@ PyObject* KX_ObjectActuator::PySetDLoc(PyObject* self,
}
m_dloc.setValue(vecArg);
m_bitLocalFlag.DLoc = PyArgToBool(bToggle);
+ UpdateFuzzyFlags();
Py_Return;
}
/* 8. getDRot */
-PyObject* KX_ObjectActuator::PyGetDRot(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_ObjectActuator::PyGetDRot(PyObject* self)
{
PyObject *retVal = PyList_New(4);
@@ -328,13 +451,12 @@ PyObject* KX_ObjectActuator::PySetDRot(PyObject* self,
}
m_drot.setValue(vecArg);
m_bitLocalFlag.DRot = PyArgToBool(bToggle);
+ UpdateFuzzyFlags();
Py_Return;
}
/* 10. getLinearVelocity */
-PyObject* KX_ObjectActuator::PyGetLinearVelocity(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_ObjectActuator::PyGetLinearVelocity(PyObject* self) {
PyObject *retVal = PyList_New(4);
PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0]));
@@ -357,14 +479,13 @@ PyObject* KX_ObjectActuator::PySetLinearVelocity(PyObject* self,
}
m_linear_velocity.setValue(vecArg);
m_bitLocalFlag.LinearVelocity = PyArgToBool(bToggle);
+ UpdateFuzzyFlags();
Py_Return;
}
/* 12. getAngularVelocity */
-PyObject* KX_ObjectActuator::PyGetAngularVelocity(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_ObjectActuator::PyGetAngularVelocity(PyObject* self) {
PyObject *retVal = PyList_New(4);
PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_angular_velocity[0]));
@@ -386,10 +507,133 @@ PyObject* KX_ObjectActuator::PySetAngularVelocity(PyObject* self,
}
m_angular_velocity.setValue(vecArg);
m_bitLocalFlag.AngularVelocity = PyArgToBool(bToggle);
+ UpdateFuzzyFlags();
+ Py_Return;
+}
+
+/* 13. setDamping */
+PyObject* KX_ObjectActuator::PySetDamping(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int damping = 0;
+ if (!PyArg_ParseTuple(args, "i", &damping) || damping < 0 || damping > 1000) {
+ return NULL;
+ }
+ m_damping = damping;
+ Py_Return;
+}
+
+/* 13. getVelocityDamping */
+PyObject* KX_ObjectActuator::PyGetDamping(PyObject* self) {
+ return Py_BuildValue("i",m_damping);
+}
+/* 6. getForceLimitX */
+PyObject* KX_ObjectActuator::PyGetForceLimitX(PyObject* self)
+{
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[0]));
+ PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.Torque));
+
+ return retVal;
+}
+/* 7. setForceLimitX */
+PyObject* KX_ObjectActuator::PySetForceLimitX(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float vecArg[2];
+ int bToggle = 0;
+ if(!PyArg_ParseTuple(args, "ffi", &vecArg[0], &vecArg[1], &bToggle)) {
+ return NULL;
+ }
+ m_drot[0] = vecArg[0];
+ m_dloc[0] = vecArg[1];
+ m_bitLocalFlag.Torque = PyArgToBool(bToggle);
+ Py_Return;
+}
+
+/* 6. getForceLimitY */
+PyObject* KX_ObjectActuator::PyGetForceLimitY(PyObject* self)
+{
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[1]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[1]));
+ PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.DLoc));
+
+ return retVal;
+}
+/* 7. setForceLimitY */
+PyObject* KX_ObjectActuator::PySetForceLimitY(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float vecArg[2];
+ int bToggle = 0;
+ if(!PyArg_ParseTuple(args, "ffi", &vecArg[0], &vecArg[1], &bToggle)) {
+ return NULL;
+ }
+ m_drot[1] = vecArg[0];
+ m_dloc[1] = vecArg[1];
+ m_bitLocalFlag.DLoc = PyArgToBool(bToggle);
+ Py_Return;
+}
+
+/* 6. getForceLimitZ */
+PyObject* KX_ObjectActuator::PyGetForceLimitZ(PyObject* self)
+{
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[2]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[2]));
+ PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.DRot));
+
+ return retVal;
+}
+/* 7. setForceLimitZ */
+PyObject* KX_ObjectActuator::PySetForceLimitZ(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float vecArg[2];
+ int bToggle = 0;
+ if(!PyArg_ParseTuple(args, "ffi", &vecArg[0], &vecArg[1], &bToggle)) {
+ return NULL;
+ }
+ m_drot[2] = vecArg[0];
+ m_dloc[2] = vecArg[1];
+ m_bitLocalFlag.DRot = PyArgToBool(bToggle);
+ Py_Return;
+}
+
+/* 4. getPID */
+PyObject* KX_ObjectActuator::PyGetPID(PyObject* self)
+{
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_torque[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_torque[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_torque[2]));
+
+ return retVal;
+}
+/* 5. setPID */
+PyObject* KX_ObjectActuator::PySetPID(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float vecArg[3];
+ if (!PyArg_ParseTuple(args, "fff", &vecArg[0], &vecArg[1], &vecArg[2])) {
+ return NULL;
+ }
+ m_torque.setValue(vecArg);
Py_Return;
}
+
/* eof */
diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.h b/source/gameengine/Ketsji/KX_ObjectActuator.h
index edbae154b8b..aa686f41233 100644
--- a/source/gameengine/Ketsji/KX_ObjectActuator.h
+++ b/source/gameengine/Ketsji/KX_ObjectActuator.h
@@ -46,7 +46,12 @@ struct KX_LocalFlags {
DLoc(false),
LinearVelocity(false),
AngularVelocity(false),
- AddOrSetLinV(false)
+ AddOrSetLinV(false),
+ ZeroForce(false),
+ ZeroDRot(false),
+ ZeroDLoc(false),
+ ZeroLinearVelocity(false),
+ ZeroAngularVelocity(false)
{
}
@@ -57,6 +62,13 @@ struct KX_LocalFlags {
unsigned short LinearVelocity : 1;
unsigned short AngularVelocity : 1;
unsigned short AddOrSetLinV : 1;
+ unsigned short ServoControl : 1;
+ unsigned short ZeroForce : 1;
+ unsigned short ZeroTorque : 1;
+ unsigned short ZeroDRot : 1;
+ unsigned short ZeroDLoc : 1;
+ unsigned short ZeroLinearVelocity : 1;
+ unsigned short ZeroAngularVelocity : 1;
};
class KX_ObjectActuator : public SCA_IActuator
@@ -69,6 +81,15 @@ class KX_ObjectActuator : public SCA_IActuator
MT_Vector3 m_drot;
MT_Vector3 m_linear_velocity;
MT_Vector3 m_angular_velocity;
+ MT_Scalar m_linear_length2;
+ MT_Scalar m_angular_length2;
+ // used in damping
+ MT_Scalar m_current_linear_factor;
+ MT_Scalar m_current_angular_factor;
+ short m_damping;
+ // used in servo control
+ MT_Vector3 m_previous_error;
+ MT_Vector3 m_error_accumulator;
KX_LocalFlags m_bitLocalFlag;
// A hack bool -- oh no sorry everyone
@@ -77,6 +98,8 @@ class KX_ObjectActuator : public SCA_IActuator
// setting linear velocity.
bool m_active_combined_velocity;
+ bool m_linear_damping_active;
+ bool m_angular_damping_active;
public:
enum KX_OBJECT_ACT_VEC_TYPE {
@@ -103,6 +126,7 @@ public:
const MT_Vector3& drot,
const MT_Vector3& linV,
const MT_Vector3& angV,
+ const short damping,
const KX_LocalFlags& flag,
PyTypeObject* T=&Type
);
@@ -110,6 +134,17 @@ public:
CValue* GetReplica();
void SetForceLoc(const double force[3]) { /*m_force=force;*/ }
+ void UpdateFuzzyFlags()
+ {
+ m_bitLocalFlag.ZeroForce = MT_fuzzyZero(m_force);
+ m_bitLocalFlag.ZeroTorque = MT_fuzzyZero(m_torque);
+ m_bitLocalFlag.ZeroDLoc = MT_fuzzyZero(m_dloc);
+ m_bitLocalFlag.ZeroDRot = MT_fuzzyZero(m_drot);
+ m_bitLocalFlag.ZeroLinearVelocity = MT_fuzzyZero(m_linear_velocity);
+ m_linear_length2 = (m_bitLocalFlag.ZeroLinearVelocity) ? 0.0 : m_linear_velocity.length2();
+ m_bitLocalFlag.ZeroAngularVelocity = MT_fuzzyZero(m_angular_velocity);
+ m_angular_length2 = (m_bitLocalFlag.ZeroAngularVelocity) ? 0.0 : m_angular_velocity.length2();
+ }
virtual bool Update();
@@ -120,18 +155,28 @@ public:
virtual PyObject* _getattr(const STR_String& attr);
- KX_PYMETHOD(KX_ObjectActuator,GetForce);
+ KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForce);
KX_PYMETHOD(KX_ObjectActuator,SetForce);
- KX_PYMETHOD(KX_ObjectActuator,GetTorque);
+ KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetTorque);
KX_PYMETHOD(KX_ObjectActuator,SetTorque);
- KX_PYMETHOD(KX_ObjectActuator,GetDLoc);
+ KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetDLoc);
KX_PYMETHOD(KX_ObjectActuator,SetDLoc);
- KX_PYMETHOD(KX_ObjectActuator,GetDRot);
+ KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetDRot);
KX_PYMETHOD(KX_ObjectActuator,SetDRot);
- KX_PYMETHOD(KX_ObjectActuator,GetLinearVelocity);
+ KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetLinearVelocity);
KX_PYMETHOD(KX_ObjectActuator,SetLinearVelocity);
- KX_PYMETHOD(KX_ObjectActuator,GetAngularVelocity);
+ KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetAngularVelocity);
KX_PYMETHOD(KX_ObjectActuator,SetAngularVelocity);
+ KX_PYMETHOD(KX_ObjectActuator,SetDamping);
+ KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetDamping);
+ KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForceLimitX);
+ KX_PYMETHOD(KX_ObjectActuator,SetForceLimitX);
+ KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForceLimitY);
+ KX_PYMETHOD(KX_ObjectActuator,SetForceLimitY);
+ KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetForceLimitZ);
+ KX_PYMETHOD(KX_ObjectActuator,SetForceLimitZ);
+ KX_PYMETHOD_NOARGS(KX_ObjectActuator,GetPID);
+ KX_PYMETHOD(KX_ObjectActuator,SetPID);
};
#endif //__KX_OBJECTACTUATOR
diff --git a/source/gameengine/Ketsji/KX_OdePhysicsController.cpp b/source/gameengine/Ketsji/KX_OdePhysicsController.cpp
index 4e45ce484e3..6a701a5f25b 100644
--- a/source/gameengine/Ketsji/KX_OdePhysicsController.cpp
+++ b/source/gameengine/Ketsji/KX_OdePhysicsController.cpp
@@ -133,8 +133,9 @@ void KX_OdePhysicsController::SetLinearVelocity(const MT_Vector3& lin_vel,bool l
ODEPhysicsController::SetLinearVelocity(lin_vel[0],lin_vel[1],lin_vel[2],local);
}
-void KX_OdePhysicsController::setOrientation(const MT_Quaternion& orn)
+void KX_OdePhysicsController::setOrientation(const MT_Matrix3x3& rot)
{
+ MT_Quaternion orn = rot.getRotation();
ODEPhysicsController::setOrientation(orn[0],orn[1],orn[2],orn[3]);
}
@@ -168,6 +169,11 @@ MT_Scalar KX_OdePhysicsController::GetMass()
return ODEPhysicsController::getMass();
}
+MT_Scalar KX_OdePhysicsController::GetRadius()
+{
+ return MT_Scalar(0.f);
+}
+
MT_Vector3 KX_OdePhysicsController::getReactionForce()
{
return MT_Vector3(0,0,0);
@@ -177,7 +183,7 @@ void KX_OdePhysicsController::setRigidBody(bool rigid)
}
-void KX_OdePhysicsController::SuspendDynamics()
+void KX_OdePhysicsController::SuspendDynamics(bool)
{
ODEPhysicsController::SuspendDynamics();
}
diff --git a/source/gameengine/Ketsji/KX_OdePhysicsController.h b/source/gameengine/Ketsji/KX_OdePhysicsController.h
index 07a0bee9775..53050f6ce3e 100644
--- a/source/gameengine/Ketsji/KX_OdePhysicsController.h
+++ b/source/gameengine/Ketsji/KX_OdePhysicsController.h
@@ -67,16 +67,16 @@ public:
virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local);
virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ);
virtual void getOrientation(MT_Quaternion& orn);
- virtual void setOrientation(const MT_Quaternion& orn);
+ virtual void setOrientation(const MT_Matrix3x3& orn);
virtual void setPosition(const MT_Point3& pos);
virtual void setScaling(const MT_Vector3& scaling);
virtual MT_Scalar GetMass();
virtual MT_Vector3 getReactionForce();
virtual void setRigidBody(bool rigid);
- virtual void SuspendDynamics();
+ virtual void SuspendDynamics(bool);
virtual void RestoreDynamics();
-
+ virtual MT_Scalar GetRadius();
virtual SG_Controller* GetReplica(class SG_Node* destnode);
diff --git a/source/gameengine/Ketsji/KX_ParentActuator.cpp b/source/gameengine/Ketsji/KX_ParentActuator.cpp
new file mode 100644
index 00000000000..89549ca6b57
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ParentActuator.cpp
@@ -0,0 +1,221 @@
+/**
+ * Set or remove an objects parent
+ *
+ * $Id: SCA_ParentActuator.cpp 13932 2008-03-01 19:05:41Z ben2610 $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "KX_ParentActuator.h"
+#include "KX_GameObject.h"
+#include "KX_PythonInit.h"
+
+#include "PyObjectPlus.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+KX_ParentActuator::KX_ParentActuator(SCA_IObject *gameobj,
+ int mode,
+ SCA_IObject *ob,
+ PyTypeObject* T)
+ : SCA_IActuator(gameobj, T),
+ m_mode(mode),
+ m_ob(ob)
+{
+ if (m_ob)
+ m_ob->RegisterActuator(this);
+}
+
+
+
+KX_ParentActuator::~KX_ParentActuator()
+{
+ if (m_ob)
+ m_ob->UnregisterActuator(this);
+}
+
+
+
+CValue* KX_ParentActuator::GetReplica()
+{
+ KX_ParentActuator* replica = new KX_ParentActuator(*this);
+ // replication just copy the m_base pointer => common random generator
+ replica->ProcessReplica();
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+}
+
+void KX_ParentActuator::ProcessReplica()
+{
+ if (m_ob)
+ m_ob->RegisterActuator(this);
+ SCA_IActuator::ProcessReplica();
+}
+
+
+bool KX_ParentActuator::UnlinkObject(SCA_IObject* clientobj)
+{
+ if (clientobj == m_ob)
+ {
+ // this object is being deleted, we cannot continue to track it.
+ m_ob = NULL;
+ return true;
+ }
+ return false;
+}
+
+void KX_ParentActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
+{
+ void **h_obj = (*obj_map)[m_ob];
+ if (h_obj) {
+ if (m_ob)
+ m_ob->UnregisterActuator(this);
+ m_ob = (SCA_IObject*)(*h_obj);
+ m_ob->RegisterActuator(this);
+ }
+}
+
+
+
+bool KX_ParentActuator::Update()
+{
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (bNegativeEvent)
+ return false; // do nothing on negative events
+
+ KX_GameObject *obj = (KX_GameObject*) GetParent();
+ KX_Scene *scene = KX_GetActiveScene();
+ switch (m_mode) {
+ case KX_PARENT_SET:
+ if (m_ob)
+ obj->SetParent(scene, (KX_GameObject*)m_ob);
+ break;
+ case KX_PARENT_REMOVE:
+ obj->RemoveParent(scene);
+ break;
+ };
+
+ return false;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_ParentActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_ParentActuator",
+ sizeof(KX_ParentActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_ParentActuator::Parents[] = {
+ &KX_ParentActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_ParentActuator::Methods[] = {
+ {"setObject", (PyCFunction) KX_ParentActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc},
+ {"getObject", (PyCFunction) KX_ParentActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* KX_ParentActuator::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_IActuator);
+}
+
+/* 1. setObject */
+const char KX_ParentActuator::SetObject_doc[] =
+"setObject(object)\n"
+"\t- object: KX_GameObject, string or None\n"
+"\tSet the object to set as parent.\n";
+PyObject* KX_ParentActuator::PySetObject(PyObject* self, PyObject* value) {
+ KX_GameObject *gameobj;
+
+ if (!ConvertPythonToGameObject(value, &gameobj, true))
+ return NULL; // ConvertPythonToGameObject sets the error
+
+ if (m_ob != NULL)
+ m_ob->UnregisterActuator(this);
+
+ m_ob = (SCA_IObject*)gameobj;
+ if (m_ob)
+ m_ob->RegisterActuator(this);
+
+ Py_RETURN_NONE;
+}
+
+/* 2. getObject */
+
+/* get obj ---------------------------------------------------------- */
+const char KX_ParentActuator::GetObject_doc[] =
+"getObject(name_only = 1)\n"
+"name_only - optional arg, when true will return the KX_GameObject rather then its name\n"
+"\tReturns the object that is set to.\n";
+PyObject* KX_ParentActuator::PyGetObject(PyObject* self, PyObject* args)
+{
+ int ret_name_only = 1;
+ if (!PyArg_ParseTuple(args, "|i", &ret_name_only))
+ return NULL;
+
+ if (!m_ob)
+ Py_RETURN_NONE;
+
+ if (ret_name_only)
+ return PyString_FromString(m_ob->GetName());
+ else
+ return m_ob->AddRef();
+}
+
+/* eof */
diff --git a/source/gameengine/Ketsji/KX_ParentActuator.h b/source/gameengine/Ketsji/KX_ParentActuator.h
new file mode 100644
index 00000000000..e2b30ba2d0f
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_ParentActuator.h
@@ -0,0 +1,89 @@
+/**
+ * Set or remove an objects parent
+ *
+ *
+ * $Id: KX_ParentActuator.h 3271 2004-10-16 11:41:50Z kester $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __KX_PARENTACTUATOR
+#define __KX_PARENTACTUATOR
+
+#include "SCA_IActuator.h"
+#include "SCA_LogicManager.h"
+
+class KX_ParentActuator : public SCA_IActuator
+{
+ Py_Header;
+
+ /** Mode */
+ int m_mode;
+
+ /** Object to set as parent */
+ SCA_IObject *m_ob;
+
+
+
+ public:
+ enum KX_PARENTACT_MODE
+ {
+ KX_PARENT_NODEF = 0,
+ KX_PARENT_SET,
+ KX_PARENT_REMOVE,
+
+ };
+
+ KX_ParentActuator(class SCA_IObject* gameobj,
+ int mode,
+ SCA_IObject *ob,
+ PyTypeObject* T=&Type);
+ virtual ~KX_ParentActuator();
+ virtual bool Update();
+
+ virtual CValue* GetReplica();
+ virtual void ProcessReplica();
+ virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
+ virtual bool UnlinkObject(SCA_IObject* clientobj);
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ /* 1. setObject */
+ KX_PYMETHOD_DOC_O(KX_ParentActuator,SetObject);
+ /* 2. getObject */
+ KX_PYMETHOD_DOC_VARARGS(KX_ParentActuator,GetObject);
+
+}; /* end of class KX_ParentActuator : public SCA_PropertyActuator */
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp
index 27cfaefc076..da4f05ced7c 100644
--- a/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp
+++ b/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp
@@ -27,6 +27,8 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include <Python.h>
+#include "PyObjectPlus.h"
+
#include "KX_PhysicsObjectWrapper.h"
#include "PHY_IPhysicsEnvironment.h"
#include "PHY_IPhysicsController.h"
@@ -58,7 +60,10 @@ PyObject* KX_PhysicsObjectWrapper::PySetPosition(PyObject* self,
{
m_ctrl->setPosition(x,y,z);
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
@@ -72,7 +77,10 @@ PyObject* KX_PhysicsObjectWrapper::PySetLinearVelocity(PyObject* self,
{
m_ctrl->SetLinearVelocity(x,y,z,local != 0);
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
PyObject* KX_PhysicsObjectWrapper::PySetAngularVelocity(PyObject* self,
@@ -85,7 +93,10 @@ PyObject* KX_PhysicsObjectWrapper::PySetAngularVelocity(PyObject* self,
{
m_ctrl->SetAngularVelocity(x,y,z,local != 0);
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
PyObject* KX_PhysicsObjectWrapper::PySetActive(PyObject* self,
@@ -97,7 +108,10 @@ PyObject* KX_PhysicsObjectWrapper::PySetActive(PyObject* self,
{
m_ctrl->SetActive(active!=0);
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
diff --git a/source/gameengine/Ketsji/KX_PolyProxy.cpp b/source/gameengine/Ketsji/KX_PolyProxy.cpp
new file mode 100644
index 00000000000..c6f6bc2db01
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PolyProxy.cpp
@@ -0,0 +1,265 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "KX_PolyProxy.h"
+#include "KX_MeshProxy.h"
+#include "RAS_MeshObject.h"
+#include "KX_BlenderMaterial.h"
+#include "KX_PolygonMaterial.h"
+
+#include "KX_PyMath.h"
+
+PyTypeObject KX_PolyProxy::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_PolyProxy",
+ sizeof(KX_PolyProxy),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_PolyProxy::Parents[] = {
+ &KX_PolyProxy::Type,
+ &SCA_IObject::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef KX_PolyProxy::Methods[] = {
+ KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterialIndex),
+ KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getNumVertex),
+ KX_PYMETHODTABLE_NOARG(KX_PolyProxy,isVisible),
+ KX_PYMETHODTABLE_NOARG(KX_PolyProxy,isCollider),
+ KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterialName),
+ KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getTextureName),
+ KX_PYMETHODTABLE(KX_PolyProxy,getVertexIndex),
+ KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMesh),
+ KX_PYMETHODTABLE_NOARG(KX_PolyProxy,getMaterial),
+ {NULL,NULL} //Sentinel
+};
+
+PyObject*
+KX_PolyProxy::_getattr(const STR_String& attr)
+{
+ if (attr == "matname")
+ {
+ return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName());
+ }
+ if (attr == "texture")
+ {
+ return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName());
+ }
+ if (attr == "material")
+ {
+ RAS_IPolyMaterial *polymat = m_polygon->GetMaterial()->GetPolyMaterial();
+ if(polymat->GetFlag() & RAS_BLENDERMAT)
+ {
+ KX_BlenderMaterial* mat = static_cast<KX_BlenderMaterial*>(polymat);
+ Py_INCREF(mat);
+ return mat;
+ }
+ else
+ {
+ KX_PolygonMaterial* mat = static_cast<KX_PolygonMaterial*>(polymat);
+ Py_INCREF(mat);
+ return mat;
+ }
+ }
+ if (attr == "matid")
+ {
+ // we'll have to scan through the material bucket of the mes and compare with
+ // the one of the polygon
+ RAS_MaterialBucket* polyBucket = m_polygon->GetMaterial();
+ unsigned int matid;
+ for (matid=0; matid<m_mesh->NumMaterials(); matid++)
+ {
+ RAS_MeshMaterial* meshMat = m_mesh->GetMeshMaterial(matid);
+ if (meshMat->m_bucket == polyBucket)
+ // found it
+ break;
+ }
+ return PyInt_FromLong(matid);
+ }
+ if (attr == "v1")
+ {
+ return PyInt_FromLong(m_polygon->GetVertexOffset(0));
+ }
+ if (attr == "v2")
+ {
+ return PyInt_FromLong(m_polygon->GetVertexOffset(1));
+ }
+ if (attr == "v3")
+ {
+ return PyInt_FromLong(m_polygon->GetVertexOffset(2));
+ }
+ if (attr == "v4")
+ {
+ return PyInt_FromLong(((m_polygon->VertexCount()>3)?m_polygon->GetVertexOffset(3):0));
+ }
+ if (attr == "visible")
+ {
+ return PyInt_FromLong(m_polygon->IsVisible());
+ }
+ if (attr == "collide")
+ {
+ return PyInt_FromLong(m_polygon->IsCollider());
+ }
+ _getattr_up(SCA_IObject);
+}
+
+KX_PolyProxy::KX_PolyProxy(const RAS_MeshObject*mesh, RAS_Polygon* polygon)
+: m_mesh((RAS_MeshObject*)mesh),
+ m_polygon(polygon)
+{
+}
+
+KX_PolyProxy::~KX_PolyProxy()
+{
+}
+
+
+// stuff for cvalue related things
+CValue* KX_PolyProxy::Calc(VALUE_OPERATOR, CValue *) { return NULL;}
+CValue* KX_PolyProxy::CalcFinal(VALUE_DATA_TYPE, VALUE_OPERATOR, CValue *) { return NULL;}
+STR_String sPolyName="polygone";
+const STR_String & KX_PolyProxy::GetText() {return sPolyName;};
+float KX_PolyProxy::GetNumber() { return -1;}
+STR_String KX_PolyProxy::GetName() { return sPolyName;}
+void KX_PolyProxy::SetName(STR_String) { };
+CValue* KX_PolyProxy::GetReplica() { return NULL;}
+void KX_PolyProxy::ReplicaSetName(STR_String) {};
+
+
+// stuff for python integration
+
+KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterialIndex,
+"getMaterialIndex() : return the material index of the polygon in the mesh\n")
+{
+ RAS_MaterialBucket* polyBucket = m_polygon->GetMaterial();
+ unsigned int matid;
+ for (matid=0; matid<m_mesh->NumMaterials(); matid++)
+ {
+ RAS_MeshMaterial* meshMat = m_mesh->GetMeshMaterial(matid);
+ if (meshMat->m_bucket == polyBucket)
+ // found it
+ break;
+ }
+ return PyInt_FromLong(matid);
+}
+
+KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getNumVertex,
+"getNumVertex() : returns the number of vertex of the polygon, 3 or 4\n")
+{
+ return PyInt_FromLong(m_polygon->VertexCount());
+}
+
+KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, isVisible,
+"isVisible() : returns whether the polygon is visible or not\n")
+{
+ return PyInt_FromLong(m_polygon->IsVisible());
+}
+
+KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, isCollider,
+"isCollider() : returns whether the polygon is receives collision or not\n")
+{
+ return PyInt_FromLong(m_polygon->IsCollider());
+}
+
+KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterialName,
+"getMaterialName() : returns the polygon material name, \"NoMaterial\" if no material\n")
+{
+ return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName());
+}
+
+KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getTextureName,
+"getTexturelName() : returns the polygon texture name, \"NULL\" if no texture\n")
+{
+ return PyString_FromString(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName());
+}
+
+KX_PYMETHODDEF_DOC(KX_PolyProxy, getVertexIndex,
+"getVertexIndex(vertex) : returns the mesh vertex index of a polygon vertex\n"
+"vertex: index of the vertex in the polygon: 0->3\n"
+"return value can be used to retrieve the vertex details through mesh proxy\n"
+"Note: getVertexIndex(3) on a triangle polygon returns 0\n")
+{
+ int index;
+ if (!PyArg_ParseTuple(args,"i",&index))
+ {
+ return NULL;
+ }
+ if (index < 0 || index > 3)
+ {
+ PyErr_SetString(PyExc_AttributeError, "Valid range for index is 0-3");
+ return NULL;
+ }
+ if (index < m_polygon->VertexCount())
+ {
+ return PyInt_FromLong(m_polygon->GetVertexOffset(index));
+ }
+ return PyInt_FromLong(0);
+}
+
+KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMesh,
+"getMesh() : returns a mesh proxy\n")
+{
+ KX_MeshProxy* meshproxy = new KX_MeshProxy((RAS_MeshObject*)m_mesh);
+ return meshproxy;
+}
+
+KX_PYMETHODDEF_DOC_NOARG(KX_PolyProxy, getMaterial,
+"getMaterial() : returns a material\n")
+{
+ RAS_IPolyMaterial *polymat = m_polygon->GetMaterial()->GetPolyMaterial();
+ if(polymat->GetFlag() & RAS_BLENDERMAT)
+ {
+ KX_BlenderMaterial* mat = static_cast<KX_BlenderMaterial*>(polymat);
+ Py_INCREF(mat);
+ return mat;
+ }
+ else
+ {
+ KX_PolygonMaterial* mat = static_cast<KX_PolygonMaterial*>(polymat);
+ Py_INCREF(mat);
+ return mat;
+ }
+}
diff --git a/source/gameengine/Ketsji/KX_PolyProxy.h b/source/gameengine/Ketsji/KX_PolyProxy.h
new file mode 100644
index 00000000000..506e2c2a656
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_PolyProxy.h
@@ -0,0 +1,71 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __KX_POLYROXY
+#define __KX_POLYPROXY
+
+#include "SCA_IObject.h"
+
+class KX_PolyProxy : public SCA_IObject
+{
+ Py_Header;
+protected:
+ class RAS_Polygon* m_polygon;
+ class RAS_MeshObject* m_mesh;
+public:
+ KX_PolyProxy(const class RAS_MeshObject*mesh, class RAS_Polygon* polygon);
+ virtual ~KX_PolyProxy();
+
+ // stuff for cvalue related things
+ CValue* Calc(VALUE_OPERATOR op, CValue *val) ;
+ CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
+ const STR_String & GetText();
+ float GetNumber();
+ STR_String GetName();
+ void SetName(STR_String name); // Set the name of the value
+ void ReplicaSetName(STR_String name);
+ CValue* GetReplica();
+
+
+// stuff for python integration
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterialIndex)
+ KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getNumVertex)
+ KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,isVisible)
+ KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,isCollider)
+ KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterialName)
+ KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getTextureName)
+ KX_PYMETHOD_DOC(KX_PolyProxy,getVertexIndex)
+ KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMesh)
+ KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterial)
+
+};
+
+#endif //__KX_POLYPROXY
+
diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp
index 70333b33d2c..c9180bf3a80 100644
--- a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp
+++ b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp
@@ -35,10 +35,6 @@
#include "BKE_global.h"
#include "BKE_image.h"
-extern "C" {
-//XXX #include "BDR_drawmesh.h"
-}
-
#include "DNA_material_types.h"
#include "DNA_texture_types.h"
#include "DNA_image_types.h"
@@ -46,6 +42,8 @@ extern "C" {
#include "IMB_imbuf_types.h"
+#include "GPU_draw.h"
+
#include "MEM_guardedalloc.h"
#include "RAS_LightObject.h"
@@ -59,11 +57,10 @@ KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname,
int tilexrep,
int tileyrep,
int mode,
- bool transparant,
+ int transp,
+ bool alpha,
bool zsort,
int lightlayer,
- bool bIsTriangle,
- void* clientobject,
struct MTFace* tface,
unsigned int* mcol,
PyTypeObject *T)
@@ -74,11 +71,10 @@ KX_PolygonMaterial::KX_PolygonMaterial(const STR_String &texname,
tilexrep,
tileyrep,
mode,
- transparant,
+ transp,
+ alpha,
zsort,
- lightlayer,
- bIsTriangle,
- clientobject),
+ lightlayer),
m_tface(tface),
m_mcol(mcol),
m_material(material),
@@ -138,38 +134,29 @@ void KX_PolygonMaterial::DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& c
if (GetCachingInfo() != cachingInfo)
{
if (!cachingInfo)
- {
- //XXX set_tpage(NULL);
- }
+ GPU_set_tpage(NULL);
+
cachingInfo = GetCachingInfo();
if ((m_drawingmode & 4)&& (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED))
{
- update_realtime_texture((struct MTFace*) m_tface, rasty->GetTime());
- //XXX set_tpage(m_tface);
- rasty->EnableTextures(true);
+ Image *ima = (Image*)m_tface->tpage;
+ GPU_update_image_time(ima, rasty->GetTime());
+ GPU_set_tpage(m_tface);
}
else
- {
- //XXX set_tpage(NULL);
- rasty->EnableTextures(false);
- }
+ GPU_set_tpage(NULL);
if(m_drawingmode & RAS_IRasterizer::KX_TWOSIDE)
- {
rasty->SetCullFace(false);
- }
else
- {
rasty->SetCullFace(true);
- }
- if (m_drawingmode & RAS_IRasterizer::KX_LINES) {
+ if ((m_drawingmode & RAS_IRasterizer::KX_LINES) ||
+ (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
rasty->SetLines(true);
- }
- else {
+ else
rasty->SetLines(false);
- }
}
rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity);
@@ -245,13 +232,14 @@ PyObject* KX_PolygonMaterial::_getattr(const STR_String& attr)
if (attr == "drawingmode")
return PyInt_FromLong(m_drawingmode);
if (attr == "transparent")
- return PyInt_FromLong(m_transparant);
+ return PyInt_FromLong(m_alpha);
if (attr == "zsort")
return PyInt_FromLong(m_zsort);
if (attr == "lightlayer")
return PyInt_FromLong(m_lightlayer);
if (attr == "triangle")
- return PyInt_FromLong(m_bIsTriangle);
+ // deprecated, triangle/quads shouldn't have been a material property
+ return 0;
if (attr == "diffuse")
return PyObjectFrom(m_diffuse);
@@ -312,7 +300,7 @@ int KX_PolygonMaterial::_setattr(const STR_String &attr, PyObject *pyvalue)
if (attr == "transparent")
{
- m_transparant = value;
+ m_alpha = value;
return 0;
}
@@ -331,7 +319,7 @@ int KX_PolygonMaterial::_setattr(const STR_String &attr, PyObject *pyvalue)
// This probably won't work...
if (attr == "triangle")
{
- m_bIsTriangle = value;
+ // deprecated, triangle/quads shouldn't have been a material property
return 0;
}
}
@@ -384,7 +372,9 @@ KX_PYMETHODDEF_DOC(KX_PolygonMaterial, updateTexture, "updateTexture(tface, rast
{
MTFace *tface = (MTFace*) PyCObject_AsVoidPtr(pytface);
RAS_IRasterizer *rasty = (RAS_IRasterizer*) PyCObject_AsVoidPtr(pyrasty);
- update_realtime_texture(tface, rasty->GetTime());
+ Image *ima = (Image*)tface->tpage;
+ GPU_update_image_time(ima, rasty->GetTime());
+
Py_Return;
}
@@ -397,7 +387,7 @@ KX_PYMETHODDEF_DOC(KX_PolygonMaterial, setTexture, "setTexture(tface)")
if (PyArg_ParseTuple(args, "O!", &PyCObject_Type, &pytface))
{
MTFace *tface = (MTFace*) PyCObject_AsVoidPtr(pytface);
- //XXX set_tpage(tface);
+ GPU_set_tpage(tface);
Py_Return;
}
diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.h b/source/gameengine/Ketsji/KX_PolygonMaterial.h
index 19015494e06..fe116f757db 100644
--- a/source/gameengine/Ketsji/KX_PolygonMaterial.h
+++ b/source/gameengine/Ketsji/KX_PolygonMaterial.h
@@ -64,11 +64,10 @@ public:
int tilexrep,
int tileyrep,
int mode,
- bool transparant,
+ int transp,
+ bool alpha,
bool zsort,
int lightlayer,
- bool bIsTriangle,
- void* clientobject,
struct MTFace* tface,
unsigned int* mcol,
PyTypeObject *T = &Type);
diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
index 172882ff18d..fb37eded450 100644
--- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
+++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
@@ -34,6 +34,8 @@
#include "PHY_IPhysicsController.h"
#include "PHY_IVehicle.h"
+#include "PyObjectPlus.h"
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -82,13 +84,16 @@ static PyObject* gPySetGravity(PyObject* self,
PyObject* kwds)
{
float x,y,z;
- int len = PyTuple_Size(args);
- if ((len == 3) && PyArg_ParseTuple(args,"fff",&x,&y,&z))
+ if (PyArg_ParseTuple(args,"fff",&x,&y,&z))
{
if (PHY_GetActiveEnvironment())
PHY_GetActiveEnvironment()->setGravity(x,y,z);
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
}
static PyObject* gPySetDebugMode(PyObject* self,
@@ -105,7 +110,11 @@ static PyObject* gPySetDebugMode(PyObject* self,
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
}
@@ -122,7 +131,10 @@ static PyObject* gPySetNumTimeSubSteps(PyObject* self,
PHY_GetActiveEnvironment()->setNumTimeSubSteps(substep);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
@@ -138,7 +150,10 @@ static PyObject* gPySetNumIterations(PyObject* self,
PHY_GetActiveEnvironment()->setNumIterations(iter);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
@@ -155,7 +170,10 @@ static PyObject* gPySetDeactivationTime(PyObject* self,
PHY_GetActiveEnvironment()->setDeactivationTime(deactive_time);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
@@ -171,7 +189,10 @@ static PyObject* gPySetDeactivationLinearTreshold(PyObject* self,
PHY_GetActiveEnvironment()->setDeactivationLinearTreshold( linearDeactivationTreshold);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
@@ -187,7 +208,10 @@ static PyObject* gPySetDeactivationAngularTreshold(PyObject* self,
PHY_GetActiveEnvironment()->setDeactivationAngularTreshold( angularDeactivationTreshold);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
static PyObject* gPySetContactBreakingTreshold(PyObject* self,
@@ -202,7 +226,10 @@ static PyObject* gPySetContactBreakingTreshold(PyObject* self,
PHY_GetActiveEnvironment()->setContactBreakingTreshold( contactBreakingTreshold);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
@@ -218,7 +245,10 @@ static PyObject* gPySetCcdMode(PyObject* self,
PHY_GetActiveEnvironment()->setCcdMode( ccdMode);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
static PyObject* gPySetSorConstant(PyObject* self,
@@ -233,7 +263,10 @@ static PyObject* gPySetSorConstant(PyObject* self,
PHY_GetActiveEnvironment()->setSolverSorConstant( sor);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
static PyObject* gPySetSolverTau(PyObject* self,
@@ -248,7 +281,10 @@ static PyObject* gPySetSolverTau(PyObject* self,
PHY_GetActiveEnvironment()->setSolverTau( tau);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
@@ -264,7 +300,10 @@ static PyObject* gPySetSolverDamping(PyObject* self,
PHY_GetActiveEnvironment()->setSolverDamping( damping);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
static PyObject* gPySetLinearAirDamping(PyObject* self,
@@ -279,7 +318,10 @@ static PyObject* gPySetLinearAirDamping(PyObject* self,
PHY_GetActiveEnvironment()->setLinearAirDamping( damping);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
@@ -295,7 +337,10 @@ static PyObject* gPySetUseEpa(PyObject* self,
PHY_GetActiveEnvironment()->setUseEpa(epa);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
static PyObject* gPySetSolverType(PyObject* self,
PyObject* args,
@@ -309,7 +354,10 @@ static PyObject* gPySetSolverType(PyObject* self,
PHY_GetActiveEnvironment()->setSolverType(solverType);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
@@ -338,8 +386,11 @@ static PyObject* gPyGetVehicleConstraint(PyObject* self,
}
}
+ else {
+ return NULL;
+ }
- Py_INCREF(Py_None); return Py_None;
+ Py_RETURN_NONE;
}
@@ -384,7 +435,7 @@ static PyObject* gPyCreateConstraint(PyObject* self,
PHY_IPhysicsController* physctrl2 = (PHY_IPhysicsController*) physicsid2;
if (physctrl) //TODO:check for existance of this pointer!
{
- int constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,pivotX,pivotY,pivotZ,axisX,axisY,axisZ);
+ int constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,pivotX,pivotY,pivotZ,axisX,axisY,axisZ,0);
KX_ConstraintWrapper* wrap = new KX_ConstraintWrapper((enum PHY_ConstraintType)constrainttype,constraintid,PHY_GetActiveEnvironment());
@@ -395,8 +446,11 @@ static PyObject* gPyCreateConstraint(PyObject* self,
}
}
+ else {
+ return NULL;
+ }
- Py_INCREF(Py_None); return Py_None;
+ Py_RETURN_NONE;
}
@@ -421,6 +475,9 @@ static PyObject* gPyGetAppliedImpulse(PyObject* self,
appliedImpulse = PHY_GetActiveEnvironment()->getAppliedImpulse(constraintid);
}
}
+ else {
+ return NULL;
+ }
return PyFloat_FromDouble(appliedImpulse);
}
@@ -443,60 +500,64 @@ static PyObject* gPyRemoveConstraint(PyObject* self,
PHY_GetActiveEnvironment()->removeConstraint(constraintid);
}
}
- Py_INCREF(Py_None); return Py_None;
+ else {
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
}
static struct PyMethodDef physicsconstraints_methods[] = {
{"setGravity",(PyCFunction) gPySetGravity,
- METH_VARARGS, gPySetGravity__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetGravity__doc__},
{"setDebugMode",(PyCFunction) gPySetDebugMode,
- METH_VARARGS, gPySetDebugMode__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetDebugMode__doc__},
/// settings that influence quality of the rigidbody dynamics
{"setNumIterations",(PyCFunction) gPySetNumIterations,
- METH_VARARGS, gPySetNumIterations__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetNumIterations__doc__},
{"setNumTimeSubSteps",(PyCFunction) gPySetNumTimeSubSteps,
- METH_VARARGS, gPySetNumTimeSubSteps__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetNumTimeSubSteps__doc__},
{"setDeactivationTime",(PyCFunction) gPySetDeactivationTime,
- METH_VARARGS, gPySetDeactivationTime__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetDeactivationTime__doc__},
{"setDeactivationLinearTreshold",(PyCFunction) gPySetDeactivationLinearTreshold,
- METH_VARARGS, gPySetDeactivationLinearTreshold__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetDeactivationLinearTreshold__doc__},
{"setDeactivationAngularTreshold",(PyCFunction) gPySetDeactivationAngularTreshold,
- METH_VARARGS, gPySetDeactivationAngularTreshold__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetDeactivationAngularTreshold__doc__},
{"setContactBreakingTreshold",(PyCFunction) gPySetContactBreakingTreshold,
- METH_VARARGS, gPySetContactBreakingTreshold__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetContactBreakingTreshold__doc__},
{"setCcdMode",(PyCFunction) gPySetCcdMode,
- METH_VARARGS, gPySetCcdMode__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetCcdMode__doc__},
{"setSorConstant",(PyCFunction) gPySetSorConstant,
- METH_VARARGS, gPySetSorConstant__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetSorConstant__doc__},
{"setSolverTau",(PyCFunction) gPySetSolverTau,
- METH_VARARGS, gPySetSolverTau__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetSolverTau__doc__},
{"setSolverDamping",(PyCFunction) gPySetSolverDamping,
- METH_VARARGS, gPySetSolverDamping__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetSolverDamping__doc__},
{"setLinearAirDamping",(PyCFunction) gPySetLinearAirDamping,
- METH_VARARGS, gPySetLinearAirDamping__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetLinearAirDamping__doc__},
{"setUseEpa",(PyCFunction) gPySetUseEpa,
- METH_VARARGS, gPySetUseEpa__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetUseEpa__doc__},
{"setSolverType",(PyCFunction) gPySetSolverType,
- METH_VARARGS, gPySetSolverType__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPySetSolverType__doc__},
{"createConstraint",(PyCFunction) gPyCreateConstraint,
- METH_VARARGS, gPyCreateConstraint__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPyCreateConstraint__doc__},
{"getVehicleConstraint",(PyCFunction) gPyGetVehicleConstraint,
- METH_VARARGS, gPyGetVehicleConstraint__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPyGetVehicleConstraint__doc__},
{"removeConstraint",(PyCFunction) gPyRemoveConstraint,
- METH_VARARGS, gPyRemoveConstraint__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPyRemoveConstraint__doc__},
{"getAppliedImpulse",(PyCFunction) gPyGetAppliedImpulse,
- METH_VARARGS, gPyGetAppliedImpulse__doc__},
+ METH_VARARGS, (PY_METHODCHAR)gPyGetAppliedImpulse__doc__},
//sentinel
diff --git a/source/gameengine/Ketsji/KX_PyMath.h b/source/gameengine/Ketsji/KX_PyMath.h
index e1715c9275f..4e383e9b3d4 100644
--- a/source/gameengine/Ketsji/KX_PyMath.h
+++ b/source/gameengine/Ketsji/KX_PyMath.h
@@ -84,7 +84,10 @@ bool PyMatTo(PyObject* pymat, T& mat)
}
} else
noerror = false;
-
+
+ if (noerror==false)
+ PyErr_SetString(PyExc_TypeError, "could not be converted to a matrix (sequence of sequences)");
+
return noerror;
}
@@ -97,9 +100,13 @@ bool PyVecTo(PyObject* pyval, T& vec)
if (PySequence_Check(pyval))
{
unsigned int numitems = PySequence_Size(pyval);
- if (numitems != Size(vec))
+ if (numitems != Size(vec)) {
+ char err[128];
+ sprintf(err, "error setting vector, %d args, should be %d", numitems, Size(vec));
+ PyErr_SetString(PyExc_AttributeError, err);
return false;
-
+ }
+
for (unsigned int x = 0; x < numitems; x++)
{
PyObject *item = PySequence_GetItem(pyval, x); /* new ref */
@@ -107,7 +114,17 @@ bool PyVecTo(PyObject* pyval, T& vec)
Py_DECREF(item);
}
+ if (PyErr_Occurred()) {
+ PyErr_SetString(PyExc_AttributeError, "one or more of the items in the sequence was not a float");
+ return false;
+ }
+
return true;
+ } else
+ {
+ char err[128];
+ sprintf(err, "not a sequence type, expected a sequence of numbers size %d", Size(vec));
+ PyErr_SetString(PyExc_AttributeError, err);
}
return false;
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
index 681548fcc06..7ac817488fe 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -28,24 +28,14 @@
* Initialize Python thingies.
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "GL/glew.h"
-#ifdef WIN32
-#include <windows.h>
-#endif // WIN32
-#ifdef __APPLE__
-#define GL_GLEXT_LEGACY 1
-#include <OpenGL/gl.h>
-#include <OpenGL/glu.h>
-#else
-#include <GL/gl.h>
-#if defined(__sun__) && !defined(__sparc__)
-#include <mesa/glu.h>
+// directory header for py function getBlendFileList
+#include <stdlib.h>
+#ifndef WIN32
+ #include <dirent.h>
#else
-#include <GL/glu.h>
-#endif
+ #include "BLI_winstuff.h"
#endif
#ifdef WIN32
@@ -67,17 +57,28 @@
#include "BL_ActionActuator.h"
#include "RAS_IRasterizer.h"
#include "RAS_ICanvas.h"
+#include "RAS_BucketManager.h"
#include "MT_Vector3.h"
#include "MT_Point3.h"
#include "ListValue.h"
#include "KX_Scene.h"
#include "SND_DeviceManager.h"
-#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
#include "BL_Shader.h"
#include "KX_PyMath.h"
+#include "PyObjectPlus.h"
+
+//XXX
+#if 0
+extern "C" {
+ #include "Mathutils.h" // Blender.Mathutils module copied here so the blenderlayer can use.
+}
+#endif
+
+#include "marshal.h" /* python header for loading/saving dicts */
+
#include "PHY_IPhysicsEnvironment.h"
// FIXME: Enable for access to blender python modules. This is disabled because
// python has dependencies on a lot of other modules and is a pain to link.
@@ -86,13 +87,20 @@
//#include "BPY_extern.h"
#endif
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BLI_blenlib.h"
+#include "GPU_material.h"
+
static void setSandbox(TPythonSecurityLevel level);
// 'local' copy of canvas ptr, for window height/width python scripts
static RAS_ICanvas* gp_Canvas = NULL;
static KX_Scene* gp_KetsjiScene = NULL;
+static KX_KetsjiEngine* gp_KetsjiEngine = NULL;
static RAS_IRasterizer* gp_Rasterizer = NULL;
+static char gp_GamePythonPath[FILE_MAXDIR + FILE_MAXFILE] = "";
void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color)
{
@@ -115,36 +123,51 @@ void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,cons
static PyObject* ErrorObject;
STR_String gPyGetRandomFloat_doc="getRandomFloat returns a random floating point value in the range [0..1)";
-static PyObject* gPyGetRandomFloat(PyObject*,
- PyObject*,
- PyObject*)
+static PyObject* gPyGetRandomFloat(PyObject*)
{
return PyFloat_FromDouble(MT_random());
}
-static PyObject* gPySetGravity(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPySetGravity(PyObject*, PyObject* args)
{
MT_Vector3 vec = MT_Vector3(0., 0., 0.);
- if (PyVecArgTo(args, vec))
- {
- if (gp_KetsjiScene)
- gp_KetsjiScene->SetGravity(vec);
-
- Py_Return;
- }
+ if (!PyVecArgTo(args, vec))
+ return NULL;
+
+ if (gp_KetsjiScene)
+ gp_KetsjiScene->SetGravity(vec);
- return NULL;
+ Py_RETURN_NONE;
+}
+
+static char gPyExpandPath_doc[] =
+"(path) - Converts a blender internal path into a proper file system path.\n\
+path - the string path to convert.\n\n\
+Use / as directory separator in path\n\
+You can use '//' at the start of the string to define a relative path;\n\
+Blender replaces that string by the directory of the startup .blend or runtime\n\
+file to make a full path name (doesn't change during the game, even if you load\n\
+other .blend).\n\
+The function also converts the directory separator to the local file system format.";
+
+static PyObject* gPyExpandPath(PyObject*, PyObject* args)
+{
+ char expanded[FILE_MAXDIR + FILE_MAXFILE];
+ char* filename;
+
+ if (!PyArg_ParseTuple(args,"s",&filename))
+ return NULL;
+
+ BLI_strncpy(expanded, filename, FILE_MAXDIR + FILE_MAXFILE);
+ BLI_convertstringcode(expanded, gp_GamePythonPath);
+ return PyString_FromString(expanded);
}
static bool usedsp = false;
// this gets a pointer to an array filled with floats
-static PyObject* gPyGetSpectrum(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPyGetSpectrum(PyObject*)
{
SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
@@ -165,111 +188,145 @@ static PyObject* gPyGetSpectrum(PyObject*,
PyList_SetItem(resultlist, index, PyFloat_FromDouble(spectrum[index]));
}
}
+ else {
+ for (int index = 0; index < 512; index++)
+ {
+ PyList_SetItem(resultlist, index, PyFloat_FromDouble(0.0));
+ }
+ }
return resultlist;
}
-static PyObject* gPyStartDSP(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPyStartDSP(PyObject*, PyObject* args)
{
SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
- if (audiodevice)
- {
- if (!usedsp)
- {
- audiodevice->StartUsingDSP();
- usedsp = true;
- Py_Return;
- }
+ if (!audiodevice) {
+ PyErr_SetString(PyExc_RuntimeError, "no audio device available");
+ return NULL;
}
- return NULL;
+
+ if (!usedsp) {
+ audiodevice->StartUsingDSP();
+ usedsp = true;
+ }
+
+ Py_RETURN_NONE;
}
-static PyObject* gPyStopDSP(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPyStopDSP(PyObject*, PyObject* args)
{
SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
- if (audiodevice)
- {
- if (usedsp)
- {
- audiodevice->StopUsingDSP();
- usedsp = false;
- Py_Return;
- }
+ if (!audiodevice) {
+ PyErr_SetString(PyExc_RuntimeError, "no audio device available");
+ return NULL;
}
- return NULL;
+
+ if (usedsp) {
+ audiodevice->StopUsingDSP();
+ usedsp = true;
+ }
+
+ Py_RETURN_NONE;
}
-static PyObject* gPySetLogicTicRate(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPySetLogicTicRate(PyObject*, PyObject* args)
{
float ticrate;
- if (PyArg_ParseTuple(args, "f", &ticrate))
- {
- KX_KetsjiEngine::SetTicRate(ticrate);
- Py_Return;
- }
+ if (!PyArg_ParseTuple(args, "f", &ticrate))
+ return NULL;
- return NULL;
+ KX_KetsjiEngine::SetTicRate(ticrate);
+ Py_RETURN_NONE;
}
-static PyObject* gPyGetLogicTicRate(PyObject*, PyObject*, PyObject*)
+static PyObject* gPyGetLogicTicRate(PyObject*)
{
return PyFloat_FromDouble(KX_KetsjiEngine::GetTicRate());
}
-static PyObject* gPySetPhysicsTicRate(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPySetPhysicsTicRate(PyObject*, PyObject* args)
{
float ticrate;
- if (PyArg_ParseTuple(args, "f", &ticrate))
- {
-
- PHY_GetActiveEnvironment()->setFixedTimeStep(true,ticrate);
- Py_Return;
- }
+ if (!PyArg_ParseTuple(args, "f", &ticrate))
+ return NULL;
- return NULL;
+ PHY_GetActiveEnvironment()->setFixedTimeStep(true,ticrate);
+ Py_RETURN_NONE;
}
-static PyObject* gPySetPhysicsDebug(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPySetPhysicsDebug(PyObject*, PyObject* args)
{
int debugMode;
- if (PyArg_ParseTuple(args, "i", &debugMode))
- {
- PHY_GetActiveEnvironment()->setDebugMode(debugMode);
- Py_Return;
- }
+ if (!PyArg_ParseTuple(args, "i", &debugMode))
+ return NULL;
- return NULL;
+ PHY_GetActiveEnvironment()->setDebugMode(debugMode);
+ Py_RETURN_NONE;
}
-static PyObject* gPyGetPhysicsTicRate(PyObject*, PyObject*, PyObject*)
+static PyObject* gPyGetPhysicsTicRate(PyObject*)
{
return PyFloat_FromDouble(PHY_GetActiveEnvironment()->getFixedTimeStep());
}
+static PyObject* gPyGetAverageFrameRate(PyObject*)
+{
+ return PyFloat_FromDouble(KX_KetsjiEngine::GetAverageFrameRate());
+}
+
+static PyObject* gPyGetBlendFileList(PyObject*, PyObject* args)
+{
+ char cpath[sizeof(gp_GamePythonPath)];
+ char *searchpath = NULL;
+ PyObject* list, *value;
+
+ DIR *dp;
+ struct dirent *dirp;
+
+ if (!PyArg_ParseTuple(args, "|s", &searchpath))
+ return NULL;
+
+ list = PyList_New(0);
+
+ if (searchpath) {
+ BLI_strncpy(cpath, searchpath, FILE_MAXDIR + FILE_MAXFILE);
+ BLI_convertstringcode(cpath, gp_GamePythonPath);
+ } else {
+ /* Get the dir only */
+ BLI_split_dirfile_basic(gp_GamePythonPath, cpath, NULL);
+ }
+
+ if((dp = opendir(cpath)) == NULL) {
+ /* todo, show the errno, this shouldnt happen anyway if the blendfile is readable */
+ fprintf(stderr, "Could not read directoty (%s) failed, code %d (%s)\n", cpath, errno, strerror(errno));
+ return list;
+ }
+
+ while ((dirp = readdir(dp)) != NULL) {
+ if (BLI_testextensie(dirp->d_name, ".blend")) {
+ value = PyString_FromString(dirp->d_name);
+ PyList_Append(list, value);
+ Py_DECREF(value);
+ }
+ }
+
+ closedir(dp);
+ return list;
+}
+
static STR_String gPyGetCurrentScene_doc =
"getCurrentScene()\n"
"Gets a reference to the current scene.\n";
-static PyObject* gPyGetCurrentScene(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+static PyObject* gPyGetCurrentScene(PyObject* self)
{
Py_INCREF(gp_KetsjiScene);
return (PyObject*) gp_KetsjiScene;
@@ -278,17 +335,13 @@ static PyObject* gPyGetCurrentScene(PyObject* self,
static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *)
{
#define pprint(x) std::cout << x << std::endl;
- bgl::BL_EXTInfo ext = bgl::RAS_EXT_support;
bool count=0;
bool support=0;
pprint("Supported Extensions...");
-#ifdef GL_ARB_shader_objects
- pprint(" GL_ARB_shader_objects supported? "<< (ext._ARB_shader_objects?"yes.":"no."));
+ pprint(" GL_ARB_shader_objects supported? "<< (GLEW_ARB_shader_objects?"yes.":"no."));
count = 1;
-#endif
-#ifdef GL_ARB_vertex_shader
- support= ext._ARB_vertex_shader;
+ support= GLEW_ARB_vertex_shader;
pprint(" GL_ARB_vertex_shader supported? "<< (support?"yes.":"no."));
count = 1;
if(support){
@@ -307,9 +360,8 @@ static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *)
pprint(" Max combined texture units." << max);
pprint("");
}
-#endif
-#ifdef GL_ARB_fragment_shader
- support=ext._ARB_fragment_shader;
+
+ support=GLEW_ARB_fragment_shader;
pprint(" GL_ARB_fragment_shader supported? "<< (support?"yes.":"no."));
count = 1;
if(support){
@@ -319,9 +371,8 @@ static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *)
pprint(" Max uniform components." << max);
pprint("");
}
-#endif
-#ifdef GL_ARB_texture_cube_map
- support = ext._ARB_texture_cube_map;
+
+ support = GLEW_ARB_texture_cube_map;
pprint(" GL_ARB_texture_cube_map supported? "<< (support?"yes.":"no."));
count = 1;
if(support){
@@ -331,9 +382,8 @@ static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *)
pprint(" Max cubemap size." << size);
pprint("");
}
-#endif
-#ifdef GL_ARB_multitexture
- support = ext._ARB_multitexture;
+
+ support = GLEW_ARB_multitexture;
count = 1;
pprint(" GL_ARB_multitexture supported? "<< (support?"yes.":"no."));
if(support){
@@ -343,63 +393,52 @@ static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *)
pprint(" Max texture units available. " << units);
pprint("");
}
-#endif
-#ifdef GL_ARB_texture_env_combine
- pprint(" GL_ARB_texture_env_combine supported? "<< (ext._ARB_texture_env_combine?"yes.":"no."));
+
+ pprint(" GL_ARB_texture_env_combine supported? "<< (GLEW_ARB_texture_env_combine?"yes.":"no."));
count = 1;
-#endif
+
if(!count)
pprint("No extenstions are used in this build");
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
static struct PyMethodDef game_methods[] = {
+ {"expandPath", (PyCFunction)gPyExpandPath, METH_VARARGS, (PY_METHODCHAR)gPyExpandPath_doc},
{"getCurrentController",
(PyCFunction) SCA_PythonController::sPyGetCurrentController,
- METH_VARARGS, SCA_PythonController::sPyGetCurrentController__doc__},
+ METH_NOARGS, (PY_METHODCHAR)SCA_PythonController::sPyGetCurrentController__doc__},
{"getCurrentScene", (PyCFunction) gPyGetCurrentScene,
- METH_VARARGS, gPyGetCurrentScene_doc.Ptr()},
+ METH_NOARGS, (PY_METHODCHAR)gPyGetCurrentScene_doc.Ptr()},
{"addActiveActuator",(PyCFunction) SCA_PythonController::sPyAddActiveActuator,
- METH_VARARGS, SCA_PythonController::sPyAddActiveActuator__doc__},
+ METH_VARARGS, (PY_METHODCHAR)SCA_PythonController::sPyAddActiveActuator__doc__},
{"getRandomFloat",(PyCFunction) gPyGetRandomFloat,
- METH_VARARGS,gPyGetRandomFloat_doc.Ptr()},
- {"setGravity",(PyCFunction) gPySetGravity, METH_VARARGS,"set Gravitation"},
- {"getSpectrum",(PyCFunction) gPyGetSpectrum, METH_VARARGS,"get audio spectrum"},
- {"stopDSP",(PyCFunction) gPyStopDSP, METH_VARARGS,"stop using the audio dsp (for performance reasons)"},
- {"getLogicTicRate", (PyCFunction) gPyGetLogicTicRate, METH_VARARGS, "Gets the logic tic rate"},
- {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, "Sets the logic tic rate"},
- {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_VARARGS, "Gets the physics tic rate"},
- {"setPhysicsTicRate", (PyCFunction) gPySetPhysicsTicRate, METH_VARARGS, "Sets the physics tic rate"},
- {"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, "Prints GL Extension Info"},
+ METH_NOARGS, (PY_METHODCHAR)gPyGetRandomFloat_doc.Ptr()},
+ {"setGravity",(PyCFunction) gPySetGravity, METH_VARARGS, (PY_METHODCHAR)"set Gravitation"},
+ {"getSpectrum",(PyCFunction) gPyGetSpectrum, METH_NOARGS, (PY_METHODCHAR)"get audio spectrum"},
+ {"stopDSP",(PyCFunction) gPyStopDSP, METH_VARARGS, (PY_METHODCHAR)"stop using the audio dsp (for performance reasons)"},
+ {"getLogicTicRate", (PyCFunction) gPyGetLogicTicRate, METH_NOARGS, (PY_METHODCHAR)"Gets the logic tic rate"},
+ {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, (PY_METHODCHAR)"Sets the logic tic rate"},
+ {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_NOARGS, (PY_METHODCHAR)"Gets the physics tic rate"},
+ {"setPhysicsTicRate", (PyCFunction) gPySetPhysicsTicRate, METH_VARARGS, (PY_METHODCHAR)"Sets the physics tic rate"},
+ {"getAverageFrameRate", (PyCFunction) gPyGetAverageFrameRate, METH_NOARGS, (PY_METHODCHAR)"Gets the estimated average frame rate"},
+ {"getBlendFileList", (PyCFunction)gPyGetBlendFileList, METH_VARARGS, (PY_METHODCHAR)"Gets a list of blend files in the same directory as the current blend file"},
+ {"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, (PY_METHODCHAR)"Prints GL Extension Info"},
{NULL, (PyCFunction) NULL, 0, NULL }
};
-static PyObject* gPyGetWindowHeight(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPyGetWindowHeight(PyObject*, PyObject* args)
{
- int height = (gp_Canvas ? gp_Canvas->GetHeight() : 0);
-
- PyObject* heightval = PyInt_FromLong(height);
- return heightval;
+ return PyInt_FromLong((gp_Canvas ? gp_Canvas->GetHeight() : 0));
}
-static PyObject* gPyGetWindowWidth(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPyGetWindowWidth(PyObject*, PyObject* args)
{
-
-
- int width = (gp_Canvas ? gp_Canvas->GetWidth() : 0);
-
- PyObject* widthval = PyInt_FromLong(width);
- return widthval;
+ return PyInt_FromLong((gp_Canvas ? gp_Canvas->GetWidth() : 0));
}
@@ -407,264 +446,403 @@ static PyObject* gPyGetWindowWidth(PyObject*,
// temporarility visibility thing, will be moved to rasterizer/renderer later
bool gUseVisibilityTemp = false;
-static PyObject* gPyEnableVisibility(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPyEnableVisibility(PyObject*, PyObject* args)
{
int visible;
- if (PyArg_ParseTuple(args,"i",&visible))
- {
- gUseVisibilityTemp = (visible != 0);
- }
- else
- {
- Py_Return;
- }
- Py_Return;
+ if (!PyArg_ParseTuple(args,"i",&visible))
+ return NULL;
+
+ gUseVisibilityTemp = (visible != 0);
+ Py_RETURN_NONE;
}
-static PyObject* gPyShowMouse(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPyShowMouse(PyObject*, PyObject* args)
{
int visible;
- if (PyArg_ParseTuple(args,"i",&visible))
+ if (!PyArg_ParseTuple(args,"i",&visible))
+ return NULL;
+
+ if (visible)
{
- if (visible)
- {
- if (gp_Canvas)
- gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
- } else
- {
- if (gp_Canvas)
- gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
- }
+ if (gp_Canvas)
+ gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
+ } else
+ {
+ if (gp_Canvas)
+ gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
}
- Py_Return;
+ Py_RETURN_NONE;
}
-static PyObject* gPySetMousePosition(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPySetMousePosition(PyObject*, PyObject* args)
{
int x,y;
- if (PyArg_ParseTuple(args,"ii",&x,&y))
- {
- if (gp_Canvas)
- gp_Canvas->SetMousePosition(x,y);
- }
+ if (!PyArg_ParseTuple(args,"ii",&x,&y))
+ return NULL;
- Py_Return;
+ if (gp_Canvas)
+ gp_Canvas->SetMousePosition(x,y);
+
+ Py_RETURN_NONE;
}
-static PyObject* gPySetEyeSeparation(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPySetEyeSeparation(PyObject*, PyObject* args)
{
float sep;
- if (PyArg_ParseTuple(args, "f", &sep))
- {
- if (gp_Rasterizer)
- gp_Rasterizer->SetEyeSeparation(sep);
-
- Py_Return;
+ if (!PyArg_ParseTuple(args, "f", &sep))
+ return NULL;
+
+ if (!gp_Rasterizer) {
+ PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available");
+ return NULL;
}
- return NULL;
+ gp_Rasterizer->SetEyeSeparation(sep);
+
+ Py_RETURN_NONE;
}
static PyObject* gPyGetEyeSeparation(PyObject*, PyObject*, PyObject*)
{
- if (gp_Rasterizer)
- return PyFloat_FromDouble(gp_Rasterizer->GetEyeSeparation());
+ if (!gp_Rasterizer) {
+ PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available");
+ return NULL;
+ }
- return NULL;
+ return PyFloat_FromDouble(gp_Rasterizer->GetEyeSeparation());
}
-static PyObject* gPySetFocalLength(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPySetFocalLength(PyObject*, PyObject* args)
{
float focus;
- if (PyArg_ParseTuple(args, "f", &focus))
- {
- if (gp_Rasterizer)
- gp_Rasterizer->SetFocalLength(focus);
- Py_Return;
+ if (!PyArg_ParseTuple(args, "f", &focus))
+ return NULL;
+
+ if (!gp_Rasterizer) {
+ PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available");
+ return NULL;
}
+
+ gp_Rasterizer->SetFocalLength(focus);
- return NULL;
+ Py_RETURN_NONE;
}
static PyObject* gPyGetFocalLength(PyObject*, PyObject*, PyObject*)
{
- if (gp_Rasterizer)
- return PyFloat_FromDouble(gp_Rasterizer->GetFocalLength());
- return NULL;
+ if (!gp_Rasterizer) {
+ PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available");
+ return NULL;
+ }
+
+ return PyFloat_FromDouble(gp_Rasterizer->GetFocalLength());
+
+ Py_RETURN_NONE;
}
-static PyObject* gPySetBackgroundColor(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPySetBackgroundColor(PyObject*, PyObject* args)
{
MT_Vector4 vec = MT_Vector4(0., 0., 0.3, 0.);
- if (PyVecArgTo(args, vec))
+ if (!PyVecArgTo(args, vec))
+ return NULL;
+
+ if (gp_Canvas)
{
- if (gp_Canvas)
- {
- gp_Rasterizer->SetBackColor(vec[0], vec[1], vec[2], vec[3]);
- }
- Py_Return;
+ gp_Rasterizer->SetBackColor(vec[0], vec[1], vec[2], vec[3]);
}
-
- return NULL;
+ Py_RETURN_NONE;
}
-static PyObject* gPySetMistColor(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPySetMistColor(PyObject*, PyObject* args)
{
MT_Vector3 vec = MT_Vector3(0., 0., 0.);
- if (PyVecArgTo(args, vec))
- {
- if (gp_Rasterizer)
- {
- gp_Rasterizer->SetFogColor(vec[0], vec[1], vec[2]);
- }
- Py_Return;
- }
+ if (!PyVecArgTo(args, vec))
+ return NULL;
- return NULL;
+ if (!gp_Rasterizer) {
+ PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available");
+ return NULL;
+ }
+ gp_Rasterizer->SetFogColor(vec[0], vec[1], vec[2]);
+
+ Py_RETURN_NONE;
}
-static PyObject* gPySetMistStart(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPySetMistStart(PyObject*, PyObject* args)
{
float miststart;
- if (PyArg_ParseTuple(args,"f",&miststart))
- {
- if (gp_Rasterizer)
- {
- gp_Rasterizer->SetFogStart(miststart);
- }
+ if (!PyArg_ParseTuple(args,"f",&miststart))
+ return NULL;
+
+ if (!gp_Rasterizer) {
+ PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available");
+ return NULL;
}
- Py_Return;
+
+ gp_Rasterizer->SetFogStart(miststart);
+
+ Py_RETURN_NONE;
}
-static PyObject* gPySetMistEnd(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPySetMistEnd(PyObject*, PyObject* args)
{
float mistend;
- if (PyArg_ParseTuple(args,"f",&mistend))
- {
- if (gp_Rasterizer)
- {
- gp_Rasterizer->SetFogEnd(mistend);
- }
+ if (!PyArg_ParseTuple(args,"f",&mistend))
+ return NULL;
+
+ if (!gp_Rasterizer) {
+ PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available");
+ return NULL;
}
- Py_Return;
+
+ gp_Rasterizer->SetFogEnd(mistend);
+
+ Py_RETURN_NONE;
}
-static PyObject* gPySetAmbientColor(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPySetAmbientColor(PyObject*, PyObject* args)
{
MT_Vector3 vec = MT_Vector3(0., 0., 0.);
- if (PyVecArgTo(args, vec))
- {
- if (gp_Rasterizer)
- {
- gp_Rasterizer->SetAmbientColor(vec[0], vec[1], vec[2]);
- }
- Py_Return;
- }
+ if (!PyVecArgTo(args, vec))
+ return NULL;
- return NULL;
+ if (!gp_Rasterizer) {
+ PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available");
+ return NULL;
+ }
+ gp_Rasterizer->SetAmbientColor(vec[0], vec[1], vec[2]);
+
+ Py_RETURN_NONE;
}
-static PyObject* gPyMakeScreenshot(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPyMakeScreenshot(PyObject*, PyObject* args)
{
char* filename;
- if (PyArg_ParseTuple(args,"s",&filename))
+ if (!PyArg_ParseTuple(args,"s",&filename))
+ return NULL;
+
+ if (gp_Canvas)
{
- if (gp_Canvas)
- {
- gp_Canvas->MakeScreenShot(filename);
- }
+ gp_Canvas->MakeScreenShot(filename);
}
- Py_Return;
+
+ Py_RETURN_NONE;
}
-static PyObject* gPyEnableMotionBlur(PyObject*,
- PyObject* args,
- PyObject*)
+static PyObject* gPyEnableMotionBlur(PyObject*, PyObject* args)
{
float motionblurvalue;
- if (PyArg_ParseTuple(args,"f",&motionblurvalue))
- {
- if(gp_Rasterizer)
- {
- gp_Rasterizer->EnableMotionBlur(motionblurvalue);
+ if (!PyArg_ParseTuple(args,"f",&motionblurvalue))
+ return NULL;
+
+ if (!gp_Rasterizer) {
+ PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available");
+ return NULL;
+ }
+
+ gp_Rasterizer->EnableMotionBlur(motionblurvalue);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject* gPyDisableMotionBlur(PyObject*, PyObject* args)
+{
+ if (!gp_Rasterizer) {
+ PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available");
+ return NULL;
+ }
+
+ gp_Rasterizer->DisableMotionBlur();
+
+ Py_RETURN_NONE;
+}
+
+int getGLSLSettingFlag(char *setting)
+{
+ if(strcmp(setting, "lights") == 0)
+ return G_FILE_GLSL_NO_LIGHTS;
+ else if(strcmp(setting, "shaders") == 0)
+ return G_FILE_GLSL_NO_SHADERS;
+ else if(strcmp(setting, "shadows") == 0)
+ return G_FILE_GLSL_NO_SHADOWS;
+ else if(strcmp(setting, "ramps") == 0)
+ return G_FILE_GLSL_NO_RAMPS;
+ else if(strcmp(setting, "nodes") == 0)
+ return G_FILE_GLSL_NO_NODES;
+ else if(strcmp(setting, "extra_textures") == 0)
+ return G_FILE_GLSL_NO_EXTRA_TEX;
+ else
+ return -1;
+}
+
+static PyObject* gPySetGLSLMaterialSetting(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ char *setting;
+ int enable, flag, fileflags;
+
+ if (!PyArg_ParseTuple(args,"si",&setting,&enable))
+ return NULL;
+
+ flag = getGLSLSettingFlag(setting);
+
+ if (flag==-1) {
+ PyErr_SetString(PyExc_ValueError, "glsl setting is not known");
+ return NULL;
+ }
+
+ fileflags = G.fileflags;
+
+ if (enable)
+ G.fileflags &= ~flag;
+ else
+ G.fileflags |= flag;
+
+ /* display lists and GLSL materials need to be remade */
+ if(G.fileflags != fileflags) {
+ if(gp_KetsjiEngine) {
+ KX_SceneList *scenes = gp_KetsjiEngine->CurrentScenes();
+ KX_SceneList::iterator it;
+
+ for(it=scenes->begin(); it!=scenes->end(); it++)
+ if((*it)->GetBucketManager())
+ (*it)->GetBucketManager()->ReleaseDisplayLists();
}
+
+ GPU_materials_free();
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject* gPyGetGLSLMaterialSetting(PyObject*,
+ PyObject* args,
+ PyObject*)
+{
+ char *setting;
+ int enabled = 0, flag;
+
+ if (!PyArg_ParseTuple(args,"s",&setting))
+ return NULL;
+
+ flag = getGLSLSettingFlag(setting);
+
+ if (flag==-1) {
+ PyErr_SetString(PyExc_ValueError, "glsl setting is not known");
+ return NULL;
}
- Py_Return;
+
+ enabled = ((G.fileflags & flag) != 0);
+ return PyInt_FromLong(enabled);
}
-static PyObject* gPyDisableMotionBlur(PyObject*,
+#define KX_TEXFACE_MATERIAL 0
+#define KX_BLENDER_MULTITEX_MATERIAL 1
+#define KX_BLENDER_GLSL_MATERIAL 2
+
+static PyObject* gPySetMaterialType(PyObject*,
PyObject* args,
PyObject*)
{
- if(gp_Rasterizer)
- {
- gp_Rasterizer->DisableMotionBlur();
+ int flag, type;
+
+ if (!PyArg_ParseTuple(args,"i",&type))
+ return NULL;
+
+ if(type == KX_BLENDER_GLSL_MATERIAL)
+ flag = G_FILE_GAME_MAT|G_FILE_GAME_MAT_GLSL;
+ else if(type == KX_BLENDER_MULTITEX_MATERIAL)
+ flag = G_FILE_GAME_MAT;
+ else if(type == KX_TEXFACE_MATERIAL)
+ flag = 0;
+ else {
+ PyErr_SetString(PyExc_ValueError, "material type is not known");
+ return NULL;
}
- Py_Return;
+
+ G.fileflags &= ~(G_FILE_GAME_MAT|G_FILE_GAME_MAT_GLSL);
+ G.fileflags |= flag;
+
+ Py_RETURN_NONE;
}
-STR_String gPyGetWindowHeight__doc__="getWindowHeight doc";
-STR_String gPyGetWindowWidth__doc__="getWindowWidth doc";
-STR_String gPyEnableVisibility__doc__="enableVisibility doc";
-STR_String gPyMakeScreenshot__doc__="make Screenshot doc";
-STR_String gPyShowMouse__doc__="showMouse(bool visible)";
-STR_String gPySetMousePosition__doc__="setMousePosition(int x,int y)";
+static PyObject* gPyGetMaterialType(PyObject*)
+{
+ int flag;
+
+ if(G.fileflags & (G_FILE_GAME_MAT|G_FILE_GAME_MAT_GLSL))
+ flag = KX_BLENDER_GLSL_MATERIAL;
+ else if(G.fileflags & G_FILE_GAME_MAT)
+ flag = KX_BLENDER_MULTITEX_MATERIAL;
+ else
+ flag = KX_TEXFACE_MATERIAL;
+
+ return PyInt_FromLong(flag);
+}
+
+static PyObject* gPyDrawLine(PyObject*, PyObject* args)
+{
+ PyObject* ob_from;
+ PyObject* ob_to;
+ PyObject* ob_color;
+
+ if (!gp_Rasterizer) {
+ PyErr_SetString(PyExc_RuntimeError, "Rasterizer not available");
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args,"OOO",&ob_from,&ob_to,&ob_color))
+ return NULL;
+
+ MT_Vector3 from(0., 0., 0.);
+ MT_Vector3 to(0., 0., 0.);
+ MT_Vector3 color(0., 0., 0.);
+ if (!PyVecTo(ob_from, from))
+ return NULL;
+ if (!PyVecTo(ob_to, to))
+ return NULL;
+ if (!PyVecTo(ob_color, color))
+ return NULL;
+
+ gp_Rasterizer->DrawDebugLine(from,to,color);
+
+ Py_RETURN_NONE;
+}
static struct PyMethodDef rasterizer_methods[] = {
{"getWindowWidth",(PyCFunction) gPyGetWindowWidth,
- METH_VARARGS, gPyGetWindowWidth__doc__.Ptr()},
+ METH_VARARGS, "getWindowWidth doc"},
{"getWindowHeight",(PyCFunction) gPyGetWindowHeight,
- METH_VARARGS, gPyGetWindowHeight__doc__.Ptr()},
+ METH_VARARGS, "getWindowHeight doc"},
{"makeScreenshot",(PyCFunction)gPyMakeScreenshot,
- METH_VARARGS, gPyMakeScreenshot__doc__.Ptr()},
+ METH_VARARGS, "make Screenshot doc"},
{"enableVisibility",(PyCFunction) gPyEnableVisibility,
- METH_VARARGS, gPyEnableVisibility__doc__.Ptr()},
+ METH_VARARGS, "enableVisibility doc"},
{"showMouse",(PyCFunction) gPyShowMouse,
- METH_VARARGS, gPyShowMouse__doc__.Ptr()},
+ METH_VARARGS, "showMouse(bool visible)"},
{"setMousePosition",(PyCFunction) gPySetMousePosition,
- METH_VARARGS, gPySetMousePosition__doc__.Ptr()},
+ METH_VARARGS, "setMousePosition(int x,int y)"},
{"setBackgroundColor",(PyCFunction)gPySetBackgroundColor,METH_VARARGS,"set Background Color (rgb)"},
{"setAmbientColor",(PyCFunction)gPySetAmbientColor,METH_VARARGS,"set Ambient Color (rgb)"},
{"setMistColor",(PyCFunction)gPySetMistColor,METH_VARARGS,"set Mist Color (rgb)"},
@@ -678,11 +856,19 @@ static struct PyMethodDef rasterizer_methods[] = {
{"getEyeSeparation", (PyCFunction) gPyGetEyeSeparation, METH_VARARGS, "get the eye separation for stereo mode"},
{"setFocalLength", (PyCFunction) gPySetFocalLength, METH_VARARGS, "set the focal length for stereo mode"},
{"getFocalLength", (PyCFunction) gPyGetFocalLength, METH_VARARGS, "get the focal length for stereo mode"},
+ {"setMaterialMode",(PyCFunction) gPySetMaterialType,
+ METH_VARARGS, "set the material mode to use for OpenGL rendering"},
+ {"getMaterialMode",(PyCFunction) gPyGetMaterialType,
+ METH_NOARGS, "get the material mode being used for OpenGL rendering"},
+ {"setGLSLMaterialSetting",(PyCFunction) gPySetGLSLMaterialSetting,
+ METH_VARARGS, "set the state of a GLSL material setting"},
+ {"getGLSLMaterialSetting",(PyCFunction) gPyGetGLSLMaterialSetting,
+ METH_VARARGS, "get the state of a GLSL material setting"},
+ {"drawLine", (PyCFunction) gPyDrawLine,
+ METH_VARARGS, "draw a line on the screen"},
{ NULL, (PyCFunction) NULL, 0, NULL }
};
-
-
// Initialization function for the module (*must* be called initGameLogic)
static char GameLogic_module_documentation[] =
@@ -695,11 +881,12 @@ static char Rasterizer_module_documentation[] =
-PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook
+PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack to get gravity hook
{
PyObject* m;
PyObject* d;
+ gp_KetsjiEngine = engine;
gp_KetsjiScene = scene;
gUseVisibilityTemp=false;
@@ -711,10 +898,14 @@ PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook
// Add some symbolic constants to the module
d = PyModule_GetDict(m);
+
+ // can be overwritten later for gameEngine instances that can load new blend files and re-initialize this module
+ // for now its safe to make sure it exists for other areas such as the web plugin
+ PyDict_SetItemString(d, "globalDict", PyDict_New());
ErrorObject = PyString_FromString("GameLogic.error");
PyDict_SetItemString(d, "error", ErrorObject);
-
+
// XXXX Add constants here
/* To use logic bricks, we need some sort of constants. Here, we associate */
/* constants and sumbolic names. Add them to dictionary d. */
@@ -737,6 +928,15 @@ PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook
KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ROTX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTX);
KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ROTY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTY);
KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ROTZ, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTZ);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_DIRPX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPX);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_DIRPY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPY);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_DIRPY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPY);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_DIRNX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNX);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_DIRNY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNY);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_DIRNY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNY);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ORIX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIX);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ORIY, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIY);
+ KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_ORIZ, KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIZ);
/* 4. Ipo actuator, simple part */
KX_MACRO_addTypesToDict(d, KX_IPOACT_PLAY, KX_IpoActuator::KX_ACT_IPO_PLAY);
@@ -803,37 +1003,75 @@ PyObject* initGameLogic(KX_Scene* scene) // quick hack to get gravity hook
KX_MACRO_addTypesToDict(d, CAM_POS, BL_Shader::CAM_POS);
KX_MACRO_addTypesToDict(d, CONSTANT_TIMER, BL_Shader::CONSTANT_TIMER);
+ /* 10 state actuator */
+ KX_MACRO_addTypesToDict(d, KX_STATE1, (1<<0));
+ KX_MACRO_addTypesToDict(d, KX_STATE2, (1<<1));
+ KX_MACRO_addTypesToDict(d, KX_STATE3, (1<<2));
+ KX_MACRO_addTypesToDict(d, KX_STATE4, (1<<3));
+ KX_MACRO_addTypesToDict(d, KX_STATE5, (1<<4));
+ KX_MACRO_addTypesToDict(d, KX_STATE6, (1<<5));
+ KX_MACRO_addTypesToDict(d, KX_STATE7, (1<<6));
+ KX_MACRO_addTypesToDict(d, KX_STATE8, (1<<7));
+ KX_MACRO_addTypesToDict(d, KX_STATE9, (1<<8));
+ KX_MACRO_addTypesToDict(d, KX_STATE10, (1<<9));
+ KX_MACRO_addTypesToDict(d, KX_STATE11, (1<<10));
+ KX_MACRO_addTypesToDict(d, KX_STATE12, (1<<11));
+ KX_MACRO_addTypesToDict(d, KX_STATE13, (1<<12));
+ KX_MACRO_addTypesToDict(d, KX_STATE14, (1<<13));
+ KX_MACRO_addTypesToDict(d, KX_STATE15, (1<<14));
+ KX_MACRO_addTypesToDict(d, KX_STATE16, (1<<15));
+ KX_MACRO_addTypesToDict(d, KX_STATE17, (1<<16));
+ KX_MACRO_addTypesToDict(d, KX_STATE18, (1<<17));
+ KX_MACRO_addTypesToDict(d, KX_STATE19, (1<<18));
+ KX_MACRO_addTypesToDict(d, KX_STATE20, (1<<19));
+ KX_MACRO_addTypesToDict(d, KX_STATE21, (1<<20));
+ KX_MACRO_addTypesToDict(d, KX_STATE22, (1<<21));
+ KX_MACRO_addTypesToDict(d, KX_STATE23, (1<<22));
+ KX_MACRO_addTypesToDict(d, KX_STATE24, (1<<23));
+ KX_MACRO_addTypesToDict(d, KX_STATE25, (1<<24));
+ KX_MACRO_addTypesToDict(d, KX_STATE26, (1<<25));
+ KX_MACRO_addTypesToDict(d, KX_STATE27, (1<<26));
+ KX_MACRO_addTypesToDict(d, KX_STATE28, (1<<27));
+ KX_MACRO_addTypesToDict(d, KX_STATE29, (1<<28));
+ KX_MACRO_addTypesToDict(d, KX_STATE30, (1<<29));
+
// Check for errors
if (PyErr_Occurred())
{
Py_FatalError("can't initialize module GameLogic");
}
- return d;
-}
-
-void dictionaryClearByHand(PyObject *dict)
-{
- // Clears the dictionary by hand:
- // This prevents, extra references to global variables
- // inside the GameLogic dictionary when the python interpreter is finalized.
- // which allows the scene to safely delete them :)
- // see: (space.c)->start_game
- if(dict) PyDict_Clear(dict);
+ return m;
}
-
// Python Sandbox code
// override builtin functions import() and open()
-PyObject *KXpy_open(PyObject *self, PyObject *args)
-{
+PyObject *KXpy_open(PyObject *self, PyObject *args) {
PyErr_SetString(PyExc_RuntimeError, "Sandbox: open() function disabled!\nGame Scripts should not use this function.");
return NULL;
}
+PyObject *KXpy_reload(PyObject *self, PyObject *args) {
+ PyErr_SetString(PyExc_RuntimeError, "Sandbox: reload() function disabled!\nGame Scripts should not use this function.");
+ return NULL;
+}
+
+PyObject *KXpy_file(PyObject *self, PyObject *args) {
+ PyErr_SetString(PyExc_RuntimeError, "Sandbox: file() function disabled!\nGame Scripts should not use this function.");
+ return NULL;
+}
+PyObject *KXpy_execfile(PyObject *self, PyObject *args) {
+ PyErr_SetString(PyExc_RuntimeError, "Sandbox: execfile() function disabled!\nGame Scripts should not use this function.");
+ return NULL;
+}
+
+PyObject *KXpy_compile(PyObject *self, PyObject *args) {
+ PyErr_SetString(PyExc_RuntimeError, "Sandbox: compile() function disabled!\nGame Scripts should not use this function.");
+ return NULL;
+}
PyObject *KXpy_import(PyObject *self, PyObject *args)
{
@@ -843,9 +1081,17 @@ PyObject *KXpy_import(PyObject *self, PyObject *args)
PyObject *fromlist = NULL;
PyObject *l, *m, *n;
+#if (PY_VERSION_HEX >= 0x02060000)
+ int dummy_val; /* what does this do?*/
+
+ if (!PyArg_ParseTuple(args, "s|OOOi:m_import",
+ &name, &globals, &locals, &fromlist, &dummy_val))
+ return NULL;
+#else
if (!PyArg_ParseTuple(args, "s|OOO:m_import",
&name, &globals, &locals, &fromlist))
return NULL;
+#endif
/* check for builtin modules */
m = PyImport_AddModule("sys");
@@ -859,7 +1105,7 @@ PyObject *KXpy_import(PyObject *self, PyObject *args)
/* quick hack for GamePython modules
TODO: register builtin modules properly by ExtendInittab */
if (!strcmp(name, "GameLogic") || !strcmp(name, "GameKeys") || !strcmp(name, "PhysicsConstraints") ||
- !strcmp(name, "Rasterizer")) {
+ !strcmp(name, "Rasterizer") || !strcmp(name, "Mathutils")) {
return PyImport_ImportModuleEx(name, globals, locals, fromlist);
}
@@ -869,40 +1115,67 @@ PyObject *KXpy_import(PyObject *self, PyObject *args)
}
+/* override python file type functions */
+#if 0
+static int
+file_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ KXpy_file(NULL, NULL);
+ return -1;
+}
+static PyObject *
+file_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ return KXpy_file(NULL, NULL);
+}
+#endif
-static PyMethodDef meth_open[] = {
- { "open", KXpy_open, METH_VARARGS,
- "(disabled)"}
-};
-
-
-static PyMethodDef meth_import[] = {
- { "import", KXpy_import, METH_VARARGS,
- "our own import"}
-};
-
+static PyMethodDef meth_open[] = {{ "open", KXpy_open, METH_VARARGS, "(disabled)"}};
+static PyMethodDef meth_reload[] = {{ "reload", KXpy_reload, METH_VARARGS, "(disabled)"}};
+static PyMethodDef meth_file[] = {{ "file", KXpy_file, METH_VARARGS, "(disabled)"}};
+static PyMethodDef meth_execfile[] = {{ "execfile", KXpy_execfile, METH_VARARGS, "(disabled)"}};
+static PyMethodDef meth_compile[] = {{ "compile", KXpy_compile, METH_VARARGS, "(disabled)"}};
+static PyMethodDef meth_import[] = {{ "import", KXpy_import, METH_VARARGS, "our own import"}};
//static PyObject *g_oldopen = 0;
//static PyObject *g_oldimport = 0;
//static int g_security = 0;
-
void setSandbox(TPythonSecurityLevel level)
{
PyObject *m = PyImport_AddModule("__builtin__");
PyObject *d = PyModule_GetDict(m);
- PyObject *meth = PyCFunction_New(meth_open, NULL);
switch (level) {
case psl_Highest:
//if (!g_security) {
//g_oldopen = PyDict_GetItemString(d, "open");
- PyDict_SetItemString(d, "open", meth);
- meth = PyCFunction_New(meth_import, NULL);
- PyDict_SetItemString(d, "__import__", meth);
+
+ // functions we cant trust
+ PyDict_SetItemString(d, "open", PyCFunction_New(meth_open, NULL));
+ PyDict_SetItemString(d, "reload", PyCFunction_New(meth_reload, NULL));
+ PyDict_SetItemString(d, "file", PyCFunction_New(meth_file, NULL));
+ PyDict_SetItemString(d, "execfile", PyCFunction_New(meth_execfile, NULL));
+ PyDict_SetItemString(d, "compile", PyCFunction_New(meth_compile, NULL));
+
+ // our own import
+ PyDict_SetItemString(d, "__import__", PyCFunction_New(meth_import, NULL));
//g_security = level;
+
+ // Overiding file dosnt stop it being accessed if your sneaky
+ // f = [ t for t in (1).__class__.__mro__[-1].__subclasses__() if t.__name__ == 'file'][0]('/some_file.txt', 'w')
+ // f.write('...')
+ // so overwrite the file types functions. be very careful here still, since python uses python.
+ // ps - python devs frown deeply upon this.
+
+ /* this could mess up pythons internals, if we are serious about sandboxing
+ * issues like the one above need to be solved, possibly modify __subclasses__ is safer? */
+#if 0
+ PyFile_Type.tp_init = file_init;
+ PyFile_Type.tp_new = file_new;
+#endif
//}
break;
/*
@@ -985,6 +1258,11 @@ PyObject* initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas)
ErrorObject = PyString_FromString("Rasterizer.error");
PyDict_SetItemString(d, "error", ErrorObject);
+ /* needed for get/setMaterialType */
+ KX_MACRO_addTypesToDict(d, KX_TEXFACE_MATERIAL, KX_TEXFACE_MATERIAL);
+ KX_MACRO_addTypesToDict(d, KX_BLENDER_MULTITEX_MATERIAL, KX_BLENDER_MULTITEX_MATERIAL);
+ KX_MACRO_addTypesToDict(d, KX_BLENDER_GLSL_MATERIAL, KX_BLENDER_GLSL_MATERIAL);
+
// XXXX Add constants here
// Check for errors
@@ -1006,9 +1284,38 @@ static char GameKeys_module_documentation[] =
"This modules provides defines for key-codes"
;
+static char gPyEventToString_doc[] =
+"Take a valid event from the GameKeys module or Keyboard Sensor and return a name"
+;
+static PyObject* gPyEventToString(PyObject*, PyObject* value)
+{
+ PyObject* mod, *dict, *key, *val, *ret = NULL;
+ Py_ssize_t pos = 0;
+
+ mod = PyImport_ImportModule( "GameKeys" );
+ if (!mod)
+ return NULL;
+
+ dict = PyModule_GetDict(mod);
+
+ while (PyDict_Next(dict, &pos, &key, &val)) {
+ if (PyObject_Compare(value, val)==0) {
+ ret = key;
+ break;
+ }
+ }
+
+ PyErr_Clear(); // incase there was an error clearing
+ Py_DECREF(mod);
+ if (!ret) PyErr_SetString(PyExc_ValueError, "expected a valid int keyboard event");
+ else Py_INCREF(ret);
+
+ return ret;
+}
static struct PyMethodDef gamekeys_methods[] = {
+ {"EventToString", (PyCFunction)gPyEventToString, METH_O, (PY_METHODCHAR)gPyEventToString_doc},
{ NULL, (PyCFunction) NULL, 0, NULL }
};
@@ -1152,7 +1459,111 @@ PyObject* initGameKeys()
return d;
}
-void PHY_SetActiveScene(class KX_Scene* scene)
+PyObject* initMathutils()
+{
+ return NULL; //XXX Mathutils_Init("Mathutils"); // Use as a top level module in BGE
+}
+
+void KX_SetActiveScene(class KX_Scene* scene)
{
gp_KetsjiScene = scene;
}
+
+class KX_Scene* KX_GetActiveScene()
+{
+ return gp_KetsjiScene;
+}
+
+class KX_KetsjiEngine* KX_GetActiveEngine()
+{
+ return gp_KetsjiEngine;
+}
+
+// utility function for loading and saving the globalDict
+int saveGamePythonConfig( char **marshal_buffer)
+{
+ int marshal_length = 0;
+ PyObject* gameLogic = PyImport_ImportModule("GameLogic");
+ if (gameLogic) {
+ PyObject* pyGlobalDict = PyDict_GetItemString(PyModule_GetDict(gameLogic), "globalDict"); // Same as importing the module
+ if (pyGlobalDict) {
+#ifdef Py_MARSHAL_VERSION
+ PyObject* pyGlobalDictMarshal = PyMarshal_WriteObjectToString( pyGlobalDict, 2); // Py_MARSHAL_VERSION == 2 as of Py2.5
+#else
+ PyObject* pyGlobalDictMarshal = PyMarshal_WriteObjectToString( pyGlobalDict );
+#endif
+ if (pyGlobalDictMarshal) {
+ // for testing only
+ // PyObject_Print(pyGlobalDictMarshal, stderr, 0);
+
+ marshal_length= PyString_Size(pyGlobalDictMarshal);
+ *marshal_buffer = new char[marshal_length + 1];
+ memcpy(*marshal_buffer, PyString_AsString(pyGlobalDictMarshal), marshal_length);
+
+ Py_DECREF(pyGlobalDictMarshal);
+ } else {
+ printf("Error, GameLogic.globalDict could not be marshal'd\n");
+ }
+ } else {
+ printf("Error, GameLogic.globalDict was removed\n");
+ }
+ Py_DECREF(gameLogic);
+ } else {
+ PyErr_Clear();
+ printf("Error, GameLogic failed to import GameLogic.globalDict will be lost\n");
+ }
+ return marshal_length;
+}
+
+int loadGamePythonConfig(char *marshal_buffer, int marshal_length)
+{
+ /* Restore the dict */
+ if (marshal_buffer) {
+ PyObject* gameLogic = PyImport_ImportModule("GameLogic");
+
+ if (gameLogic) {
+ PyObject* pyGlobalDict = PyMarshal_ReadObjectFromString(marshal_buffer, marshal_length);
+ if (pyGlobalDict) {
+ PyObject* pyGlobalDict_orig = PyDict_GetItemString(PyModule_GetDict(gameLogic), "globalDict"); // Same as importing the module.
+ if (pyGlobalDict_orig) {
+ PyDict_Clear(pyGlobalDict_orig);
+ PyDict_Update(pyGlobalDict_orig, pyGlobalDict);
+ } else {
+ /* this should not happen, but cant find the original globalDict, just assign it then */
+ PyDict_SetItemString(PyModule_GetDict(gameLogic), "globalDict", pyGlobalDict); // Same as importing the module.
+ }
+ Py_DECREF(gameLogic);
+ Py_DECREF(pyGlobalDict);
+ return 1;
+ } else {
+ Py_DECREF(gameLogic);
+ PyErr_Clear();
+ printf("Error could not marshall string\n");
+ }
+ } else {
+ PyErr_Clear();
+ printf("Error, GameLogic failed to import GameLogic.globalDict will be lost\n");
+ }
+ }
+ return 0;
+}
+
+void pathGamePythonConfig( char *path )
+{
+ int len = strlen(gp_GamePythonPath);
+
+ BLI_strncpy(path, gp_GamePythonPath, sizeof(gp_GamePythonPath));
+
+ /* replace extension */
+ if (BLI_testextensie(path, ".blend")) {
+ strcpy(path+(len-6), ".bgeconf");
+ } else {
+ strcpy(path+len, ".bgeconf");
+ }
+}
+
+void setGamePythonPath(char *path)
+{
+ BLI_strncpy(gp_GamePythonPath, path, sizeof(gp_GamePythonPath));
+}
+
diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h
index b2b66e70f5b..57ee0be9400 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.h
+++ b/source/gameengine/Ketsji/KX_PythonInit.h
@@ -40,16 +40,27 @@ typedef enum {
extern bool gUseVisibilityTemp;
-PyObject* initGameLogic(class KX_Scene* ketsjiscene);
+PyObject* initGameLogic(class KX_KetsjiEngine *engine, class KX_Scene* ketsjiscene);
PyObject* initGameKeys();
PyObject* initRasterizer(class RAS_IRasterizer* rasty,class RAS_ICanvas* canvas);
PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level);
+PyObject* initMathutils();
+PyObject* initVideoTexture(void);
void exitGamePlayerPythonScripting();
PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level);
void exitGamePythonScripting();
-void dictionaryClearByHand(PyObject *dict);
-void PHY_SetActiveScene(class KX_Scene* scene);
+void setGamePythonPath(char *path);
+void pathGamePythonConfig( char *path );
+int saveGamePythonConfig( char **marshal_buffer);
+int loadGamePythonConfig(char *marshal_buffer, int marshal_length);
+
+class KX_KetsjiEngine;
+class KX_Scene;
+
+void KX_SetActiveScene(class KX_Scene* scene);
+class KX_Scene* KX_GetActiveScene();
+class KX_KetsjiEngine* KX_GetActiveEngine();
#include "MT_Vector3.h"
void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color);
diff --git a/source/gameengine/Ketsji/KX_RadarSensor.cpp b/source/gameengine/Ketsji/KX_RadarSensor.cpp
index 66ff1e1e7ca..244e9b75d8e 100644
--- a/source/gameengine/Ketsji/KX_RadarSensor.cpp
+++ b/source/gameengine/Ketsji/KX_RadarSensor.cpp
@@ -71,7 +71,6 @@ KX_RadarSensor::KX_RadarSensor(SCA_EventManager* eventmgr,
//sumoObj->setClientObject(&m_client_info);
}
-
KX_RadarSensor::~KX_RadarSensor()
{
@@ -81,10 +80,7 @@ CValue* KX_RadarSensor::GetReplica()
{
KX_RadarSensor* replica = new KX_RadarSensor(*this);
replica->m_colliders = new CListValue();
- replica->m_bCollision = false;
- replica->m_bTriggered= false;
- replica->m_hitObject = NULL;
- replica->m_bLastTriggered = false;
+ replica->Init();
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
@@ -93,6 +89,10 @@ CValue* KX_RadarSensor::GetReplica()
if (replica->m_physCtrl)
{
replica->m_physCtrl = replica->m_physCtrl->GetReplica();
+ if (replica->m_physCtrl)
+ {
+ replica->m_physCtrl->setNewClientInfo(replica->m_client_info);
+ }
}
//todo: make sure replication works fine!
@@ -124,27 +124,48 @@ void KX_RadarSensor::SynchronizeTransform()
// depends on the radar 'axis'
switch (m_axis)
{
- case 0: // X Axis
+ case 0: // +X Axis
{
MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(90));
trans.rotate(rotquatje);
trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0));
break;
};
- case 1: // Y Axis
+ case 1: // +Y Axis
{
MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-180));
trans.rotate(rotquatje);
trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0));
break;
};
- case 2: // Z Axis
+ case 2: // +Z Axis
{
MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-90));
trans.rotate(rotquatje);
trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0));
break;
};
+ case 3: // -X Axis
+ {
+ MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(-90));
+ trans.rotate(rotquatje);
+ trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0));
+ break;
+ };
+ case 4: // -Y Axis
+ {
+ //MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-180));
+ //trans.rotate(rotquatje);
+ trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0));
+ break;
+ };
+ case 5: // -Z Axis
+ {
+ MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(90));
+ trans.rotate(rotquatje);
+ trans.translate(MT_Vector3 (0, -m_coneheight/2.0 ,0));
+ break;
+ };
default:
{
}
@@ -155,8 +176,10 @@ void KX_RadarSensor::SynchronizeTransform()
if (m_physCtrl)
{
- m_physCtrl->setPosition(trans.getOrigin().x(),trans.getOrigin().y(),trans.getOrigin().z());
- m_physCtrl->setOrientation(trans.getRotation().x(),trans.getRotation().y(),trans.getRotation().z(),trans.getRotation().w());
+ MT_Quaternion orn = trans.getRotation();
+ MT_Point3 pos = trans.getOrigin();
+ m_physCtrl->setPosition(pos[0],pos[1],pos[2]);
+ m_physCtrl->setOrientation(orn[0],orn[1],orn[2],orn[3]);
m_physCtrl->calcXform();
}
@@ -198,11 +221,11 @@ PyParentObject KX_RadarSensor::Parents[] = {
PyMethodDef KX_RadarSensor::Methods[] = {
{"getConeOrigin", (PyCFunction) KX_RadarSensor::sPyGetConeOrigin,
- METH_VARARGS, GetConeOrigin_doc},
+ METH_VARARGS, (PY_METHODCHAR)GetConeOrigin_doc},
{"getConeTarget", (PyCFunction) KX_RadarSensor::sPyGetConeTarget,
- METH_VARARGS, GetConeTarget_doc},
+ METH_VARARGS, (PY_METHODCHAR)GetConeTarget_doc},
{"getConeHeight", (PyCFunction) KX_RadarSensor::sPyGetConeHeight,
- METH_VARARGS, GetConeHeight_doc},
+ METH_VARARGS, (PY_METHODCHAR)GetConeHeight_doc},
{NULL,NULL,NULL,NULL} //Sentinel
};
@@ -211,7 +234,7 @@ PyObject* KX_RadarSensor::_getattr(const STR_String& attr) {
}
/* getConeOrigin */
-char KX_RadarSensor::GetConeOrigin_doc[] =
+const char KX_RadarSensor::GetConeOrigin_doc[] =
"getConeOrigin()\n"
"\tReturns the origin of the cone with which to test. The origin\n"
"\tis in the middle of the cone.";
@@ -228,7 +251,7 @@ PyObject* KX_RadarSensor::PyGetConeOrigin(PyObject* self,
}
/* getConeOrigin */
-char KX_RadarSensor::GetConeTarget_doc[] =
+const char KX_RadarSensor::GetConeTarget_doc[] =
"getConeTarget()\n"
"\tReturns the center of the bottom face of the cone with which to test.\n";
PyObject* KX_RadarSensor::PyGetConeTarget(PyObject* self,
@@ -244,7 +267,7 @@ PyObject* KX_RadarSensor::PyGetConeTarget(PyObject* self,
}
/* getConeOrigin */
-char KX_RadarSensor::GetConeHeight_doc[] =
+const char KX_RadarSensor::GetConeHeight_doc[] =
"getConeHeight()\n"
"\tReturns the height of the cone with which to test.\n";
PyObject* KX_RadarSensor::PyGetConeHeight(PyObject* self,
diff --git a/source/gameengine/Ketsji/KX_RayCast.cpp b/source/gameengine/Ketsji/KX_RayCast.cpp
index 288a936e1b1..974d4b992a6 100644
--- a/source/gameengine/Ketsji/KX_RayCast.cpp
+++ b/source/gameengine/Ketsji/KX_RayCast.cpp
@@ -29,6 +29,7 @@
*/
#include <stdlib.h>
+#include <stdio.h>
#include "KX_RayCast.h"
@@ -39,7 +40,21 @@
#include "PHY_IPhysicsEnvironment.h"
#include "PHY_IPhysicsController.h"
-bool KX_RayCast::RayTest(KX_IPhysicsController* ignore_controller, PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, MT_Point3& result_point, MT_Vector3& result_normal, const KX_RayCast& callback)
+KX_RayCast::KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal)
+ :PHY_IRayCastFilterCallback(dynamic_cast<PHY_IPhysicsController*>(ignoreController), faceNormal)
+{
+}
+
+void KX_RayCast::reportHit(PHY_RayCastResult* result)
+{
+ m_hitFound = true;
+ m_hitPoint.setValue((const float*)result->m_hitPoint);
+ m_hitNormal.setValue((const float*)result->m_hitNormal);
+ m_hitMesh = result->m_meshObject;
+ m_hitPolygon = result->m_polygon;
+}
+
+bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, KX_RayCast& callback)
{
// Loops over all physics objects between frompoint and topoint,
// calling callback.RayHit for each one.
@@ -48,51 +63,52 @@ bool KX_RayCast::RayTest(KX_IPhysicsController* ignore_controller, PHY_IPhysicsE
//
// returns true if an object was found, false if not.
MT_Point3 frompoint(_frompoint);
- const MT_Vector3 todir( (topoint - frompoint).normalized() );
+ const MT_Vector3 todir( (topoint - frompoint).safe_normalized() );
+ MT_Point3 prevpoint(_frompoint+todir*(-1.f));
PHY_IPhysicsController* hit_controller;
- PHY__Vector3 phy_pos;
- PHY__Vector3 phy_normal;
- while((hit_controller = physics_environment->rayTest(dynamic_cast<PHY_IPhysicsController*>(ignore_controller),
+ while((hit_controller = physics_environment->rayTest(callback,
frompoint.x(),frompoint.y(),frompoint.z(),
- topoint.x(),topoint.y(),topoint.z(),
- phy_pos[0],phy_pos[1],phy_pos[2],
- phy_normal[0],phy_normal[1],phy_normal[2])))
+ topoint.x(),topoint.y(),topoint.z())) != NULL)
{
- result_point = MT_Point3(phy_pos);
- result_normal = MT_Vector3(phy_normal);
KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(hit_controller->getNewClientInfo());
if (!info)
{
printf("no info!\n");
MT_assert(info && "Physics controller with no client object info");
- return false;
+ break;
}
- if (callback.RayHit(info, result_point, result_normal))
- return true;
-
-
- // skip past the object and keep tracing
- /* We add 0.01 of fudge, so that if the margin && radius == 0., we don't endless loop. */
- MT_Scalar marg = 0.01 + hit_controller->GetMargin();
- marg += 2.f * hit_controller->GetMargin();
+ // The biggest danger to to endless loop, prevent this by checking that the
+ // hit point always progresses along the ray direction..
+ prevpoint -= callback.m_hitPoint;
+ if (prevpoint.length2() < MT_EPSILON)
+ break;
+
+ if (callback.RayHit(info))
+ // caller may decide to stop the loop and still cancel the hit
+ return callback.m_hitFound;
+
+ // Skip past the object and keep tracing.
+ // Note that retrieving in a single shot multiple hit points would be possible
+ // but it would require some change in Bullet.
+ prevpoint = callback.m_hitPoint;
+ /* We add 0.001 of fudge, so that if the margin && radius == 0., we don't endless loop. */
+ MT_Scalar marg = 0.001 + hit_controller->GetMargin();
+ marg *= 2.f;
/* Calculate the other side of this object */
- PHY__Vector3 hitpos;
- hit_controller->getPosition(hitpos);
- MT_Point3 hitObjPos(hitpos);
-
- MT_Vector3 hitvector = hitObjPos - result_point;
- if (hitvector.dot(hitvector) > MT_EPSILON)
- {
- hitvector.normalize();
- marg *= 2.*todir.dot(hitvector);
- }
- frompoint = result_point + marg * todir;
+ MT_Scalar h = MT_abs(todir.dot(callback.m_hitNormal));
+ if (h <= 0.01)
+ // the normal is almost orthogonal to the ray direction, cannot compute the other side
+ break;
+ marg /= h;
+ frompoint = callback.m_hitPoint + marg * todir;
+ // verify that we are not passed the to point
+ if ((topoint - frompoint).dot(todir) < 0.f)
+ break;
}
-
- return hit_controller;
+ return false;
}
diff --git a/source/gameengine/Ketsji/KX_RayCast.h b/source/gameengine/Ketsji/KX_RayCast.h
index 607dabd8afc..c3084c997a1 100644
--- a/source/gameengine/Ketsji/KX_RayCast.h
+++ b/source/gameengine/Ketsji/KX_RayCast.h
@@ -30,12 +30,14 @@
#ifndef __KX_RAYCAST_H__
#define __KX_RAYCAST_H__
-class MT_Point3;
-class MT_Vector3;
-class KX_IPhysicsController;
-class PHY_IPhysicsEnvironment;
+#include "PHY_IPhysicsEnvironment.h"
+#include "PHY_IPhysicsController.h"
+#include "MT_Point3.h"
+#include "MT_Vector3.h"
+class RAS_MeshObject;
struct KX_ClientObjectInfo;
+class KX_IPhysicsController;
/**
* Defines a function for doing a ray cast.
@@ -49,17 +51,27 @@ struct KX_ClientObjectInfo;
*
* Returns true if a client was accepted, false if nothing found.
*/
-class KX_RayCast
+class KX_RayCast : public PHY_IRayCastFilterCallback
{
-protected:
- KX_RayCast() {};
public:
+ bool m_hitFound;
+ MT_Point3 m_hitPoint;
+ MT_Vector3 m_hitNormal;
+ const RAS_MeshObject* m_hitMesh;
+ int m_hitPolygon;
+
+ KX_RayCast(KX_IPhysicsController* ignoreController, bool faceNormal);
virtual ~KX_RayCast() {}
+ /**
+ * The physic environment returns the ray casting result through this function
+ */
+ virtual void reportHit(PHY_RayCastResult* result);
+
/** ray test callback.
* either override this in your class, or use a callback wrapper.
*/
- virtual bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal) const = 0;
+ virtual bool RayHit(KX_ClientObjectInfo* client) = 0;
/**
* Callback wrapper.
@@ -71,13 +83,11 @@ public:
/// Public interface.
/// Implement bool RayHit in your class to receive ray callbacks.
- static bool RayTest(KX_IPhysicsController* physics_controller,
+ static bool RayTest(
PHY_IPhysicsEnvironment* physics_environment,
- const MT_Point3& _frompoint,
+ const MT_Point3& frompoint,
const MT_Point3& topoint,
- MT_Point3& result_point,
- MT_Vector3& result_normal,
- const KX_RayCast& callback);
+ KX_RayCast& callback);
};
@@ -86,18 +96,32 @@ template<class T> class KX_RayCast::Callback : public KX_RayCast
T *self;
void *data;
public:
- Callback(T *_self, void *_data = NULL)
- : self(_self),
+ Callback(T *_self, KX_IPhysicsController* controller=NULL, void *_data = NULL, bool faceNormal=false)
+ : KX_RayCast(controller, faceNormal),
+ self(_self),
data(_data)
{
}
~Callback() {}
-
- virtual bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal) const
+
+ virtual bool RayHit(KX_ClientObjectInfo* client)
{
- return self->RayHit(client, hit_point, hit_normal, data);
+ return self->RayHit(client, this, data);
}
+
+ virtual bool needBroadphaseRayCast(PHY_IPhysicsController* controller)
+ {
+ KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(controller->getNewClientInfo());
+
+ if (!info)
+ {
+ MT_assert(info && "Physics controller with no client object info");
+ return false;
+ }
+ return self->NeedRayCast(info);
+ }
+
};
diff --git a/source/gameengine/Ketsji/KX_RayEventManager.cpp b/source/gameengine/Ketsji/KX_RayEventManager.cpp
index 4101c6b547e..1af29151adf 100644
--- a/source/gameengine/Ketsji/KX_RayEventManager.cpp
+++ b/source/gameengine/Ketsji/KX_RayEventManager.cpp
@@ -44,14 +44,9 @@ using namespace std;
void KX_RayEventManager::NextFrame()
{
- for (vector<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++)
+ for (set<class SCA_ISensor*>::const_iterator i= m_sensors.begin();!(i==m_sensors.end());i++)
{
- SCA_ISensor *sensor = *i;
- sensor->Activate(m_logicmgr, NULL);
+ (*i)->Activate(m_logicmgr, NULL);
}
}
-void KX_RayEventManager::RegisterSensor(SCA_ISensor* sensor)
-{
- m_sensors.push_back(sensor);
-};
diff --git a/source/gameengine/Ketsji/KX_RayEventManager.h b/source/gameengine/Ketsji/KX_RayEventManager.h
index 3630f9682b9..b816d4d5250 100644
--- a/source/gameengine/Ketsji/KX_RayEventManager.h
+++ b/source/gameengine/Ketsji/KX_RayEventManager.h
@@ -45,7 +45,6 @@ public:
m_logicmgr(logicmgr)
{}
virtual void NextFrame();
- virtual void RegisterSensor(SCA_ISensor* sensor);
};
#endif //__KX_RAYEVENTMGR
diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp
index 4ccb02d34ec..e24fb773eac 100644
--- a/source/gameengine/Ketsji/KX_RaySensor.cpp
+++ b/source/gameengine/Ketsji/KX_RaySensor.cpp
@@ -51,6 +51,7 @@ KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr,
SCA_IObject* gameobj,
const STR_String& propname,
bool bFindMaterial,
+ bool bXRay,
double distance,
int axis,
KX_Scene* ketsjiScene,
@@ -58,19 +59,23 @@ KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr,
: SCA_ISensor(gameobj,eventmgr, T),
m_propertyname(propname),
m_bFindMaterial(bFindMaterial),
+ m_bXRay(bXRay),
m_distance(distance),
m_scene(ketsjiScene),
- m_bTriggered(false),
- m_axis(axis),
- m_rayHit(false),
- m_hitObject(NULL)
+ m_axis(axis)
{
-
+ Init();
}
-
+void KX_RaySensor::Init()
+{
+ m_bTriggered = (m_invert)?true:false;
+ m_rayHit = false;
+ m_hitObject = NULL;
+ m_reset = true;
+}
KX_RaySensor::~KX_RaySensor()
{
@@ -81,9 +86,10 @@ KX_RaySensor::~KX_RaySensor()
CValue* KX_RaySensor::GetReplica()
{
- CValue* replica = new KX_RaySensor(*this);
+ KX_RaySensor* replica = new KX_RaySensor(*this);
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
+ replica->Init();
return replica;
}
@@ -100,16 +106,10 @@ bool KX_RaySensor::IsPositiveTrigger()
return result;
}
-bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data)
+bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data)
{
KX_GameObject* hitKXObj = client->m_gameobject;
-
- if (client->m_type > KX_ClientObjectInfo::ACTOR)
- {
- // false hit
- return false;
- }
bool bFound = false;
if (m_propertyname.Length() == 0)
@@ -135,20 +135,48 @@ bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_
{
m_rayHit = true;
m_hitObject = hitKXObj;
- m_hitPosition = hit_point;
- m_hitNormal = hit_normal;
+ m_hitPosition = result->m_hitPoint;
+ m_hitNormal = result->m_hitNormal;
}
-
+ // no multi-hit search yet
return true;
-
}
-
+/* this function is used to pre-filter the object before casting the ray on them.
+ This is useful for "X-Ray" option when we want to see "through" unwanted object.
+ */
+bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo* client)
+{
+ if (client->m_type > KX_ClientObjectInfo::ACTOR)
+ {
+ // Unknown type of object, skip it.
+ // Should not occur as the sensor objects are filtered in RayTest()
+ printf("Invalid client type %d found ray casting\n", client->m_type);
+ return false;
+ }
+ if (m_bXRay && m_propertyname.Length() != 0)
+ {
+ if (m_bFindMaterial)
+ {
+ // not quite correct: an object may have multiple material
+ // should check all the material and not only the first one
+ if (!client->m_auxilary_info || (m_propertyname != ((char*)client->m_auxilary_info)))
+ return false;
+ }
+ else
+ {
+ if (client->m_gameobject->GetProperty(m_propertyname) == NULL)
+ return false;
+ }
+ }
+ return true;
+}
bool KX_RaySensor::Evaluate(CValue* event)
{
bool result = false;
+ bool reset = m_reset && m_level;
m_rayHit = false;
m_hitObject = NULL;
m_hitPosition = MT_Vector3(0,0,0);
@@ -160,6 +188,7 @@ bool KX_RaySensor::Evaluate(CValue* event)
MT_Matrix3x3 invmat = matje.inverse();
MT_Vector3 todir;
+ m_reset = false;
switch (m_axis)
{
case 1: // X
@@ -209,8 +238,6 @@ bool KX_RaySensor::Evaluate(CValue* event)
m_rayDirection = todir;
MT_Point3 topoint = frompoint + (m_distance) * todir;
- MT_Point3 resultpoint;
- MT_Vector3 resultnormal;
PHY_IPhysicsEnvironment* pe = m_scene->GetPhysicsEnvironment();
if (!pe)
@@ -232,7 +259,8 @@ bool KX_RaySensor::Evaluate(CValue* event)
PHY_IPhysicsEnvironment* physics_environment = this->m_scene->GetPhysicsEnvironment();
- result = KX_RayCast::RayTest(spc, physics_environment, frompoint, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_RaySensor>(this));
+ KX_RayCast::Callback<KX_RaySensor> callback(this, spc);
+ KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback);
/* now pass this result to some controller */
@@ -259,9 +287,15 @@ bool KX_RaySensor::Evaluate(CValue* event)
// notify logicsystem that ray JUST left the Object
result = true;
}
+ else
+ {
+ result = false;
+ }
}
-
+ if (reset)
+ // force an event
+ result = true;
return result;
}
@@ -301,14 +335,14 @@ PyParentObject KX_RaySensor::Parents[] = {
};
PyMethodDef KX_RaySensor::Methods[] = {
- {"getHitObject",(PyCFunction) KX_RaySensor::sPyGetHitObject,METH_VARARGS, GetHitObject_doc},
- {"getHitPosition",(PyCFunction) KX_RaySensor::sPyGetHitPosition,METH_VARARGS, GetHitPosition_doc},
- {"getHitNormal",(PyCFunction) KX_RaySensor::sPyGetHitNormal,METH_VARARGS, GetHitNormal_doc},
- {"getRayDirection",(PyCFunction) KX_RaySensor::sPyGetRayDirection,METH_VARARGS, GetRayDirection_doc},
+ {"getHitObject",(PyCFunction) KX_RaySensor::sPyGetHitObject,METH_VARARGS, (PY_METHODCHAR)GetHitObject_doc},
+ {"getHitPosition",(PyCFunction) KX_RaySensor::sPyGetHitPosition,METH_VARARGS, (PY_METHODCHAR)GetHitPosition_doc},
+ {"getHitNormal",(PyCFunction) KX_RaySensor::sPyGetHitNormal,METH_VARARGS, (PY_METHODCHAR)GetHitNormal_doc},
+ {"getRayDirection",(PyCFunction) KX_RaySensor::sPyGetRayDirection,METH_VARARGS, (PY_METHODCHAR)GetRayDirection_doc},
{NULL,NULL} //Sentinel
};
-char KX_RaySensor::GetHitObject_doc[] =
+const char KX_RaySensor::GetHitObject_doc[] =
"getHitObject()\n"
"\tReturns the name of the object that was hit by this ray.\n";
PyObject* KX_RaySensor::PyGetHitObject(PyObject* self,
@@ -323,7 +357,7 @@ PyObject* KX_RaySensor::PyGetHitObject(PyObject* self,
}
-char KX_RaySensor::GetHitPosition_doc[] =
+const char KX_RaySensor::GetHitPosition_doc[] =
"getHitPosition()\n"
"\tReturns the position (in worldcoordinates) where the object was hit by this ray.\n";
PyObject* KX_RaySensor::PyGetHitPosition(PyObject* self,
@@ -343,7 +377,7 @@ PyObject* KX_RaySensor::PyGetHitPosition(PyObject* self,
}
-char KX_RaySensor::GetRayDirection_doc[] =
+const char KX_RaySensor::GetRayDirection_doc[] =
"getRayDirection()\n"
"\tReturns the direction from the ray (in worldcoordinates) .\n";
PyObject* KX_RaySensor::PyGetRayDirection(PyObject* self,
@@ -363,7 +397,7 @@ PyObject* KX_RaySensor::PyGetRayDirection(PyObject* self,
}
-char KX_RaySensor::GetHitNormal_doc[] =
+const char KX_RaySensor::GetHitNormal_doc[] =
"getHitNormal()\n"
"\tReturns the normal (in worldcoordinates) of the object at the location where the object was hit by this ray.\n";
PyObject* KX_RaySensor::PyGetHitNormal(PyObject* self,
diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h
index 8a317ffaa07..02a755fedc1 100644
--- a/source/gameengine/Ketsji/KX_RaySensor.h
+++ b/source/gameengine/Ketsji/KX_RaySensor.h
@@ -36,12 +36,14 @@
#include "MT_Point3.h"
struct KX_ClientObjectInfo;
+class KX_RayCast;
class KX_RaySensor : public SCA_ISensor
{
Py_Header;
STR_String m_propertyname;
bool m_bFindMaterial;
+ bool m_bXRay;
double m_distance;
class KX_Scene* m_scene;
bool m_bTriggered;
@@ -56,7 +58,8 @@ public:
KX_RaySensor(class SCA_EventManager* eventmgr,
SCA_IObject* gameobj,
const STR_String& propname,
- bool fFindMaterial,
+ bool bFindMaterial,
+ bool bXRay,
double distance,
int axis,
class KX_Scene* ketsjiScene,
@@ -66,8 +69,10 @@ public:
virtual bool Evaluate(CValue* event);
virtual bool IsPositiveTrigger();
+ virtual void Init();
- bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data);
+ bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
+ bool NeedRayCast(KX_ClientObjectInfo* client);
KX_PYMETHOD_DOC(KX_RaySensor,GetHitObject);
KX_PYMETHOD_DOC(KX_RaySensor,GetHitPosition);
diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp
index b31fe16d05d..5777f54b799 100644
--- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp
@@ -39,6 +39,8 @@
#include "KX_GameObject.h"
#include "KX_IPhysicsController.h"
+#include "PyObjectPlus.h"
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -48,19 +50,28 @@
/* ------------------------------------------------------------------------- */
KX_SCA_AddObjectActuator::KX_SCA_AddObjectActuator(SCA_IObject *gameobj,
- CValue* original,
+ SCA_IObject *original,
int time,
SCA_IScene* scene,
const MT_Vector3& linvel,
- bool local,
+ bool linv_local,
+ const MT_Vector3& angvel,
+ bool angv_local,
PyTypeObject* T)
:
SCA_IActuator(gameobj, T),
m_OriginalObject(original),
m_scene(scene),
+
m_linear_velocity(linvel),
- m_localFlag(local)
+ m_localLinvFlag(linv_local),
+
+ m_angular_velocity(angvel),
+ m_localAngvFlag(angv_local)
{
+ if (m_OriginalObject)
+ m_OriginalObject->RegisterActuator(this);
+
m_lastCreatedObject = NULL;
m_timeProp = time;
}
@@ -69,6 +80,8 @@ KX_SCA_AddObjectActuator::KX_SCA_AddObjectActuator(SCA_IObject *gameobj,
KX_SCA_AddObjectActuator::~KX_SCA_AddObjectActuator()
{
+ if (m_OriginalObject)
+ m_OriginalObject->UnregisterActuator(this);
if (m_lastCreatedObject)
m_lastCreatedObject->Release();
}
@@ -108,12 +121,40 @@ CValue* KX_SCA_AddObjectActuator::GetReplica()
// this will copy properties and so on...
replica->ProcessReplica();
- replica->m_lastCreatedObject=NULL;
CValue::AddDataToReplica(replica);
return replica;
}
+void KX_SCA_AddObjectActuator::ProcessReplica()
+{
+ if (m_OriginalObject)
+ m_OriginalObject->RegisterActuator(this);
+ m_lastCreatedObject=NULL;
+ SCA_IActuator::ProcessReplica();
+}
+
+bool KX_SCA_AddObjectActuator::UnlinkObject(SCA_IObject* clientobj)
+{
+ if (clientobj == m_OriginalObject)
+ {
+ // this object is being deleted, we cannot continue to track it.
+ m_OriginalObject = NULL;
+ return true;
+ }
+ return false;
+}
+
+void KX_SCA_AddObjectActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
+{
+ void **h_obj = (*obj_map)[m_OriginalObject];
+ if (h_obj) {
+ if (m_OriginalObject)
+ m_OriginalObject->UnregisterActuator(this);
+ m_OriginalObject = (SCA_IObject*)(*h_obj);
+ m_OriginalObject->RegisterActuator(this);
+ }
+}
/* ------------------------------------------------------------------------- */
@@ -147,14 +188,16 @@ PyParentObject KX_SCA_AddObjectActuator::Parents[] = {
NULL
};
PyMethodDef KX_SCA_AddObjectActuator::Methods[] = {
- {"setObject", (PyCFunction) KX_SCA_AddObjectActuator::sPySetObject, METH_VARARGS, SetObject_doc},
- {"setTime", (PyCFunction) KX_SCA_AddObjectActuator::sPySetTime, METH_VARARGS, SetTime_doc},
- {"getObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetObject, METH_VARARGS, GetObject_doc},
- {"getTime", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetTime, METH_VARARGS, GetTime_doc},
- {"getLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLinearVelocity, METH_VARARGS, GetLinearVelocity_doc},
- {"setLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPySetLinearVelocity, METH_VARARGS, SetLinearVelocity_doc},
- {"getLastCreatedObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLastCreatedObject, METH_VARARGS,"getLastCreatedObject() : get the object handle to the last created object\n"},
- {"instantAddObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyInstantAddObject, METH_VARARGS,"instantAddObject() : immediately add object without delay\n"},
+ {"setObject", (PyCFunction) KX_SCA_AddObjectActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc},
+ {"setTime", (PyCFunction) KX_SCA_AddObjectActuator::sPySetTime, METH_O, (PY_METHODCHAR)SetTime_doc},
+ {"getObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc},
+ {"getTime", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetTime, METH_NOARGS, (PY_METHODCHAR)GetTime_doc},
+ {"getLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLinearVelocity, METH_NOARGS, (PY_METHODCHAR)GetLinearVelocity_doc},
+ {"setLinearVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPySetLinearVelocity, METH_VARARGS, (PY_METHODCHAR)SetLinearVelocity_doc},
+ {"getAngularVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetAngularVelocity, METH_NOARGS, (PY_METHODCHAR)GetAngularVelocity_doc},
+ {"setAngularVelocity", (PyCFunction) KX_SCA_AddObjectActuator::sPySetAngularVelocity, METH_VARARGS, (PY_METHODCHAR)SetAngularVelocity_doc},
+ {"getLastCreatedObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyGetLastCreatedObject, METH_NOARGS,"getLastCreatedObject() : get the object handle to the last created object\n"},
+ {"instantAddObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyInstantAddObject, METH_NOARGS,"instantAddObject() : immediately add object without delay\n"},
{NULL,NULL} //Sentinel
};
@@ -166,114 +209,101 @@ PyObject* KX_SCA_AddObjectActuator::_getattr(const STR_String& attr)
}
/* 1. setObject */
-char KX_SCA_AddObjectActuator::SetObject_doc[] =
-"setObject(name)\n"
-"\t- name: string\n"
+const char KX_SCA_AddObjectActuator::SetObject_doc[] =
+"setObject(object)\n"
+"\t- object: KX_GameObject, string or None\n"
"\tSets the object that will be added. There has to be an object\n"
"\tof this name. If not, this function does nothing.\n";
-
-
-
-PyObject* KX_SCA_AddObjectActuator::PySetObject(PyObject* self,
- PyObject* args,
- PyObject* kwds)
-{
- PyObject* gameobj;
- if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj))
- {
- m_OriginalObject = (CValue*)gameobj;
- Py_Return;
- }
- PyErr_Clear();
+PyObject* KX_SCA_AddObjectActuator::PySetObject(PyObject* self, PyObject* value)
+{
+ KX_GameObject *gameobj;
- char* objectname;
- if (PyArg_ParseTuple(args, "s", &objectname))
- {
- m_OriginalObject= (CValue*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname));;
-
- Py_Return;
- }
+ if (!ConvertPythonToGameObject(value, &gameobj, true))
+ return NULL; // ConvertPythonToGameObject sets the error
+
+ if (m_OriginalObject != NULL)
+ m_OriginalObject->UnregisterActuator(this);
+
+ m_OriginalObject = (SCA_IObject*)gameobj;
+ if (m_OriginalObject)
+ m_OriginalObject->RegisterActuator(this);
- return NULL;
+ Py_RETURN_NONE;
}
/* 2. setTime */
-char KX_SCA_AddObjectActuator::SetTime_doc[] =
+const char KX_SCA_AddObjectActuator::SetTime_doc[] =
"setTime(duration)\n"
"\t- duration: integer\n"
"\tSets the lifetime of the object that will be added, in frames. \n"
"\tIf the duration is negative, it is set to 0.\n";
-PyObject* KX_SCA_AddObjectActuator::PySetTime(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_SCA_AddObjectActuator::PySetTime(PyObject* self, PyObject* value)
{
- int deltatime;
-
- if (!PyArg_ParseTuple(args, "i", &deltatime))
+ int deltatime = PyInt_AsLong(value);
+ if (deltatime==-1 && PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "expected an int");
return NULL;
+ }
m_timeProp = deltatime;
if (m_timeProp < 0) m_timeProp = 0;
- Py_Return;
+ Py_RETURN_NONE;
}
/* 3. getTime */
-char KX_SCA_AddObjectActuator::GetTime_doc[] =
+const char KX_SCA_AddObjectActuator::GetTime_doc[] =
"GetTime()\n"
"\tReturns the lifetime of the object that will be added.\n";
-PyObject* KX_SCA_AddObjectActuator::PyGetTime(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_SCA_AddObjectActuator::PyGetTime(PyObject* self)
{
return PyInt_FromLong(m_timeProp);
}
/* 4. getObject */
-char KX_SCA_AddObjectActuator::GetObject_doc[] =
-"getObject()\n"
+const char KX_SCA_AddObjectActuator::GetObject_doc[] =
+"getObject(name_only = 1)\n"
+"name_only - optional arg, when true will return the KX_GameObject rather then its name\n"
"\tReturns the name of the object that will be added.\n";
-
-
-
-PyObject* KX_SCA_AddObjectActuator::PyGetObject(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_SCA_AddObjectActuator::PyGetObject(PyObject* self, PyObject* args)
{
+ int ret_name_only = 1;
+ if (!PyArg_ParseTuple(args, "|i", &ret_name_only))
+ return NULL;
+
if (!m_OriginalObject)
- Py_Return;
-
- return PyString_FromString(m_OriginalObject->GetName());
+ Py_RETURN_NONE;
+
+ if (ret_name_only)
+ return PyString_FromString(m_OriginalObject->GetName());
+ else
+ return m_OriginalObject->AddRef();
}
/* 5. getLinearVelocity */
-char KX_SCA_AddObjectActuator::GetLinearVelocity_doc[] =
+const char KX_SCA_AddObjectActuator::GetLinearVelocity_doc[] =
"GetLinearVelocity()\n"
"\tReturns the linear velocity that will be assigned to \n"
"\tthe created object.\n";
-
-
-PyObject* KX_SCA_AddObjectActuator::PyGetLinearVelocity(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_SCA_AddObjectActuator::PyGetLinearVelocity(PyObject* self)
{
PyObject *retVal = PyList_New(3);
- PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0]));
- PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1]));
- PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2]));
+ PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0]));
+ PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1]));
+ PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2]));
return retVal;
}
@@ -281,17 +311,15 @@ PyObject* KX_SCA_AddObjectActuator::PyGetLinearVelocity(PyObject* self,
/* 6. setLinearVelocity */
-char KX_SCA_AddObjectActuator::SetLinearVelocity_doc[] =
+const char KX_SCA_AddObjectActuator::SetLinearVelocity_doc[] =
"setLinearVelocity(vx, vy, vz)\n"
"\t- vx: float\n"
"\t- vy: float\n"
"\t- vz: float\n"
+"\t- local: bool\n"
"\tAssign this velocity to the created object. \n";
-
-PyObject* KX_SCA_AddObjectActuator::PySetLinearVelocity(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_SCA_AddObjectActuator::PySetLinearVelocity(PyObject* self, PyObject* args)
{
float vecArg[3];
@@ -299,7 +327,46 @@ PyObject* KX_SCA_AddObjectActuator::PySetLinearVelocity(PyObject* self,
return NULL;
m_linear_velocity.setValue(vecArg);
- Py_Return;
+ Py_RETURN_NONE;
+}
+
+/* 7. getAngularVelocity */
+const char KX_SCA_AddObjectActuator::GetAngularVelocity_doc[] =
+"GetAngularVelocity()\n"
+"\tReturns the angular velocity that will be assigned to \n"
+"\tthe created object.\n";
+
+PyObject* KX_SCA_AddObjectActuator::PyGetAngularVelocity(PyObject* self)
+{
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_angular_velocity[0]));
+ PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_angular_velocity[1]));
+ PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_angular_velocity[2]));
+
+ return retVal;
+}
+
+
+
+/* 8. setAngularVelocity */
+const char KX_SCA_AddObjectActuator::SetAngularVelocity_doc[] =
+"setAngularVelocity(vx, vy, vz)\n"
+"\t- vx: float\n"
+"\t- vy: float\n"
+"\t- vz: float\n"
+"\t- local: bool\n"
+"\tAssign this angular velocity to the created object. \n";
+
+PyObject* KX_SCA_AddObjectActuator::PySetAngularVelocity(PyObject* self, PyObject* args)
+{
+
+ float vecArg[3];
+ if (!PyArg_ParseTuple(args, "fff", &vecArg[0], &vecArg[1], &vecArg[2]))
+ return NULL;
+
+ m_angular_velocity.setValue(vecArg);
+ Py_RETURN_NONE;
}
void KX_SCA_AddObjectActuator::InstantAddObject()
@@ -310,8 +377,9 @@ void KX_SCA_AddObjectActuator::InstantAddObject()
// Now it needs to be added to the current scene.
SCA_IObject* replica = m_scene->AddReplicaObject(m_OriginalObject,GetParent(),m_timeProp );
KX_GameObject * game_obj = static_cast<KX_GameObject *>(replica);
- game_obj->setLinearVelocity(m_linear_velocity,m_localFlag);
- game_obj->ResolveCombinedVelocities(m_linear_velocity, MT_Vector3(0., 0., 0.), m_localFlag, false);
+ game_obj->setLinearVelocity(m_linear_velocity,m_localLinvFlag);
+ game_obj->setAngularVelocity(m_angular_velocity,m_localAngvFlag);
+ game_obj->ResolveCombinedVelocities(m_linear_velocity, m_angular_velocity, m_localLinvFlag, m_localAngvFlag);
// keep a copy of the last object, to allow python scripters to change it
if (m_lastCreatedObject)
@@ -323,36 +391,37 @@ void KX_SCA_AddObjectActuator::InstantAddObject()
m_lastCreatedObject = replica;
m_lastCreatedObject->AddRef();
+ // finished using replica? then release it
+ replica->Release();
}
}
-PyObject* KX_SCA_AddObjectActuator::PyInstantAddObject(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_SCA_AddObjectActuator::PyInstantAddObject(PyObject* self)
{
InstantAddObject();
- Py_Return;
+ Py_RETURN_NONE;
}
/* 7. GetLastCreatedObject */
-char KX_SCA_AddObjectActuator::GetLastCreatedObject_doc[] =
+const char KX_SCA_AddObjectActuator::GetLastCreatedObject_doc[] =
"getLastCreatedObject()\n"
"\tReturn the last created object. \n";
-PyObject* KX_SCA_AddObjectActuator::PyGetLastCreatedObject(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_SCA_AddObjectActuator::PyGetLastCreatedObject(PyObject* self)
{
SCA_IObject* result = this->GetLastCreatedObject();
- if (result)
+
+ // if result->GetSGNode() is NULL
+ // it means the object has ended, The BGE python api crashes in many places if the object is returned.
+ if (result && (static_cast<KX_GameObject *>(result))->GetSGNode())
{
result->AddRef();
return result;
}
// don't return NULL to python anymore, it gives trouble in the scripts
- Py_Return;
+ Py_RETURN_NONE;
}
diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h
index 2126a646303..278d4180284 100644
--- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h
+++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h
@@ -53,16 +53,20 @@ class KX_SCA_AddObjectActuator : public SCA_IActuator
int m_timeProp;
/// Original object reference (object to replicate)
- CValue* m_OriginalObject;
+ SCA_IObject* m_OriginalObject;
/// Object will be added to the following scene
SCA_IScene* m_scene;
/// Linear velocity upon creation of the object.
MT_Vector3 m_linear_velocity;
+
+ /// Angular velocity upon creation of the object.
+ MT_Vector3 m_angular_velocity;
/// Apply the velocity locally
- bool m_localFlag;
+ bool m_localLinvFlag;
+ bool m_localAngvFlag;
SCA_IObject* m_lastCreatedObject;
@@ -75,11 +79,13 @@ public:
KX_SCA_AddObjectActuator(
SCA_IObject *gameobj,
- CValue* original,
+ SCA_IObject *original,
int time,
SCA_IScene* scene,
const MT_Vector3& linvel,
- bool local,
+ bool linv_local,
+ const MT_Vector3& angvel,
+ bool angv_local,
PyTypeObject* T=&Type
);
@@ -89,6 +95,15 @@ public:
GetReplica(
) ;
+ virtual void
+ ProcessReplica();
+
+ virtual bool
+ UnlinkObject(SCA_IObject* clientobj);
+
+ virtual void
+ Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
+
virtual bool
Update();
@@ -104,21 +119,25 @@ public:
void InstantAddObject();
/* 1. setObject */
- KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,SetObject);
+ KX_PYMETHOD_DOC_O(KX_SCA_AddObjectActuator,SetObject);
/* 2. setTime */
- KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,SetTime);
+ KX_PYMETHOD_DOC_O(KX_SCA_AddObjectActuator,SetTime);
/* 3. getTime */
- KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetTime);
+ KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetTime);
/* 4. getObject */
- KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetObject);
+ KX_PYMETHOD_DOC_VARARGS(KX_SCA_AddObjectActuator,GetObject);
/* 5. getLinearVelocity */
- KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetLinearVelocity);
+ KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetLinearVelocity);
/* 6. setLinearVelocity */
- KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,SetLinearVelocity);
- /* 7. getLastCreatedObject */
- KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,GetLastCreatedObject);
- /* 8. instantAddObject*/
- KX_PYMETHOD_DOC(KX_SCA_AddObjectActuator,InstantAddObject);
+ KX_PYMETHOD_DOC_VARARGS(KX_SCA_AddObjectActuator,SetLinearVelocity);
+ /* 7. getAngularVelocity */
+ KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetAngularVelocity);
+ /* 8. setAngularVelocity */
+ KX_PYMETHOD_DOC_VARARGS(KX_SCA_AddObjectActuator,SetAngularVelocity);
+ /* 9. getLastCreatedObject */
+ KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,GetLastCreatedObject);
+ /* 10. instantAddObject*/
+ KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,InstantAddObject);
}; /* end of class KX_SCA_AddObjectActuator : public KX_EditObjectActuator */
diff --git a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp
new file mode 100644
index 00000000000..d44ab477749
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp
@@ -0,0 +1,206 @@
+//
+// Adjust dynamics settins for this object
+//
+// $Id$
+//
+// ***** BEGIN GPL LICENSE BLOCK *****
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+// All rights reserved.
+//
+// The Original Code is: all of this file.
+//
+// Contributor(s): none yet.
+//
+// ***** END GPL LICENSE BLOCK *****
+
+//
+// Previously existed as:
+
+// \source\gameengine\GameLogic\SCA_DynamicActuator.cpp
+
+// Please look here for revision history.
+
+#include "KX_SCA_DynamicActuator.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+
+ PyTypeObject
+
+KX_SCA_DynamicActuator::
+
+Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_SCA_DynamicActuator",
+ sizeof(KX_SCA_DynamicActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0,
+ __repr,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject KX_SCA_DynamicActuator::Parents[] = {
+ &KX_SCA_DynamicActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+
+PyMethodDef KX_SCA_DynamicActuator::Methods[] = {
+ KX_PYMETHODTABLE(KX_SCA_DynamicActuator, setOperation),
+ KX_PYMETHODTABLE(KX_SCA_DynamicActuator, getOperation),
+ {NULL,NULL} //Sentinel
+};
+
+
+
+PyObject* KX_SCA_DynamicActuator::_getattr(const STR_String& attr)
+{
+ _getattr_up(SCA_IActuator);
+}
+
+
+
+/* 1. setOperation */
+KX_PYMETHODDEF_DOC(KX_SCA_DynamicActuator, setOperation,
+"setOperation(operation?)\n"
+"\t - operation? : type of dynamic operation\n"
+"\t 0 = restore dynamics\n"
+"\t 1 = disable dynamics\n"
+"\t 2 = enable rigid body\n"
+"\t 3 = disable rigid body\n"
+"Change the dynamic status of the parent object.\n")
+{
+ int dyn_operation;
+
+ if (!PyArg_ParseTuple(args, "i", &dyn_operation))
+ {
+ return NULL;
+ }
+ if (dyn_operation <0 || dyn_operation>3) {
+ PyErr_SetString(PyExc_IndexError, "Dynamic Actuator's setOperation() range must be between 0 and 3");
+ return NULL;
+ }
+ m_dyn_operation= dyn_operation;
+ Py_Return;
+}
+
+KX_PYMETHODDEF_DOC(KX_SCA_DynamicActuator, getOperation,
+"getOperation() -> integer\n"
+"Returns the operation type of this actuator.\n"
+)
+{
+ return PyInt_FromLong((long)m_dyn_operation);
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+KX_SCA_DynamicActuator::KX_SCA_DynamicActuator(SCA_IObject *gameobj,
+ short dyn_operation,
+ PyTypeObject* T) :
+
+ SCA_IActuator(gameobj, T),
+ m_dyn_operation(dyn_operation)
+{
+} /* End of constructor */
+
+
+KX_SCA_DynamicActuator::~KX_SCA_DynamicActuator()
+{
+ // there's nothing to be done here, really....
+} /* end of destructor */
+
+
+
+bool KX_SCA_DynamicActuator::Update()
+{
+ // bool result = false; /*unused*/
+ KX_GameObject *obj = (KX_GameObject*) GetParent();
+ bool bNegativeEvent = IsNegativeEvent();
+ KX_IPhysicsController* controller;
+ RemoveAllEvents();
+
+ if (bNegativeEvent)
+ return false; // do nothing on negative events
+
+ if (!obj)
+ return false; // object not accessible, shouldnt happen
+ controller = obj->GetPhysicsController();
+ if (!controller)
+ return false; // no physic object
+
+ switch (m_dyn_operation)
+ {
+ case 0:
+ obj->RestoreDynamics();
+ break;
+ case 1:
+ obj->SuspendDynamics();
+ break;
+ case 2:
+ controller->setRigidBody(true);
+ break;
+ case 3:
+ controller->setRigidBody(false);
+ break;
+ }
+
+ return false;
+}
+
+
+
+CValue* KX_SCA_DynamicActuator::GetReplica()
+{
+ KX_SCA_DynamicActuator* replica =
+ new KX_SCA_DynamicActuator(*this);
+
+ if (replica == NULL)
+ return NULL;
+
+ replica->ProcessReplica();
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+
+ return replica;
+};
+
+
+/* eof */
diff --git a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h
new file mode 100644
index 00000000000..b47c3a511d9
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h
@@ -0,0 +1,76 @@
+//
+// Add object to the game world on action of this actuator
+//
+// $Id$
+//
+// ***** BEGIN GPL LICENSE BLOCK *****
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+// All rights reserved.
+//
+// The Original Code is: all of this file.
+//
+// Contributor(s): Campbell Barton
+//
+// ***** END GPL LICENSE BLOCK *****
+//
+
+#ifndef __KX_SCA_DYNAMICACTUATOR
+#define __KX_SCA_DYNAMICACTUATOR
+
+#include "SCA_IActuator.h"
+#include "SCA_PropertyActuator.h"
+#include "SCA_LogicManager.h"
+
+#include "KX_GameObject.h"
+#include "KX_IPhysicsController.h"
+
+class KX_SCA_DynamicActuator : public SCA_IActuator
+{
+ Py_Header;
+
+ // dynamics operation to apply to the game object
+ short m_dyn_operation;
+ public:
+ KX_SCA_DynamicActuator(
+ SCA_IObject* gameobj,
+ short dyn_operation,
+ PyTypeObject* T=&Type
+ );
+
+ ~KX_SCA_DynamicActuator(
+ );
+
+ CValue*
+ GetReplica(
+ );
+
+ virtual bool
+ Update();
+
+ virtual PyObject*
+ _getattr(
+ const STR_String& attr
+ );
+
+ /* 1. setOperation */
+ KX_PYMETHOD_DOC(KX_SCA_DynamicActuator,setOperation);
+ KX_PYMETHOD_DOC(KX_SCA_DynamicActuator,getOperation);
+
+};
+
+#endif
diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp
index 630df2d21d9..261d9ec8f0c 100644
--- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp
@@ -37,6 +37,8 @@
#include "KX_SCA_ReplaceMeshActuator.h"
+#include "PyObjectPlus.h"
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -80,7 +82,7 @@ PyParentObject KX_SCA_ReplaceMeshActuator::Parents[] = {
PyMethodDef KX_SCA_ReplaceMeshActuator::Methods[] = {
- {"setMesh", (PyCFunction) KX_SCA_ReplaceMeshActuator::sPySetMesh, METH_VARARGS, SetMesh_doc},
+ {"setMesh", (PyCFunction) KX_SCA_ReplaceMeshActuator::sPySetMesh, METH_O, (PY_METHODCHAR)SetMesh_doc},
KX_PYMETHODTABLE(KX_SCA_ReplaceMeshActuator, instantReplaceMesh),
KX_PYMETHODTABLE(KX_SCA_ReplaceMeshActuator, getMesh),
@@ -97,30 +99,31 @@ PyObject* KX_SCA_ReplaceMeshActuator::_getattr(const STR_String& attr)
/* 1. setMesh */
-char KX_SCA_ReplaceMeshActuator::SetMesh_doc[] =
+const char KX_SCA_ReplaceMeshActuator::SetMesh_doc[] =
"setMesh(name)\n"
- "\t- name: string\n"
+ "\t- name: string or None\n"
"\tSet the mesh that will be substituted for the current one.\n";
-PyObject* KX_SCA_ReplaceMeshActuator::PySetMesh(PyObject* self,
- PyObject* args,
- PyObject* kwds)
+PyObject* KX_SCA_ReplaceMeshActuator::PySetMesh(PyObject* self, PyObject* value)
{
- char* meshname;
-
- if (!PyArg_ParseTuple(args, "s", &meshname))
- {
- return NULL;
- }
-
- void* mesh = SCA_ILogicBrick::m_sCurrentLogicManager->GetMeshByName(STR_String(meshname));
-
- if (mesh) {
+ if (value == Py_None) {
+ m_mesh = NULL;
+ } else {
+ char* meshname = PyString_AsString(value);
+ if (!meshname) {
+ PyErr_SetString(PyExc_ValueError, "Expected the name of a mesh or None");
+ return NULL;
+ }
+ void* mesh = SCA_ILogicBrick::m_sCurrentLogicManager->GetMeshByName(STR_String(meshname));
+
+ if (mesh==NULL) {
+ PyErr_SetString(PyExc_ValueError, "The mesh name given does not exist");
+ return NULL;
+ }
m_mesh= (class RAS_MeshObject*)mesh;
- Py_Return;
}
- return NULL;
+ Py_RETURN_NONE;
}
KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, getMesh,
@@ -129,7 +132,7 @@ KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, getMesh,
)
{
if (!m_mesh)
- Py_Return;
+ Py_RETURN_NONE;
return PyString_FromString(const_cast<char *>(m_mesh->GetName().ReadPtr()));
}
@@ -139,7 +142,7 @@ KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, instantReplaceMesh,
"instantReplaceMesh() : immediately replace mesh without delay\n")
{
InstantReplaceMesh();
- Py_Return;
+ Py_RETURN_NONE;
}
/* ------------------------------------------------------------------------- */
diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h
index 5ba0a099b14..1da154cc222 100644
--- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h
+++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h
@@ -76,7 +76,7 @@ class KX_SCA_ReplaceMeshActuator : public SCA_IActuator
void InstantReplaceMesh();
/* 1. setMesh */
- KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,SetMesh);
+ KX_PYMETHOD_DOC_O(KX_SCA_ReplaceMeshActuator,SetMesh);
KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,getMesh);
KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,instantReplaceMesh);
diff --git a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp
index f085ff435dc..d651373869a 100644
--- a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp
+++ b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp
@@ -78,7 +78,7 @@ UpdateChildCoordinates(
if (parent)
{
- const BL_ArmatureObject *armature = (const BL_ArmatureObject*)(parent->GetSGClientObject());
+ BL_ArmatureObject *armature = (BL_ArmatureObject*)(parent->GetSGClientObject());
if (armature)
{
MT_Matrix4x4 parent_matrix;
diff --git a/source/gameengine/Ketsji/KX_SG_NodeRelationships.h b/source/gameengine/Ketsji/KX_SG_NodeRelationships.h
index d83fb79ee25..faa650106c8 100644
--- a/source/gameengine/Ketsji/KX_SG_NodeRelationships.h
+++ b/source/gameengine/Ketsji/KX_SG_NodeRelationships.h
@@ -129,6 +129,12 @@ public :
~KX_VertexParentRelation(
);
+ bool
+ IsVertexRelation(
+ ) {
+ return true;
+ }
+
private :
KX_VertexParentRelation(
@@ -171,8 +177,23 @@ public :
NewCopy(
);
+ MT_Scalar
+ GetTimeOffset(
+ ) { return m_relax; }
+
+ void
+ SetTimeOffset(
+ MT_Scalar relaxation
+ ) { m_relax = relaxation; }
+
~KX_SlowParentRelation(
);
+
+ bool
+ IsSlowRelation(
+ ) {
+ return true;
+ }
private :
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
index 7f7558b0ab7..caa71441b1d 100644
--- a/source/gameengine/Ketsji/KX_Scene.cpp
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -32,10 +32,12 @@
#pragma warning (disable : 4786)
#endif //WIN32
+
#include "KX_Scene.h"
#include "MT_assert.h"
#include "KX_KetsjiEngine.h"
+#include "KX_BlenderMaterial.h"
#include "RAS_IPolygonMaterial.h"
#include "ListValue.h"
#include "SCA_LogicManager.h"
@@ -47,6 +49,7 @@
#include "SCA_KeyboardManager.h"
#include "SCA_MouseManager.h"
#include "SCA_PropertyEventManager.h"
+#include "SCA_ActuatorEventManager.h"
#include "KX_Camera.h"
#include "SCA_JoystickManager.h"
@@ -64,6 +67,9 @@
#include "SG_Controller.h"
#include "SG_IObject.h"
#include "SG_Tree.h"
+#include "DNA_group_types.h"
+#include "DNA_scene_types.h"
+#include "BKE_anim.h"
#include "KX_SG_NodeRelationships.h"
@@ -71,15 +77,26 @@
#include "NG_NetworkScene.h"
#include "PHY_IPhysicsEnvironment.h"
#include "KX_IPhysicsController.h"
+#include "KX_BlenderSceneConverter.h"
-#include "BL_SkinDeformer.h"
+#include "BL_ShapeDeformer.h"
#include "BL_DeformableGameObject.h"
+// to get USE_BULLET!
+#include "KX_ConvertPhysicsObject.h"
+
+#ifdef USE_BULLET
+#include "CcdPhysicsEnvironment.h"
+#include "CcdPhysicsController.h"
+#endif
void* KX_SceneReplicationFunc(SG_IObject* node,void* gameobj,void* scene)
{
KX_GameObject* replica = ((KX_Scene*)scene)->AddNodeReplicaObject(node,(KX_GameObject*)gameobj);
+ if(replica)
+ replica->Release();
+
return (void*)replica;
}
@@ -100,16 +117,19 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
class SCA_IInputDevice* mousedevice,
class NG_NetworkDeviceInterface *ndi,
class SND_IAudioDevice* adi,
- const STR_String& sceneName):
+ const STR_String& sceneName,
+ Scene *scene):
PyObjectPlus(&KX_Scene::Type),
m_keyboardmgr(NULL),
m_mousemgr(NULL),
+ m_sceneConverter(NULL),
m_physicsEnvironment(0),
m_sceneName(sceneName),
m_adi(adi),
m_networkDeviceInterface(ndi),
m_active_camera(NULL),
- m_ueberExecutionPriority(0)
+ m_ueberExecutionPriority(0),
+ m_blenderScene(scene)
{
m_suspendedtime = 0.0;
m_suspendeddelta = 0.0;
@@ -121,6 +141,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
m_objectlist = new CListValue();
m_parentlist = new CListValue();
m_lightlist= new CListValue();
+ m_inactivelist = new CListValue();
m_euthanasyobjects = new CListValue();
m_delayReleaseObjects = new CListValue();
@@ -132,22 +153,32 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
SCA_AlwaysEventManager* alwaysmgr = new SCA_AlwaysEventManager(m_logicmgr);
SCA_PropertyEventManager* propmgr = new SCA_PropertyEventManager(m_logicmgr);
+ SCA_ActuatorEventManager* actmgr = new SCA_ActuatorEventManager(m_logicmgr);
SCA_RandomEventManager* rndmgr = new SCA_RandomEventManager(m_logicmgr);
KX_RayEventManager* raymgr = new KX_RayEventManager(m_logicmgr);
KX_NetworkEventManager* netmgr = new KX_NetworkEventManager(m_logicmgr, ndi);
- SCA_JoystickManager *joymgr = new SCA_JoystickManager(m_logicmgr);
+
m_logicmgr->RegisterEventManager(alwaysmgr);
m_logicmgr->RegisterEventManager(propmgr);
+ m_logicmgr->RegisterEventManager(actmgr);
m_logicmgr->RegisterEventManager(m_keyboardmgr);
m_logicmgr->RegisterEventManager(m_mousemgr);
m_logicmgr->RegisterEventManager(m_timemgr);
m_logicmgr->RegisterEventManager(rndmgr);
m_logicmgr->RegisterEventManager(raymgr);
m_logicmgr->RegisterEventManager(netmgr);
- m_logicmgr->RegisterEventManager(joymgr);
+
+
+ SYS_SystemHandle hSystem = SYS_GetSystem();
+ bool nojoystick= SYS_GetCommandLineInt(hSystem,"nojoystick",0);
+ if (!nojoystick)
+ {
+ SCA_JoystickManager *joymgr = new SCA_JoystickManager(m_logicmgr);
+ m_logicmgr->RegisterEventManager(joymgr);
+ }
m_soundScene = new SND_Scene(adi);
MT_assert (m_networkDeviceInterface != NULL);
@@ -167,13 +198,14 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
KX_Scene::~KX_Scene()
{
-
-// int numobj = m_objectlist->GetCount();
+ // The release of debug properties used to be in SCA_IScene::~SCA_IScene
+ // It's still there but we remove all properties here otherwise some
+ // reference might be hanging and causing late release of objects
+ RemoveAllDebugProperties();
- //int numrootobjects = GetRootParentList()->GetCount();
- for (int i = 0; i < GetRootParentList()->GetCount(); i++)
+ while (GetRootParentList()->GetCount() > 0)
{
- KX_GameObject* parentobj = (KX_GameObject*) GetRootParentList()->GetValue(i);
+ KX_GameObject* parentobj = (KX_GameObject*) GetRootParentList()->GetValue(0);
this->RemoveObject(parentobj);
}
@@ -183,6 +215,9 @@ KX_Scene::~KX_Scene()
if (m_parentlist)
m_parentlist->Release();
+ if (m_inactivelist)
+ m_inactivelist->Release();
+
if (m_lightlist)
m_lightlist->Release();
@@ -210,13 +245,9 @@ KX_Scene::~KX_Scene()
{
delete m_bucketmanager;
}
-
//Py_DECREF(m_attrlist);
}
-
-
-
void KX_Scene::SetProjectionMatrix(MT_CmMatrix4x4& pmat)
{
m_projectionmat = pmat;
@@ -243,6 +274,11 @@ CListValue* KX_Scene::GetRootParentList()
return m_parentlist;
}
+CListValue* KX_Scene::GetInactiveList()
+{
+ return m_inactivelist;
+}
+
CListValue* KX_Scene::GetLightList()
@@ -263,7 +299,7 @@ SCA_TimeEventManager* KX_Scene::GetTimeEventManager()
-set<class KX_Camera*>* KX_Scene::GetCameras()
+list<class KX_Camera*>* KX_Scene::GetCameras()
{
return &m_cameras;
}
@@ -364,14 +400,26 @@ void KX_Scene::EnableZBufferClearing(bool isclearingZbuffer)
void KX_Scene::RemoveNodeDestructObject(class SG_IObject* node,class CValue* gameobj)
{
KX_GameObject* orgobj = (KX_GameObject*)gameobj;
- NewRemoveObject(orgobj);
-
+ if (NewRemoveObject(orgobj) != 0)
+ {
+ // object is not yet deleted (this can happen when it hangs in an add object actuator
+ // last object created reference. It's a bad situation, don't know how to fix it exactly
+ // The least I can do, is remove the reference to the node in the object as the node
+ // will in any case be deleted. This ensures that the object will not try to use the node
+ // when it is finally deleted (see KX_GameObject destructor)
+ orgobj->SetSGNode(NULL);
+ }
if (node)
delete node;
}
KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CValue* gameobj)
{
+ // for group duplication, limit the duplication of the hierarchy to the
+ // objects that are part of the group.
+ if (!IsObjectInGroup(gameobj))
+ return NULL;
+
KX_GameObject* orgobj = (KX_GameObject*)gameobj;
KX_GameObject* newobj = (KX_GameObject*)orgobj->GetReplica();
m_map_gameobject_to_replica.insert(orgobj, newobj);
@@ -415,8 +463,8 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal
replicanode->SetSGClientObject(newobj);
// this is the list of object that are send to the graphics pipeline
- m_objectlist->Add(newobj);
- newobj->Bucketize();
+ m_objectlist->Add(newobj->AddRef());
+ newobj->AddMeshUser();
// logic cannot be replicated, until the whole hierarchy is replicated.
m_logicHierarchicalGameObjects.push_back(newobj);
@@ -449,6 +497,11 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal
// hierarchy that's because first ALL bricks must exist in the new
// replica of the hierarchy in order to make cross-links work properly
// !
+// It is VERY important that the order of sensors and actuators in
+// the replicated object is preserved: it is is used to reconnect the logic.
+// This method is more robust then using the bricks name in case of complex
+// group replication. The replication of logic bricks is done in
+// SCA_IObject::ReParentLogic(), make sure it preserves the order of the bricks.
void KX_Scene::ReplicateLogic(KX_GameObject* newobj)
{
// also relink the controller to sensors/actuators
@@ -471,37 +524,38 @@ void KX_Scene::ReplicateLogic(KX_GameObject* newobj)
for (vector<SCA_ISensor*>::iterator its = linkedsensors.begin();!(its==linkedsensors.end());its++)
{
SCA_ISensor* oldsensor = (*its);
- STR_String name = oldsensor->GetName();
- //find this name in the list
- SCA_ISensor* newsensor = newobj->FindSensor(name);
+ SCA_IObject* oldsensorobj = oldsensor->GetParent();
+ SCA_IObject* newsensorobj = NULL;
- if (newsensor)
+ // the original owner of the sensor has been replicated?
+ void **h_obj = m_map_gameobject_to_replica[oldsensorobj];
+ if (h_obj)
+ newsensorobj = (SCA_IObject*)(*h_obj);
+ if (!newsensorobj)
{
- // relink this newsensor to the controller
- m_logicmgr->RegisterToSensor(cont,newsensor);
+ // no, then the sensor points outside the hierachy, keep it the same
+ if (m_objectlist->SearchValue(oldsensorobj))
+ // only replicate links that points to active objects
+ m_logicmgr->RegisterToSensor(cont,oldsensor);
}
else
{
- // it can be linked somewhere in the hierarchy or...
- for (vector<KX_GameObject*>::iterator git = m_logicHierarchicalGameObjects.begin();
- !(git==m_logicHierarchicalGameObjects.end());++git)
- {
- newsensor = (*git)->FindSensor(name);
- if (newsensor)
- break;
- }
+ // yes, then the new sensor has the same position
+ SCA_SensorList& sensorlist = oldsensorobj->GetSensors();
+ SCA_SensorList::iterator sit;
+ SCA_ISensor* newsensor = NULL;
+ int sensorpos;
- if (newsensor)
- {
- // relink this newsensor to the controller somewhere else within this
- // hierarchy
- m_logicmgr->RegisterToSensor(cont,newsensor);
- }
- else
+ for (sensorpos=0, sit=sensorlist.begin(); sit!=sensorlist.end(); sit++, sensorpos++)
{
- // must be an external sensor, so...
- m_logicmgr->RegisterToSensor(cont,oldsensor);
+ if ((*sit) == oldsensor)
+ {
+ newsensor = newsensorobj->GetSensors().at(sensorpos);
+ break;
+ }
}
+ assert(newsensor != NULL);
+ m_logicmgr->RegisterToSensor(cont,newsensor);
}
}
@@ -509,43 +563,189 @@ void KX_Scene::ReplicateLogic(KX_GameObject* newobj)
for (vector<SCA_IActuator*>::iterator ita = linkedactuators.begin();!(ita==linkedactuators.end());ita++)
{
SCA_IActuator* oldactuator = (*ita);
- STR_String name = oldactuator->GetName();
- //find this name in the list
- SCA_IActuator* newactuator = newobj->FindActuator(name);
- if (newactuator)
+ SCA_IObject* oldactuatorobj = oldactuator->GetParent();
+ SCA_IObject* newactuatorobj = NULL;
+
+ // the original owner of the sensor has been replicated?
+ void **h_obj = m_map_gameobject_to_replica[oldactuatorobj];
+ if (h_obj)
+ newactuatorobj = (SCA_IObject*)(*h_obj);
+
+ if (!newactuatorobj)
{
- // relink this newsensor to the controller
- m_logicmgr->RegisterToActuator(cont,newactuator);
- newactuator->SetUeberExecutePriority(m_ueberExecutionPriority);
+ // no, then the sensor points outside the hierachy, keep it the same
+ if (m_objectlist->SearchValue(oldactuatorobj))
+ // only replicate links that points to active objects
+ m_logicmgr->RegisterToActuator(cont,oldactuator);
}
else
{
- // it can be linked somewhere in the hierarchy or...
- for (vector<KX_GameObject*>::iterator git = m_logicHierarchicalGameObjects.begin();
- !(git==m_logicHierarchicalGameObjects.end());++git)
- {
- newactuator= (*git)->FindActuator(name);
- if (newactuator)
- break;
- }
+ // yes, then the new sensor has the same position
+ SCA_ActuatorList& actuatorlist = oldactuatorobj->GetActuators();
+ SCA_ActuatorList::iterator ait;
+ SCA_IActuator* newactuator = NULL;
+ int actuatorpos;
- if (newactuator)
+ for (actuatorpos=0, ait=actuatorlist.begin(); ait!=actuatorlist.end(); ait++, actuatorpos++)
{
- // relink this actuator to the controller somewhere else within this
- // hierarchy
- m_logicmgr->RegisterToActuator(cont,newactuator);
- newactuator->SetUeberExecutePriority(m_ueberExecutionPriority);
- }
- else
- {
- // must be an external actuator, so...
- m_logicmgr->RegisterToActuator(cont,oldactuator);
+ if ((*ait) == oldactuator)
+ {
+ newactuator = newactuatorobj->GetActuators().at(actuatorpos);
+ break;
+ }
}
+ assert(newactuator != NULL);
+ m_logicmgr->RegisterToActuator(cont,newactuator);
+ newactuator->SetUeberExecutePriority(m_ueberExecutionPriority);
}
}
}
+ // ready to set initial state
+ newobj->ResetState();
}
+void KX_Scene::DupliGroupRecurse(CValue* obj, int level)
+{
+ KX_GameObject* groupobj = (KX_GameObject*) obj;
+ KX_GameObject* replica;
+ KX_GameObject* gameobj;
+ Object* blgroupobj = groupobj->GetBlenderObject();
+ Group* group;
+ GroupObject *go;
+ vector<KX_GameObject*> duplilist;
+
+ if (!groupobj->GetSGNode() ||
+ !groupobj->IsDupliGroup() ||
+ level>MAX_DUPLI_RECUR)
+ return;
+
+ // we will add one group at a time
+ m_logicHierarchicalGameObjects.clear();
+ m_map_gameobject_to_replica.clear();
+ m_ueberExecutionPriority++;
+ // for groups will do something special:
+ // we will force the creation of objects to those in the group only
+ // Again, this is match what Blender is doing (it doesn't care of parent relationship)
+ m_groupGameObjects.clear();
+
+ group = blgroupobj->dup_group;
+ for(go=(GroupObject*)group->gobject.first; go; go=(GroupObject*)go->next)
+ {
+ Object* blenderobj = go->ob;
+ if (blgroupobj == blenderobj)
+ // this check is also in group_duplilist()
+ continue;
+
+ gameobj = (KX_GameObject*)m_logicmgr->FindGameObjByBlendObj(blenderobj);
+ if (gameobj == NULL)
+ {
+ // this object has not been converted!!!
+ // Should not happen as dupli group are created automatically
+ continue;
+ }
+
+ gameobj->SetBlenderGroupObject(blgroupobj);
+
+ if ((blenderobj->lay & group->layer)==0)
+ {
+ // object is not visible in the 3D view, will not be instantiated
+ continue;
+ }
+ m_groupGameObjects.insert(gameobj);
+ }
+
+ set<CValue*>::iterator oit;
+ for (oit=m_groupGameObjects.begin(); oit != m_groupGameObjects.end(); oit++)
+ {
+ gameobj = (KX_GameObject*)(*oit);
+
+ KX_GameObject *parent = gameobj->GetParent();
+ if (parent != NULL)
+ {
+ parent->Release(); // GetParent() increased the refcount
+
+ // this object is not a top parent. Either it is the child of another
+ // object in the group and it will be added automatically when the parent
+ // is added. Or it is the child of an object outside the group and the group
+ // is inconsistent, skip it anyway
+ continue;
+ }
+ replica = (KX_GameObject*) AddNodeReplicaObject(NULL,gameobj);
+ // add to 'rootparent' list (this is the list of top hierarchy objects, updated each frame)
+ m_parentlist->Add(replica->AddRef());
+
+ // recurse replication into children nodes
+ NodeList& children = gameobj->GetSGNode()->GetSGChildren();
+
+ replica->GetSGNode()->ClearSGChildren();
+ for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit)
+ {
+ SG_Node* orgnode = (*childit);
+ SG_Node* childreplicanode = orgnode->GetSGReplica();
+ if (childreplicanode)
+ replica->GetSGNode()->AddChild(childreplicanode);
+ }
+ // don't replicate logic now: we assume that the objects in the group can have
+ // logic relationship, even outside parent relationship
+ // In order to match 3D view, the position of groupobj is used as a
+ // transformation matrix instead of the new position. This means that
+ // the group reference point is 0,0,0
+
+ // get the rootnode's scale
+ MT_Vector3 newscale = groupobj->NodeGetWorldScaling();
+ // set the replica's relative scale with the rootnode's scale
+ replica->NodeSetRelativeScale(newscale);
+
+ MT_Matrix3x3 newori = groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldOrientation();
+ replica->NodeSetLocalOrientation(newori);
+
+ MT_Point3 newpos = groupobj->NodeGetWorldPosition() +
+ newscale*(groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldPosition());
+ replica->NodeSetLocalPosition(newpos);
+
+ replica->GetSGNode()->UpdateWorldData(0);
+ replica->GetSGNode()->SetBBox(gameobj->GetSGNode()->BBox());
+ replica->GetSGNode()->SetRadius(gameobj->GetSGNode()->Radius());
+ // done with replica
+ replica->Release();
+ }
+
+ // the logic must be replicated first because we need
+ // the new logic bricks before relinking
+ vector<KX_GameObject*>::iterator git;
+ for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
+ {
+ (*git)->ReParentLogic();
+ }
+
+ // relink any pointers as necessary, sort of a temporary solution
+ for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
+ {
+ // this will also relink the actuator to objects within the hierarchy
+ (*git)->Relink(&m_map_gameobject_to_replica);
+ // add the object in the layer of the parent
+ (*git)->SetLayer(groupobj->GetLayer());
+ }
+
+ // replicate crosslinks etc. between logic bricks
+ for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
+ {
+ ReplicateLogic((*git));
+ }
+
+ // now look if object in the hierarchy have dupli group and recurse
+ for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
+ {
+ if ((*git) != groupobj && (*git)->IsDupliGroup())
+ // can't instantiate group immediately as it destroys m_logicHierarchicalGameObjects
+ duplilist.push_back((*git));
+ }
+
+ for (git = duplilist.begin(); !(git == duplilist.end()); ++git)
+ {
+ DupliGroupRecurse((*git), level+1);
+ }
+}
SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
@@ -555,6 +755,7 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
m_logicHierarchicalGameObjects.clear();
m_map_gameobject_to_replica.clear();
+ m_groupGameObjects.clear();
// todo: place a timebomb in the object, for temporarily objects :)
// lifespan of zero means 'this object lives forever'
@@ -571,7 +772,9 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
// add a timebomb to this object
// for now, convert between so called frames and realtime
m_tempObjectList->Add(replica->AddRef());
- replica->SetProperty("::timebomb",new CFloatValue(lifespan*0.02));
+ CValue *fval = new CFloatValue(lifespan*0.02);
+ replica->SetProperty("::timebomb",fval);
+ fval->Release();
}
// add to 'rootparent' list (this is the list of top hierarchy objects, updated each frame)
@@ -586,22 +789,26 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
{
SG_Node* orgnode = (*childit);
SG_Node* childreplicanode = orgnode->GetSGReplica();
- replica->GetSGNode()->AddChild(childreplicanode);
+ if (childreplicanode)
+ replica->GetSGNode()->AddChild(childreplicanode);
}
- // relink any pointers as necessary, sort of a temporary solution
+ // now replicate logic
vector<KX_GameObject*>::iterator git;
for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
{
- (*git)->Relink(&m_map_gameobject_to_replica);
+ (*git)->ReParentLogic();
}
-
- // now replicate logic
+
+ // relink any pointers as necessary, sort of a temporary solution
for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
{
- (*git)->ReParentLogic();
+ // this will also relink the actuators in the hierarchy
+ (*git)->Relink(&m_map_gameobject_to_replica);
+ // add the object in the layer of the parent
+ (*git)->SetLayer(parentobj->GetLayer());
}
-
+
// replicate crosslinks etc. between logic bricks
for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
{
@@ -620,21 +827,24 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
// set the replica's relative scale with the rootnode's scale
replica->NodeSetRelativeScale(newscale);
- if (replica->GetPhysicsController())
- {
- replica->GetPhysicsController()->setPosition(newpos);
- replica->GetPhysicsController()->setOrientation(newori.getRotation());
- replica->GetPhysicsController()->setScaling(newscale);
- }
-
- // here we want to set the relative scale: the rootnode's scale will override all other
- // scalings, so lets better prepare for it
-
-
replica->GetSGNode()->UpdateWorldData(0);
replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox());
replica->GetSGNode()->SetRadius(originalobj->GetSGNode()->Radius());
-
+ // check if there are objects with dupligroup in the hierarchy
+ vector<KX_GameObject*> duplilist;
+ for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
+ {
+ if ((*git)->IsDupliGroup())
+ {
+ // separate list as m_logicHierarchicalGameObjects is also used by DupliGroupRecurse()
+ duplilist.push_back(*git);
+ }
+ }
+ for (git = duplilist.begin();!(git==duplilist.end());++git)
+ {
+ DupliGroupRecurse(*git, 0);
+ }
+ // don't release replica here because we are returning it, not done with it...
return replica;
}
@@ -654,7 +864,8 @@ void KX_Scene::RemoveObject(class CValue* gameobj)
// recursively destruct
node->Destruct();
}
- newobj->SetSGNode(0);
+ //no need to do that: the object is destroyed and memory released
+ //newobj->SetSGNode(0);
}
void KX_Scene::DelayedReleaseObject(CValue* gameobj)
@@ -674,10 +885,17 @@ void KX_Scene::DelayedRemoveObject(class CValue* gameobj)
-void KX_Scene::NewRemoveObject(class CValue* gameobj)
+int KX_Scene::NewRemoveObject(class CValue* gameobj)
{
+ int ret;
KX_GameObject* newobj = (KX_GameObject*) gameobj;
+ // keep the blender->game object association up to date
+ // note that all the replicas of an object will have the same
+ // blender object, that's why we need to check the game object
+ // as only the deletion of the original object must be recorded
+ m_logicmgr->UnregisterGameObj(newobj->GetBlenderObject(), gameobj);
+
//todo: look at this
//GetPhysicsEnvironment()->RemovePhysicsController(gameobj->getPhysicsController());
@@ -694,8 +912,7 @@ void KX_Scene::NewRemoveObject(class CValue* gameobj)
for (SCA_ControllerList::iterator itc = controllers.begin();
!(itc==controllers.end());itc++)
{
- (*itc)->UnlinkAllSensors();
- (*itc)->UnlinkAllActuators();
+ m_logicmgr->RemoveController(*itc);
}
SCA_ActuatorList& actuators = newobj->GetActuators();
@@ -704,6 +921,7 @@ void KX_Scene::NewRemoveObject(class CValue* gameobj)
{
m_logicmgr->RemoveDestroyedActuator(*ita);
}
+ // the sensors/controllers/actuators must also be released, this is done in ~SCA_IObject
// now remove the timer properties from the time manager
int numprops = newobj->GetPropertyCount();
@@ -718,113 +936,138 @@ void KX_Scene::NewRemoveObject(class CValue* gameobj)
}
newobj->RemoveMeshes();
+ ret = 1;
+ if (m_lightlist->RemoveValue(newobj)) // TODO - use newobj->IsLight() test when its merged in from apricot. - Campbell
+ ret = newobj->Release();
if (m_objectlist->RemoveValue(newobj))
- newobj->Release();
+ ret = newobj->Release();
if (m_tempObjectList->RemoveValue(newobj))
- newobj->Release();
+ ret = newobj->Release();
if (m_parentlist->RemoveValue(newobj))
- newobj->Release();
+ ret = newobj->Release();
+ if (m_inactivelist->RemoveValue(newobj))
+ ret = newobj->Release();
if (m_euthanasyobjects->RemoveValue(newobj))
- newobj->Release();
+ ret = newobj->Release();
if (newobj == m_active_camera)
{
- m_active_camera->Release();
+ //no AddRef done on m_active_camera so no Release
+ //m_active_camera->Release();
m_active_camera = NULL;
}
+
+ // in case this is a camera
+ m_cameras.remove((KX_Camera*)newobj);
+
+ if (m_sceneConverter)
+ m_sceneConverter->UnregisterGameObject(newobj);
+ // return value will be 0 if the object is actually deleted (all reference gone)
+ return ret;
}
-void KX_Scene::ReplaceMesh(class CValue* gameobj,void* meshobj)
+void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj)
{
- KX_GameObject* newobj = static_cast<KX_GameObject*>(gameobj);
+ KX_GameObject* gameobj = static_cast<KX_GameObject*>(obj);
RAS_MeshObject* mesh = static_cast<RAS_MeshObject*>(meshobj);
- const STR_String origMeshName = newobj->GetMesh(0)->GetName();
-
- if( !newobj || !mesh )
+ if(!gameobj || !mesh)
{
std::cout << "warning: invalid object, mesh will not be replaced" << std::endl;
return;
}
- newobj->RemoveMeshes();
- newobj->AddMesh(mesh);
-
- bool isDeformer = (newobj->m_isDeformable && mesh->m_class == 1);
- if(isDeformer)
- {
- /* FindBlendObjByGameObj() can return 0...
- In the case of 0 here,
- the replicated object that is calling this function
- is some how not in the map. (which is strange because it's added)
- So we will search the map by the first mesh name
- to try to locate it there. If its still not found
- spit some message rather than crash
- */
- Object* blendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameObj(newobj));
- Object* oldblendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(mesh->GetName()));
+ gameobj->RemoveMeshes();
+ gameobj->AddMesh(mesh);
- bool parSkin = blendobj && blendobj->parent && blendobj->parent->type == OB_ARMATURE && blendobj->partype==PARSKEL;
- bool releaseParent = true;
- KX_GameObject* parentobj = newobj->GetParent();
-
-
- // lookup by mesh name if blendobj is 0
- if( !blendobj && parentobj )
+ if (gameobj->m_isDeformable)
+ {
+ BL_DeformableGameObject* newobj = static_cast<BL_DeformableGameObject*>( gameobj );
+
+ if (newobj->GetDeformer())
{
- blendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(origMeshName));
-
- // replace the mesh on the parent armature
- if( blendobj )
- parSkin = parentobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE;
-
- // can't do it
- else
- std::cout << "warning: child object for " << parentobj->GetName().ReadPtr()
- << " not found, and can't create!" << std::endl;
+ delete newobj->GetDeformer();
+ newobj->SetDeformer(NULL);
}
- if( blendobj && oldblendobj )
+ if (mesh->IsDeformed())
{
- isDeformer = (static_cast<Mesh*>(blendobj->data)->dvert != 0);
- BL_DeformableGameObject* deformIter =0;
-
- // armature parent
- if( parSkin && isDeformer )
+ // we must create a new deformer but which one?
+ KX_GameObject* parentobj = newobj->GetParent();
+ // this always return the original game object (also for replicate)
+ Object* blendobj = newobj->GetBlenderObject();
+ // object that owns the new mesh
+ Object* oldblendobj = static_cast<struct Object*>(m_logicmgr->FindBlendObjByGameMeshName(mesh->GetName()));
+ Mesh* blendmesh = mesh->GetMesh();
+
+ bool bHasShapeKey = blendmesh->key != NULL && blendmesh->key->type==KEY_RELATIVE;
+ bool bHasDvert = blendmesh->dvert != NULL;
+ bool bHasArmature =
+ parentobj && // current parent is armature
+ parentobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE &&
+ oldblendobj && // needed for mesh deform
+ blendobj->parent && // original object had armature (not sure this test is needed)
+ blendobj->parent->type == OB_ARMATURE &&
+ blendobj->partype==PARSKEL &&
+ blendmesh->dvert!=NULL; // mesh has vertex group
+ bool releaseParent = true;
+
+ if (bHasShapeKey)
+ {
+ BL_ShapeDeformer* shapeDeformer;
+ if (bHasArmature)
+ {
+ shapeDeformer = new BL_ShapeDeformer(
+ newobj,
+ oldblendobj, blendobj,
+ static_cast<BL_SkinMeshObject*>(mesh),
+ true,
+ static_cast<BL_ArmatureObject*>( parentobj )
+ );
+ releaseParent= false;
+ shapeDeformer->LoadShapeDrivers(blendobj->parent);
+ }
+ else
+ {
+ shapeDeformer = new BL_ShapeDeformer(
+ newobj,
+ oldblendobj, blendobj,
+ static_cast<BL_SkinMeshObject*>(mesh),
+ false,
+ NULL
+ );
+ }
+ newobj->SetDeformer( shapeDeformer);
+ }
+ else if (bHasArmature)
{
- deformIter = static_cast<BL_DeformableGameObject*>( newobj );
- delete deformIter->m_pDeformer;
-
BL_SkinDeformer* skinDeformer = new BL_SkinDeformer(
+ newobj,
oldblendobj, blendobj,
static_cast<BL_SkinMeshObject*>(mesh),
true,
static_cast<BL_ArmatureObject*>( parentobj )
);
releaseParent= false;
- deformIter->m_pDeformer = skinDeformer;
+ newobj->SetDeformer(skinDeformer);
}
-
- // normal deformer
- if( !parSkin && isDeformer)
+ else if (bHasDvert)
{
- deformIter = static_cast<BL_DeformableGameObject*>( newobj );
- delete deformIter->m_pDeformer;
-
BL_MeshDeformer* meshdeformer = new BL_MeshDeformer(
- oldblendobj, static_cast<BL_SkinMeshObject*>(mesh)
+ newobj, oldblendobj, static_cast<BL_SkinMeshObject*>(mesh)
);
-
- deformIter->m_pDeformer = meshdeformer;
+ newobj->SetDeformer(meshdeformer);
}
+
+ // release parent reference if its not being used
+ if( releaseParent && parentobj)
+ parentobj->Release();
}
- // release parent reference if its not being used
- if( releaseParent && parentobj)
- parentobj->Release();
}
- newobj->Bucketize();
+
+ gameobj->AddMeshUser();
}
@@ -847,7 +1090,7 @@ MT_CmMatrix4x4& KX_Scene::GetProjectionMatrix()
KX_Camera* KX_Scene::FindCamera(KX_Camera* cam)
{
- set<KX_Camera*>::iterator it = m_cameras.begin();
+ list<KX_Camera*>::iterator it = m_cameras.begin();
while ( (it != m_cameras.end())
&& ((*it) != cam) ) {
@@ -860,7 +1103,7 @@ KX_Camera* KX_Scene::FindCamera(KX_Camera* cam)
KX_Camera* KX_Scene::FindCamera(STR_String& name)
{
- set<KX_Camera*>::iterator it = m_cameras.begin();
+ list<KX_Camera*>::iterator it = m_cameras.begin();
while ( (it != m_cameras.end())
&& ((*it)->GetName() != name) ) {
@@ -872,9 +1115,11 @@ KX_Camera* KX_Scene::FindCamera(STR_String& name)
void KX_Scene::AddCamera(KX_Camera* cam)
{
- m_cameras.insert(cam);
+ if (!FindCamera(cam))
+ m_cameras.push_back(cam);
}
+
KX_Camera* KX_Scene::GetActiveCamera()
{
// NULL if not defined
@@ -893,6 +1138,17 @@ void KX_Scene::SetActiveCamera(KX_Camera* cam)
m_active_camera = cam;
}
+void KX_Scene::SetCameraOnTop(KX_Camera* cam)
+{
+ if (!FindCamera(cam)){
+ // adding is always done at the back, so that's all that needs to be done
+ AddCamera(cam);
+ if (cam) std::cout << "Added cam " << cam->GetName() << std::endl;
+ } else {
+ m_cameras.remove(cam);
+ m_cameras.push_back(cam);
+ }
+}
void KX_Scene::UpdateMeshTransformations()
@@ -906,12 +1162,13 @@ void KX_Scene::UpdateMeshTransformations()
}
}
-void KX_Scene::MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera* cam)
+void KX_Scene::MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera* cam, int layer)
{
int intersect = KX_Camera::INTERSECT;
KX_GameObject *gameobj = node->Client()?(KX_GameObject*) node->Client()->GetSGClientObject():NULL;
- bool dotest = (gameobj && gameobj->GetVisible()) || node->Left() || node->Right();
-
+ bool visible = (gameobj && gameobj->GetVisible() && (!layer || (gameobj->GetLayer() & layer)));
+ bool dotest = visible || node->Left() || node->Right();
+
/* If the camera is inside the box, assume intersect. */
if (dotest && !node->inside( cam->NodeGetWorldPosition()))
{
@@ -935,19 +1192,19 @@ void KX_Scene::MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera* cam
break;
case KX_Camera::INTERSECT:
if (gameobj)
- MarkVisible(rasty, gameobj,cam);
+ MarkVisible(rasty, gameobj, cam, layer);
if (node->Left())
- MarkVisible(node->Left(), rasty,cam);
+ MarkVisible(node->Left(), rasty, cam, layer);
if (node->Right())
- MarkVisible(node->Right(), rasty,cam);
+ MarkVisible(node->Right(), rasty, cam, layer);
break;
case KX_Camera::INSIDE:
- MarkSubTreeVisible(node, rasty, true,cam);
+ MarkSubTreeVisible(node, rasty, true, cam, layer);
break;
}
}
-void KX_Scene::MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible,KX_Camera* cam)
+void KX_Scene::MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible, KX_Camera* cam, int layer)
{
if (node->Client())
{
@@ -957,29 +1214,35 @@ void KX_Scene::MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool vi
if (visible)
{
int nummeshes = gameobj->GetMeshCount();
- MT_Transform t( cam->GetWorldToCamera() * gameobj->GetSGNode()->GetWorldTransform());
-
+ // this adds the vertices to the display list
for (int m=0;m<nummeshes;m++)
- {
- // this adds the vertices to the display list
- (gameobj->GetMesh(m))->SchedulePolygons(t, rasty->GetDrawingMode());
- }
+ (gameobj->GetMesh(m))->SchedulePolygons(rasty->GetDrawingMode());
}
- gameobj->MarkVisible(visible);
+
+ gameobj->SetCulled(!visible);
+ gameobj->UpdateBuckets(false);
}
}
if (node->Left())
- MarkSubTreeVisible(node->Left(), rasty, visible,cam);
+ MarkSubTreeVisible(node->Left(), rasty, visible, cam, layer);
if (node->Right())
- MarkSubTreeVisible(node->Right(), rasty, visible,cam);
+ MarkSubTreeVisible(node->Right(), rasty, visible, cam, layer);
}
-void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Camera* cam)
+void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Camera* cam,int layer)
{
// User (Python/Actuator) has forced object invisible...
- if (!gameobj->GetVisible())
+ if (!gameobj->GetSGNode() || !gameobj->GetVisible())
+ return;
+
+ // Shadow lamp layers
+ if(layer && !(gameobj->GetLayer() & layer)) {
+ gameobj->SetCulled(true);
+ gameobj->UpdateBuckets(false);
return;
+ }
+
// If Frustum culling is off, the object is always visible.
bool vis = !cam->GetFrustumCulling();
@@ -1014,35 +1277,36 @@ void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Cam
if (vis)
{
int nummeshes = gameobj->GetMeshCount();
- MT_Transform t(cam->GetWorldToCamera() * gameobj->GetSGNode()->GetWorldTransform());
for (int m=0;m<nummeshes;m++)
{
// this adds the vertices to the display list
- (gameobj->GetMesh(m))->SchedulePolygons(t, rasty->GetDrawingMode());
+ (gameobj->GetMesh(m))->SchedulePolygons(rasty->GetDrawingMode());
}
// Visibility/ non-visibility are marked
// elsewhere now.
- gameobj->MarkVisible();
+ gameobj->SetCulled(false);
+ gameobj->UpdateBuckets(false);
} else {
- gameobj->MarkVisible(false);
+ gameobj->SetCulled(true);
+ gameobj->UpdateBuckets(false);
}
}
-void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam)
+void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int layer)
{
// FIXME: When tree is operational
#if 1
// do this incrementally in the future
for (int i = 0; i < m_objectlist->GetCount(); i++)
{
- MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam);
+ MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam, layer);
}
#else
if (cam->GetFrustumCulling())
- MarkVisible(m_objecttree, rasty, cam);
+ MarkVisible(m_objecttree, rasty, cam, layer);
else
- MarkSubTreeVisible(m_objecttree, rasty, true, cam);
+ MarkSubTreeVisible(m_objecttree, rasty, true, cam, layer);
#endif
}
@@ -1096,6 +1360,8 @@ void KX_Scene::LogicEndFrame()
for (i = numobj - 1; i >= 0; i--)
{
KX_GameObject* gameobj = (KX_GameObject*)m_euthanasyobjects->GetValue(i);
+ // KX_Scene::RemoveObject will also remove the object from this list
+ // that's why we start from the end
this->RemoveObject(gameobj);
}
@@ -1103,11 +1369,11 @@ void KX_Scene::LogicEndFrame()
for (i = numobj-1;i>=0;i--)
{
KX_GameObject* gameobj = (KX_GameObject*)m_delayReleaseObjects->GetValue(i);
- m_delayReleaseObjects->RemoveValue(gameobj);
-
+ // This list is not for object removal, but just object release
+ gameobj->Release();
}
-
-
+ // empty the list as we have removed all references
+ m_delayReleaseObjects->Resize(0);
}
@@ -1128,9 +1394,9 @@ void KX_Scene::UpdateParents(double curtime)
-RAS_MaterialBucket* KX_Scene::FindBucket(class RAS_IPolyMaterial* polymat)
+RAS_MaterialBucket* KX_Scene::FindBucket(class RAS_IPolyMaterial* polymat, bool &bucketCreated)
{
- return m_bucketmanager->RAS_BucketManagerFindBucket(polymat);
+ return m_bucketmanager->FindBucket(polymat, bucketCreated);
}
@@ -1140,10 +1406,9 @@ void KX_Scene::RenderBuckets(const MT_Transform & cameratransform,
class RAS_IRenderTools* rendertools)
{
m_bucketmanager->Renderbuckets(cameratransform,rasty,rendertools);
+ KX_BlenderMaterial::EndFrame();
}
-
-
void KX_Scene::UpdateObjectActivity(void)
{
if (m_activity_culling) {
@@ -1212,6 +1477,11 @@ void KX_Scene::SetNodeTree(SG_Tree* root)
m_objecttree = root;
}
+void KX_Scene::SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter)
+{
+ m_sceneConverter = sceneConverter;
+}
+
void KX_Scene::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* physEnv)
{
m_physicsEnvironment = physEnv;
diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h
index dbe04a18e0f..5f7e1167e27 100644
--- a/source/gameengine/Ketsji/KX_Scene.h
+++ b/source/gameengine/Ketsji/KX_Scene.h
@@ -36,6 +36,7 @@
#include <vector>
#include <set>
+#include <list>
#include "GEN_Map.h"
#include "GEN_HashedPtr.h"
@@ -53,6 +54,7 @@
*/
struct SM_MaterialProps;
struct SM_ShapeProps;
+struct Scene;
class GEN_HashedPtr;
class CListValue;
@@ -81,6 +83,8 @@ class RAS_IPolyMaterial;
class RAS_IRasterizer;
class RAS_IRenderTools;
class SCA_JoystickManager;
+class btCollisionShape;
+class KX_BlenderSceneConverter;
/**
* The KX_Scene holds all data for an independent scene. It relates
* KX_Objects to the specific objects in the modules.
@@ -107,6 +111,7 @@ protected:
CListValue* m_objectlist;
CListValue* m_parentlist; // all 'root' parents
CListValue* m_lightlist;
+ CListValue* m_inactivelist; // all objects that are not in the active layer
/**
* The tree of objects in the scene.
@@ -116,8 +121,7 @@ protected:
/**
* The set of cameras for this scene
*/
- set<class KX_Camera*> m_cameras;
-
+ list<class KX_Camera*> m_cameras;
/**
* Various SCA managers used by the scene
*/
@@ -126,10 +130,12 @@ protected:
SCA_MouseManager* m_mousemgr;
SCA_TimeEventManager* m_timemgr;
+ // Scene converter where many scene entities are registered
+ // Used to deregister objects that are deleted
+ class KX_BlenderSceneConverter* m_sceneConverter;
/**
* physics engine abstraction
*/
-
//e_PhysicsEngine m_physicsEngine; //who needs this ?
class PHY_IPhysicsEnvironment* m_physicsEnvironment;
@@ -206,6 +212,16 @@ protected:
*/
std::vector<KX_GameObject*> m_logicHierarchicalGameObjects;
+ /**
+ * This temporary variable will contain the list of
+ * object that can be added during group instantiation.
+ * objects outside this list will not be added (can
+ * happen with children that are outside the group).
+ * Used in AddReplicaObject. If the list is empty, it
+ * means don't care.
+ */
+ std::set<CValue*> m_groupGameObjects;
+
/**
* Pointer to system variable passed in in constructor
* only used in constructor so we do not need to keep it
@@ -250,9 +266,9 @@ protected:
/**
* Visibility testing functions.
*/
- void MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera*cam);
- void MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible, KX_Camera*cam);
- void MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj, KX_Camera*cam);
+ void MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera*cam,int layer=0);
+ void MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible, KX_Camera*cam,int layer=0);
+ void MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj, KX_Camera*cam, int layer=0);
double m_suspendedtime;
double m_suspendeddelta;
@@ -262,18 +278,21 @@ protected:
*/
PyObject* m_attrlist;
+ struct Scene* m_blenderScene;
+
public:
KX_Scene(class SCA_IInputDevice* keyboarddevice,
class SCA_IInputDevice* mousedevice,
class NG_NetworkDeviceInterface* ndi,
class SND_IAudioDevice* adi,
- const STR_String& scenename );
+ const STR_String& scenename,
+ struct Scene* scene);
virtual
~KX_Scene();
RAS_BucketManager* GetBucketManager();
- RAS_MaterialBucket* FindBucket(RAS_IPolyMaterial* polymat);
+ RAS_MaterialBucket* FindBucket(RAS_IPolyMaterial* polymat, bool &bucketCreated);
void RenderBuckets(const MT_Transform& cameratransform,
RAS_IRasterizer* rasty,
RAS_IRenderTools* rendertools);
@@ -281,6 +300,12 @@ public:
* Update all transforms according to the scenegraph.
*/
void UpdateParents(double curtime);
+ void DupliGroupRecurse(CValue* gameobj, int level);
+ bool IsObjectInGroup(CValue* gameobj)
+ {
+ return (m_groupGameObjects.empty() ||
+ m_groupGameObjects.find(gameobj) != m_groupGameObjects.end());
+ }
SCA_IObject* AddReplicaObject(CValue* gameobj,
CValue* locationobj,
int lifespan=0);
@@ -293,7 +318,7 @@ public:
void DelayedReleaseObject(CValue* gameobj);
- void NewRemoveObject(CValue* gameobj);
+ int NewRemoveObject(CValue* gameobj);
void ReplaceMesh(CValue* gameobj,
void* meshobj);
/**
@@ -312,6 +337,10 @@ public:
);
CListValue*
+ GetInactiveList(
+ );
+
+ CListValue*
GetRootParentList(
);
@@ -327,7 +356,7 @@ public:
GetTimeEventManager(
);
- set<class KX_Camera*>*
+ list<class KX_Camera*>*
GetCameras(
);
@@ -365,6 +394,15 @@ public:
class KX_Camera*
);
+ /**
+ * Move this camera to the end of the list so that it is rendered last.
+ * If the camera is not on the list, it will be added
+ */
+ void
+ SetCameraOnTop(
+ class KX_Camera*
+ );
+
/** Return the viewmatrix as used by the last frame. */
MT_CmMatrix4x4&
GetViewMatrix(
@@ -459,7 +497,7 @@ public:
void SetNetworkScene(NG_NetworkScene *newScene);
void SetWorldInfo(class KX_WorldInfo* wi);
KX_WorldInfo* GetWorldInfo();
- void CalculateVisibleMeshes(RAS_IRasterizer* rasty, KX_Camera *cam);
+ void CalculateVisibleMeshes(RAS_IRasterizer* rasty, KX_Camera *cam, int layer=0);
void UpdateMeshTransformations();
KX_Camera* GetpCamera();
SND_Scene* GetSoundScene();
@@ -493,6 +531,8 @@ public:
bool IsClearingZBuffer();
void EnableZBufferClearing(bool isclearingZbuffer);
+ void SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter);
+
class PHY_IPhysicsEnvironment* GetPhysicsEnvironment()
{
return m_physicsEnvironment;
@@ -546,6 +586,10 @@ public:
* was running and not suspended) and the "curtime"
*/
double getSuspendedDelta();
+ /**
+ * Returns the Blender scene this was made from
+ */
+ struct Scene *GetBlenderScene() { return m_blenderScene; }
};
typedef std::vector<KX_Scene*> KX_SceneList;
diff --git a/source/gameengine/Ketsji/KX_SceneActuator.cpp b/source/gameengine/Ketsji/KX_SceneActuator.cpp
index ce357cd708a..35484699b17 100644
--- a/source/gameengine/Ketsji/KX_SceneActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SceneActuator.cpp
@@ -58,13 +58,16 @@ KX_SceneActuator::KX_SceneActuator(SCA_IObject *gameobj,
m_KetsjiEngine=ketsjiEngine;
m_camera = camera;
m_nextSceneName = nextSceneName;
+ if (m_camera)
+ m_camera->RegisterActuator(this);
} /* End of constructor */
KX_SceneActuator::~KX_SceneActuator()
{
- // there's nothing to be done here, really....
+ if (m_camera)
+ m_camera->UnregisterActuator(this);
} /* end of destructor */
@@ -79,6 +82,34 @@ CValue* KX_SceneActuator::GetReplica()
return replica;
}
+void KX_SceneActuator::ProcessReplica()
+{
+ if (m_camera)
+ m_camera->RegisterActuator(this);
+ SCA_IActuator::ProcessReplica();
+}
+
+bool KX_SceneActuator::UnlinkObject(SCA_IObject* clientobj)
+{
+ if (clientobj == (SCA_IObject*)m_camera)
+ {
+ // this object is being deleted, we cannot continue to track it.
+ m_camera = NULL;
+ return true;
+ }
+ return false;
+}
+
+void KX_SceneActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
+{
+ void **h_obj = (*obj_map)[m_camera];
+ if (h_obj) {
+ if (m_camera)
+ m_camera->UnregisterActuator(this);
+ m_camera = (KX_Camera*)(*h_obj);
+ m_camera->RegisterActuator(this);
+ }
+}
bool KX_SceneActuator::Update()
@@ -102,6 +133,15 @@ bool KX_SceneActuator::Update()
{
m_scene->SetActiveCamera(m_camera);
}
+ else
+ {
+ // if no camera is set and the parent object is a camera, use it as the camera
+ SCA_IObject* parent = GetParent();
+ if (parent->isA(&KX_Camera::Type))
+ {
+ m_scene->SetActiveCamera((KX_Camera*)parent);
+ }
+ }
break;
default:
break;
@@ -219,12 +259,12 @@ PyParentObject KX_SceneActuator::Parents[] =
PyMethodDef KX_SceneActuator::Methods[] =
{
- {"setUseRestart", (PyCFunction) KX_SceneActuator::sPySetUseRestart, METH_VARARGS, SetUseRestart_doc},
- {"setScene", (PyCFunction) KX_SceneActuator::sPySetScene, METH_VARARGS, SetScene_doc},
- {"setCamera", (PyCFunction) KX_SceneActuator::sPySetCamera, METH_VARARGS, SetCamera_doc},
- {"getUseRestart", (PyCFunction) KX_SceneActuator::sPyGetUseRestart, METH_VARARGS, GetUseRestart_doc},
- {"getScene", (PyCFunction) KX_SceneActuator::sPyGetScene, METH_VARARGS, GetScene_doc},
- {"getCamera", (PyCFunction) KX_SceneActuator::sPyGetCamera, METH_VARARGS, GetCamera_doc},
+ {"setUseRestart", (PyCFunction) KX_SceneActuator::sPySetUseRestart, METH_VARARGS, (PY_METHODCHAR)SetUseRestart_doc},
+ {"setScene", (PyCFunction) KX_SceneActuator::sPySetScene, METH_VARARGS, (PY_METHODCHAR)SetScene_doc},
+ {"setCamera", (PyCFunction) KX_SceneActuator::sPySetCamera, METH_VARARGS, (PY_METHODCHAR)SetCamera_doc},
+ {"getUseRestart", (PyCFunction) KX_SceneActuator::sPyGetUseRestart, METH_VARARGS, (PY_METHODCHAR)GetUseRestart_doc},
+ {"getScene", (PyCFunction) KX_SceneActuator::sPyGetScene, METH_VARARGS, (PY_METHODCHAR)GetScene_doc},
+ {"getCamera", (PyCFunction) KX_SceneActuator::sPyGetCamera, METH_VARARGS, (PY_METHODCHAR)GetCamera_doc},
{NULL,NULL} //Sentinel
};
@@ -238,7 +278,7 @@ PyObject* KX_SceneActuator::_getattr(const STR_String& attr)
/* 2. setUseRestart--------------------------------------------------------- */
-char KX_SceneActuator::SetUseRestart_doc[] =
+const char KX_SceneActuator::SetUseRestart_doc[] =
"setUseRestart(flag)\n"
"\t- flag: 0 or 1.\n"
"\tSet flag to 1 to restart the scene.\n" ;
@@ -261,7 +301,7 @@ PyObject* KX_SceneActuator::PySetUseRestart(PyObject* self,
/* 3. getUseRestart: */
-char KX_SceneActuator::GetUseRestart_doc[] =
+const char KX_SceneActuator::GetUseRestart_doc[] =
"getUseRestart()\n"
"\tReturn whether the scene will be restarted.\n" ;
PyObject* KX_SceneActuator::PyGetUseRestart(PyObject* self,
@@ -274,7 +314,7 @@ PyObject* KX_SceneActuator::PyGetUseRestart(PyObject* self,
/* 4. set scene------------------------------------------------------------- */
-char KX_SceneActuator::SetScene_doc[] =
+const char KX_SceneActuator::SetScene_doc[] =
"setScene(scene)\n"
"\t- scene: string\n"
"\tSet the name of scene the actuator will switch to.\n" ;
@@ -299,7 +339,7 @@ PyObject* KX_SceneActuator::PySetScene(PyObject* self,
/* 5. getScene: */
-char KX_SceneActuator::GetScene_doc[] =
+const char KX_SceneActuator::GetScene_doc[] =
"getScene()\n"
"\tReturn the name of the scene the actuator wants to switch to.\n" ;
PyObject* KX_SceneActuator::PyGetScene(PyObject* self,
@@ -312,7 +352,7 @@ PyObject* KX_SceneActuator::PyGetScene(PyObject* self,
/* 6. set camera------------------------------------------------------------ */
-char KX_SceneActuator::SetCamera_doc[] =
+const char KX_SceneActuator::SetCamera_doc[] =
"setCamera(camera)\n"
"\t- camera: string\n"
"\tSet the camera to switch to.\n" ;
@@ -323,7 +363,11 @@ PyObject* KX_SceneActuator::PySetCamera(PyObject* self,
PyObject *cam;
if (PyArg_ParseTuple(args, "O!", &KX_Camera::Type, &cam))
{
+ if (m_camera)
+ m_camera->UnregisterActuator(this);
m_camera = (KX_Camera*) cam;
+ if (m_camera)
+ m_camera->RegisterActuator(this);
Py_Return;
}
PyErr_Clear();
@@ -336,7 +380,13 @@ PyObject* KX_SceneActuator::PySetCamera(PyObject* self,
}
KX_Camera *camOb = FindCamera(camName);
- if (camOb) m_camera = camOb;
+ if (camOb)
+ {
+ if (m_camera)
+ m_camera->UnregisterActuator(this);
+ m_camera = camOb;
+ m_camera->RegisterActuator(this);
+ }
Py_Return;
}
@@ -344,7 +394,7 @@ PyObject* KX_SceneActuator::PySetCamera(PyObject* self,
/* 7. getCamera: */
-char KX_SceneActuator::GetCamera_doc[] =
+const char KX_SceneActuator::GetCamera_doc[] =
"getCamera()\n"
"\tReturn the name of the camera to switch to.\n" ;
PyObject* KX_SceneActuator::PyGetCamera(PyObject* self,
diff --git a/source/gameengine/Ketsji/KX_SceneActuator.h b/source/gameengine/Ketsji/KX_SceneActuator.h
index cfc79b93f8e..55aaf629d7c 100644
--- a/source/gameengine/Ketsji/KX_SceneActuator.h
+++ b/source/gameengine/Ketsji/KX_SceneActuator.h
@@ -82,6 +82,9 @@ class KX_SceneActuator : public SCA_IActuator
virtual ~KX_SceneActuator();
virtual CValue* GetReplica();
+ virtual void ProcessReplica();
+ virtual bool UnlinkObject(SCA_IObject* clientobj);
+ virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
virtual bool Update();
diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp
index 949156571a7..afa5af3bc04 100644
--- a/source/gameengine/Ketsji/KX_SoundActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp
@@ -69,11 +69,11 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj,
KX_SoundActuator::~KX_SoundActuator()
{
- //m_soundScene->RemoveObject(this->m_soundObject);
- //(this->m_soundObject)->DeleteWhenFinished();
- m_soundScene->RemoveActiveObject(m_soundObject);
-// m_soundScene->DeleteObjectWhenFinished(m_soundObject);
- m_soundScene->DeleteObject(m_soundObject);
+ if (m_soundObject)
+ {
+ m_soundScene->RemoveActiveObject(m_soundObject);
+ m_soundScene->DeleteObject(m_soundObject);
+ }
}
@@ -82,9 +82,12 @@ CValue* KX_SoundActuator::GetReplica()
{
KX_SoundActuator* replica = new KX_SoundActuator(*this);
replica->ProcessReplica();
- SND_SoundObject* soundobj = new SND_SoundObject(*m_soundObject);
- replica->setSoundObject(soundobj);
- m_soundScene->AddObject(soundobj);
+ if (m_soundObject)
+ {
+ SND_SoundObject* soundobj = new SND_SoundObject(*m_soundObject);
+ replica->setSoundObject(soundobj);
+ m_soundScene->AddObject(soundobj);
+ }
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
@@ -104,6 +107,12 @@ bool KX_SoundActuator::Update(double curtime, bool frame)
RemoveAllEvents();
+ if (!m_soundObject)
+ return false;
+
+ // actual audio device playing state
+ bool isplaying = (m_soundObject->GetPlaystate() != SND_STOPPED) ? true : false;
+
if (m_pino)
{
bNegativeEvent = true;
@@ -113,30 +122,40 @@ bool KX_SoundActuator::Update(double curtime, bool frame)
if (bNegativeEvent)
{
// here must be a check if it is still playing
- m_isplaying = false;
-
- switch (m_type)
+ if (m_isplaying && isplaying)
{
- case KX_SOUNDACT_PLAYSTOP:
- case KX_SOUNDACT_LOOPSTOP:
- case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP:
- {
- m_soundScene->RemoveActiveObject(m_soundObject);
- break;
- }
- case KX_SOUNDACT_PLAYEND:
+ switch (m_type)
{
- m_soundObject->SetPlaystate(SND_MUST_STOP_WHEN_FINISHED);
+ case KX_SOUNDACT_PLAYSTOP:
+ case KX_SOUNDACT_LOOPSTOP:
+ case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP:
+ {
+ m_soundScene->RemoveActiveObject(m_soundObject);
+ break;
+ }
+ case KX_SOUNDACT_PLAYEND:
+ {
+ m_soundObject->SetPlaystate(SND_MUST_STOP_WHEN_FINISHED);
+ break;
+ }
+ case KX_SOUNDACT_LOOPEND:
+ case KX_SOUNDACT_LOOPBIDIRECTIONAL:
+ {
+ m_soundObject->SetLoopMode(SND_LOOP_OFF);
+ m_soundObject->SetPlaystate(SND_MUST_STOP_WHEN_FINISHED);
+ break;
+ }
+ default:
+ // implement me !!
break;
}
- default:
- // implement me !!
- break;
}
+ // remember that we tried to stop the actuator
+ m_isplaying = false;
}
else
{
- if (m_soundObject && !m_isplaying)
+ if (!m_isplaying)
{
switch (m_type)
{
@@ -173,8 +192,10 @@ bool KX_SoundActuator::Update(double curtime, bool frame)
}
}
}
+ // verify that the sound is still playing
+ isplaying = (m_soundObject->GetPlaystate() != SND_STOPPED) ? true : false;
- if (m_isplaying)
+ if (isplaying)
{
m_soundObject->SetPosition(((KX_GameObject*)this->GetParent())->NodeGetWorldPosition());
m_soundObject->SetVelocity(((KX_GameObject*)this->GetParent())->GetLinearVelocity());
@@ -183,14 +204,15 @@ bool KX_SoundActuator::Update(double curtime, bool frame)
}
else
{
+ m_isplaying = false;
result = false;
}
-
+ /*
if (result && (m_soundObject->IsLifeSpanOver(curtime)) && ((m_type == KX_SOUNDACT_PLAYEND) || (m_type == KX_SOUNDACT_PLAYSTOP)))
{
m_pino = true;
}
-
+ */
return result;
}
@@ -287,11 +309,16 @@ PyObject* KX_SoundActuator::PySetFilename(PyObject* self, PyObject* args, PyObje
PyObject* KX_SoundActuator::PyGetFilename(PyObject* self, PyObject* args, PyObject* kwds)
{
+ if (!m_soundObject)
+ {
+ return PyString_FromString("");
+ }
STR_String objectname = m_soundObject->GetObjectName();
char* name = objectname.Ptr();
if (!name) {
- Py_Return; /* internal error */
+ PyErr_SetString(PyExc_RuntimeError, "Unable to get sound filename");
+ return NULL;
} else
return PyString_FromString(name);
}
@@ -300,7 +327,11 @@ PyObject* KX_SoundActuator::PyGetFilename(PyObject* self, PyObject* args, PyObje
PyObject* KX_SoundActuator::PyStartSound(PyObject* self, PyObject* args, PyObject* kwds)
{
- m_soundObject->StartSound();
+ if (m_soundObject)
+ // This has no effect if the actuator is not active.
+ // To start the sound you must activate the actuator.
+ // This function is to restart the sound.
+ m_soundObject->StartSound();
Py_Return;
}
@@ -308,7 +339,9 @@ PyObject* KX_SoundActuator::PyStartSound(PyObject* self, PyObject* args, PyObjec
PyObject* KX_SoundActuator::PyPauseSound(PyObject* self, PyObject* args, PyObject* kwds)
{
- m_soundObject->PauseSound();
+ if (m_soundObject)
+ // unfortunately, openal does not implement pause correctly, it is equivalent to a stop
+ m_soundObject->PauseSound();
Py_Return;
}
@@ -316,7 +349,8 @@ PyObject* KX_SoundActuator::PyPauseSound(PyObject* self, PyObject* args, PyObjec
PyObject* KX_SoundActuator::PyStopSound(PyObject* self, PyObject* args, PyObject* kwds)
{
- m_soundObject->StopSound();
+ if (m_soundObject)
+ m_soundObject->StopSound();
Py_Return;
}
@@ -328,7 +362,8 @@ PyObject* KX_SoundActuator::PySetGain(PyObject* self, PyObject* args, PyObject*
if (!PyArg_ParseTuple(args, "f", &gain))
return NULL;
- m_soundObject->SetGain(gain);
+ if (m_soundObject)
+ m_soundObject->SetGain(gain);
Py_Return;
}
@@ -337,7 +372,7 @@ PyObject* KX_SoundActuator::PySetGain(PyObject* self, PyObject* args, PyObject*
PyObject* KX_SoundActuator::PyGetGain(PyObject* self, PyObject* args, PyObject* kwds)
{
- float gain = m_soundObject->GetGain();
+ float gain = (m_soundObject) ? m_soundObject->GetGain() : 1.0f;
PyObject* result = PyFloat_FromDouble(gain);
return result;
@@ -351,7 +386,8 @@ PyObject* KX_SoundActuator::PySetPitch(PyObject* self, PyObject* args, PyObject*
if (!PyArg_ParseTuple(args, "f", &pitch))
return NULL;
- m_soundObject->SetPitch(pitch);
+ if (m_soundObject)
+ m_soundObject->SetPitch(pitch);
Py_Return;
}
@@ -360,7 +396,7 @@ PyObject* KX_SoundActuator::PySetPitch(PyObject* self, PyObject* args, PyObject*
PyObject* KX_SoundActuator::PyGetPitch(PyObject* self, PyObject* args, PyObject* kwds)
{
- float pitch = m_soundObject->GetPitch();
+ float pitch = (m_soundObject) ? m_soundObject->GetPitch() : 1.0;
PyObject* result = PyFloat_FromDouble(pitch);
return result;
@@ -374,7 +410,8 @@ PyObject* KX_SoundActuator::PySetRollOffFactor(PyObject* self, PyObject* args, P
if (!PyArg_ParseTuple(args, "f", &rollofffactor))
return NULL;
- m_soundObject->SetRollOffFactor(rollofffactor);
+ if (m_soundObject)
+ m_soundObject->SetRollOffFactor(rollofffactor);
Py_Return;
}
@@ -383,7 +420,7 @@ PyObject* KX_SoundActuator::PySetRollOffFactor(PyObject* self, PyObject* args, P
PyObject* KX_SoundActuator::PyGetRollOffFactor(PyObject* self, PyObject* args, PyObject* kwds)
{
- float rollofffactor = m_soundObject->GetRollOffFactor();
+ float rollofffactor = (m_soundObject) ? m_soundObject->GetRollOffFactor() : 1.0;
PyObject* result = PyFloat_FromDouble(rollofffactor);
return result;
@@ -397,7 +434,8 @@ PyObject* KX_SoundActuator::PySetLooping(PyObject* self, PyObject* args, PyObjec
if (!PyArg_ParseTuple(args, "i", &looping))
return NULL;
- m_soundObject->SetLoopMode(looping);
+ if (m_soundObject)
+ m_soundObject->SetLoopMode(looping);
Py_Return;
}
@@ -406,7 +444,7 @@ PyObject* KX_SoundActuator::PySetLooping(PyObject* self, PyObject* args, PyObjec
PyObject* KX_SoundActuator::PyGetLooping(PyObject* self, PyObject* args, PyObject* kwds)
{
- int looping = m_soundObject->GetLoopMode();
+ int looping = (m_soundObject) ? m_soundObject->GetLoopMode() : SND_LOOP_OFF;
PyObject* result = PyInt_FromLong(looping);
return result;
@@ -424,7 +462,8 @@ PyObject* KX_SoundActuator::PySetPosition(PyObject* self, PyObject* args, PyObje
if (!PyArg_ParseTuple(args, "fff", &pos[0], &pos[1], &pos[2]))
return NULL;
- m_soundObject->SetPosition(pos);
+ if (m_soundObject)
+ m_soundObject->SetPosition(pos);
Py_Return;
}
@@ -441,7 +480,8 @@ PyObject* KX_SoundActuator::PySetVelocity(PyObject* self, PyObject* args, PyObje
if (!PyArg_ParseTuple(args, "fff", &vel[0], &vel[1], &vel[2]))
return NULL;
- m_soundObject->SetVelocity(vel);
+ if (m_soundObject)
+ m_soundObject->SetVelocity(vel);
Py_Return;
}
@@ -464,7 +504,8 @@ PyObject* KX_SoundActuator::PySetOrientation(PyObject* self, PyObject* args, PyO
if (!PyArg_ParseTuple(args, "fffffffff", &ori[0][0], &ori[0][1], &ori[0][2], &ori[1][0], &ori[1][1], &ori[1][2], &ori[2][0], &ori[2][1], &ori[2][2]))
return NULL;
- m_soundObject->SetOrientation(ori);
+ if (m_soundObject)
+ m_soundObject->SetOrientation(ori);
Py_Return;
}
diff --git a/source/gameengine/Ketsji/KX_StateActuator.cpp b/source/gameengine/Ketsji/KX_StateActuator.cpp
new file mode 100644
index 00000000000..e360c4bac1f
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_StateActuator.cpp
@@ -0,0 +1,207 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * Actuator to toggle visibility/invisibility of objects
+ */
+
+#include "KX_StateActuator.h"
+#include "KX_GameObject.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+KX_StateActuator::KX_StateActuator(
+ SCA_IObject* gameobj,
+ int operation,
+ unsigned int mask,
+ PyTypeObject* T
+ )
+ : SCA_IActuator(gameobj,T),
+ m_operation(operation),
+ m_mask(mask)
+{
+ // intentionally empty
+}
+
+KX_StateActuator::~KX_StateActuator(
+ void
+ )
+{
+ // intentionally empty
+}
+
+CValue*
+KX_StateActuator::GetReplica(
+ void
+ )
+{
+ KX_StateActuator* replica = new KX_StateActuator(*this);
+ replica->ProcessReplica();
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+}
+
+bool
+KX_StateActuator::Update()
+{
+ bool bNegativeEvent = IsNegativeEvent();
+ unsigned int objMask;
+
+ RemoveAllEvents();
+ if (bNegativeEvent) return false;
+
+ KX_GameObject *obj = (KX_GameObject*) GetParent();
+
+ objMask = obj->GetState();
+ switch (m_operation)
+ {
+ case OP_CPY:
+ objMask = m_mask;
+ break;
+ case OP_SET:
+ objMask |= m_mask;
+ break;
+ case OP_CLR:
+ objMask &= ~m_mask;
+ break;
+ case OP_NEG:
+ objMask ^= m_mask;
+ break;
+ default:
+ // unsupported operation, no nothing
+ return false;
+ }
+ obj->SetState(objMask);
+ return false;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject
+KX_StateActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_StateActuator",
+ sizeof(KX_StateActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject
+KX_StateActuator::Parents[] = {
+ &KX_StateActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef
+KX_StateActuator::Methods[] = {
+ {"setOperation", (PyCFunction) KX_StateActuator::sPySetOperation,
+ METH_VARARGS, (PY_METHODCHAR)SetOperation_doc},
+ {"setMask", (PyCFunction) KX_StateActuator::sPySetMask,
+ METH_VARARGS, (PY_METHODCHAR)SetMask_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject*
+KX_StateActuator::_getattr(
+ const STR_String& attr
+ )
+{
+ _getattr_up(SCA_IActuator);
+};
+
+
+
+/* set operation ---------------------------------------------------------- */
+const char
+KX_StateActuator::SetOperation_doc[] =
+"setOperation(op)\n"
+"\t - op : bit operation (0=Copy, 1=Set, 2=Clear, 3=Negate)"
+"\tSet the type of bit operation to be applied on object state mask.\n"
+"\tUse setMask() to specify the bits that will be modified.\n";
+PyObject*
+
+KX_StateActuator::PySetOperation(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int oper;
+
+ if(!PyArg_ParseTuple(args, "i", &oper)) {
+ return NULL;
+ }
+
+ m_operation = oper;
+
+ Py_Return;
+}
+
+/* set mask ---------------------------------------------------------- */
+const char
+KX_StateActuator::SetMask_doc[] =
+"setMask(mask)\n"
+"\t - mask : bits that will be modified"
+"\tSet the value that defines the bits that will be modified by the operation.\n"
+"\tThe bits that are 1 in the value will be updated in the object state,\n"
+"\tthe bits that are 0 are will be left unmodified expect for the Copy operation\n"
+"\twhich copies the value to the object state.\n";
+PyObject*
+
+KX_StateActuator::PySetMask(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int mask;
+
+ if(!PyArg_ParseTuple(args, "i", &mask)) {
+ return NULL;
+ }
+
+ m_mask = mask;
+
+ Py_Return;
+}
+
+
diff --git a/source/gameengine/Ketsji/KX_StateActuator.h b/source/gameengine/Ketsji/KX_StateActuator.h
new file mode 100644
index 00000000000..8698e51b2c1
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_StateActuator.h
@@ -0,0 +1,83 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * Actuator to toggle visibility/invisibility of objects
+ */
+
+#ifndef __KX_STATEACTUATOR
+#define __KX_STATEACTUATOR
+
+#include "SCA_IActuator.h"
+
+class KX_StateActuator : public SCA_IActuator
+{
+ Py_Header;
+
+ /** Make visible? */
+ enum {
+ OP_CPY = 0,
+ OP_SET,
+ OP_CLR,
+ OP_NEG
+ };
+ int m_operation;
+ unsigned int m_mask;
+
+ public:
+
+ KX_StateActuator(
+ SCA_IObject* gameobj,
+ int operation,
+ unsigned int mask,
+ PyTypeObject* T=&Type
+ );
+
+ virtual
+ ~KX_StateActuator(
+ void
+ );
+
+ virtual CValue*
+ GetReplica(
+ void
+ );
+
+ virtual bool
+ Update();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+ //KX_PYMETHOD_DOC
+ KX_PYMETHOD_DOC(KX_StateActuator,SetOperation);
+ KX_PYMETHOD_DOC(KX_StateActuator,SetMask);
+};
+
+#endif
+
diff --git a/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp b/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp
index 6ea5461dbaa..c842ca1ee14 100644
--- a/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp
+++ b/source/gameengine/Ketsji/KX_SumoPhysicsController.cpp
@@ -101,7 +101,7 @@ void KX_SumoPhysicsController::SetSumoTransform(bool nondynaonly)
}
-void KX_SumoPhysicsController::SuspendDynamics()
+void KX_SumoPhysicsController::SuspendDynamics(bool)
{
SumoPhysicsController::SuspendDynamics();
}
@@ -170,8 +170,9 @@ void KX_SumoPhysicsController::setMargin(float collisionMargin)
}
-void KX_SumoPhysicsController::setOrientation(const MT_Quaternion& orn)
+void KX_SumoPhysicsController::setOrientation(const MT_Matrix3x3& rot)
{
+ MT_Quaternion orn = rot.getRotation();
SumoPhysicsController::setOrientation(
orn[0],orn[1],orn[2],orn[3]);
@@ -204,6 +205,11 @@ MT_Scalar KX_SumoPhysicsController::GetMass()
return SumoPhysicsController::getMass();
}
+MT_Scalar KX_SumoPhysicsController::GetRadius()
+{
+ return SumoPhysicsController::GetRadius();
+}
+
MT_Vector3 KX_SumoPhysicsController::getReactionForce()
{
float force[3];
diff --git a/source/gameengine/Ketsji/KX_SumoPhysicsController.h b/source/gameengine/Ketsji/KX_SumoPhysicsController.h
index 868465c8f10..abe48d99043 100644
--- a/source/gameengine/Ketsji/KX_SumoPhysicsController.h
+++ b/source/gameengine/Ketsji/KX_SumoPhysicsController.h
@@ -68,20 +68,23 @@ public:
void ApplyTorque(const MT_Vector3& torque,bool local);
void ApplyForce(const MT_Vector3& force,bool local);
MT_Vector3 GetLinearVelocity();
+ MT_Vector3 GetAngularVelocity() // to keep compiler happy
+ { return MT_Vector3(0.0,0.0,0.0); }
MT_Vector3 GetVelocity(const MT_Point3& pos);
void SetAngularVelocity(const MT_Vector3& ang_vel,bool local);
void SetLinearVelocity(const MT_Vector3& lin_vel,bool local);
void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ);
- void SuspendDynamics();
+ void SuspendDynamics(bool);
void RestoreDynamics();
virtual void getOrientation(MT_Quaternion& orn);
- virtual void setOrientation(const MT_Quaternion& orn);
+ virtual void setOrientation(const MT_Matrix3x3& orn);
virtual void setPosition(const MT_Point3& pos);
virtual void setScaling(const MT_Vector3& scaling);
virtual MT_Scalar GetMass();
+ virtual MT_Scalar GetRadius();
virtual MT_Vector3 getReactionForce();
virtual void setRigidBody(bool rigid);
diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp
index 2da899c62cb..48d4cf59a2b 100644
--- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp
+++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp
@@ -51,6 +51,7 @@ KX_TouchEventManager::KX_TouchEventManager(class SCA_LogicManager* logicmgr,
m_physEnv->addTouchCallback(PHY_OBJECT_RESPONSE, KX_TouchEventManager::newCollisionResponse, this);
m_physEnv->addTouchCallback(PHY_SENSOR_RESPONSE, KX_TouchEventManager::newCollisionResponse, this);
+ m_physEnv->addTouchCallback(PHY_BROADPH_RESPONSE, KX_TouchEventManager::newBroadphaseResponse, this);
}
@@ -76,19 +77,47 @@ bool KX_TouchEventManager::newCollisionResponse(void *client_data,
return false;
}
+bool KX_TouchEventManager::newBroadphaseResponse(void *client_data,
+ void *object1,
+ void *object2,
+ const PHY_CollData *coll_data)
+{
+ PHY_IPhysicsController* ctrl = static_cast<PHY_IPhysicsController*>(object1);
+ KX_ClientObjectInfo* info = (ctrl) ? static_cast<KX_ClientObjectInfo*>(ctrl->getNewClientInfo()) : NULL;
+ // This call back should only be called for controllers of Near and Radar sensor
+ if (info &&
+ info->m_sensors.size() == 1 &&
+ (info->m_type == KX_ClientObjectInfo::NEAR ||
+ info->m_type == KX_ClientObjectInfo::RADAR))
+ {
+ // only one sensor for this type of object
+ KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(*info->m_sensors.begin());
+ return touchsensor->BroadPhaseFilterCollision(object1,object2);
+ }
+ return true;
+}
+
void KX_TouchEventManager::RegisterSensor(SCA_ISensor* sensor)
{
KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(sensor);
- m_sensors.push_back(touchsensor);
+ if (m_sensors.insert(touchsensor).second)
+ // the sensor was effectively inserted, register it
+ touchsensor->RegisterSumo(this);
+}
- touchsensor->RegisterSumo(this);
+void KX_TouchEventManager::RemoveSensor(SCA_ISensor* sensor)
+{
+ KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(sensor);
+ if (m_sensors.erase(touchsensor))
+ // the sensor was effectively removed, unregister it
+ touchsensor->UnregisterSumo(this);
}
void KX_TouchEventManager::EndFrame()
{
- vector<SCA_ISensor*>::iterator it;
+ set<SCA_ISensor*>::iterator it;
for ( it = m_sensors.begin();
!(it==m_sensors.end());it++)
{
@@ -103,7 +132,7 @@ void KX_TouchEventManager::NextFrame()
{
if (m_sensors.size() > 0)
{
- vector<SCA_ISensor*>::iterator it;
+ set<SCA_ISensor*>::iterator it;
for (it = m_sensors.begin();!(it==m_sensors.end());++it)
static_cast<KX_TouchSensor*>(*it)->SynchronizeTransform();
@@ -116,14 +145,18 @@ void KX_TouchEventManager::NextFrame()
// KX_GameObject* gameOb1 = ctrl1->getClientInfo();
KX_ClientObjectInfo *client_info = static_cast<KX_ClientObjectInfo *>(ctrl1->getNewClientInfo());
-
list<SCA_ISensor*>::iterator sit;
- for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit)
- static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision((*cit).first, (*cit).second, NULL);
-
+ if (client_info) {
+ for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit) {
+ static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision((*cit).first, (*cit).second, NULL);
+ }
+ }
client_info = static_cast<KX_ClientObjectInfo *>((*cit).second->getNewClientInfo());
- for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit)
- static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision((*cit).second, (*cit).first, NULL);
+ if (client_info) {
+ for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit) {
+ static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision((*cit).second, (*cit).first, NULL);
+ }
+ }
}
m_newCollisions.clear();
@@ -132,20 +165,3 @@ void KX_TouchEventManager::NextFrame()
(*it)->Activate(m_logicmgr,NULL);
}
}
-
-
-
-void KX_TouchEventManager::RemoveSensor(class SCA_ISensor* sensor)
-{
- std::vector<SCA_ISensor*>::iterator i =
- std::find(m_sensors.begin(), m_sensors.end(), sensor);
- if (!(i == m_sensors.end()))
- {
- std::swap(*i, m_sensors.back());
- m_sensors.pop_back();
- }
-
- // remove the sensor forever :)
- SCA_EventManager::RemoveSensor(sensor);
-}
-
diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.h b/source/gameengine/Ketsji/KX_TouchEventManager.h
index d15128284da..cc77bccfc31 100644
--- a/source/gameengine/Ketsji/KX_TouchEventManager.h
+++ b/source/gameengine/Ketsji/KX_TouchEventManager.h
@@ -53,7 +53,12 @@ class KX_TouchEventManager : public SCA_EventManager
void *object1,
void *object2,
const PHY_CollData *coll_data);
-
+
+ static bool newBroadphaseResponse(void *client_data,
+ void *object1,
+ void *object2,
+ const PHY_CollData *coll_data);
+
virtual bool NewHandleCollision(void* obj1,void* obj2,
const PHY_CollData * coll_data);
@@ -66,8 +71,8 @@ public:
PHY_IPhysicsEnvironment* physEnv);
virtual void NextFrame();
virtual void EndFrame();
- virtual void RemoveSensor(class SCA_ISensor* sensor);
virtual void RegisterSensor(SCA_ISensor* sensor);
+ virtual void RemoveSensor(SCA_ISensor* sensor);
SCA_LogicManager* GetLogicManager() { return m_logicmgr;}
PHY_IPhysicsEnvironment *GetPhysicsEnvironment() { return m_physEnv; }
diff --git a/source/gameengine/Ketsji/KX_TouchSensor.cpp b/source/gameengine/Ketsji/KX_TouchSensor.cpp
index 62e400a7049..1935a0bde39 100644
--- a/source/gameengine/Ketsji/KX_TouchSensor.cpp
+++ b/source/gameengine/Ketsji/KX_TouchSensor.cpp
@@ -48,30 +48,30 @@
void KX_TouchSensor::SynchronizeTransform()
{
-
- if (m_physCtrl)
- {
-
- KX_GameObject* parent = ((KX_GameObject*)GetParent());
- MT_Vector3 pos = parent->NodeGetWorldPosition();
- MT_Quaternion orn = parent->NodeGetWorldOrientation().getRotation();
- m_physCtrl->setPosition(pos.x(),pos.y(),pos.z());
- m_physCtrl->setOrientation(orn.x(),orn.y(),orn.z(),orn.w());
- m_physCtrl->calcXform();
- }
-
+ // the touch sensor does not require any synchronization: it uses
+ // the same physical object which is already synchronized by Blender
}
void KX_TouchSensor::EndFrame() {
m_colliders->ReleaseAndRemoveAll();
+ m_hitObject = NULL;
m_bTriggered = false;
}
+void KX_TouchSensor::UnregisterToManager()
+{
+ // before unregistering the sensor, make sure we release all references
+ EndFrame();
+ m_eventmgr->RemoveSensor(this);
+}
+
bool KX_TouchSensor::Evaluate(CValue* event)
{
bool result = false;
+ bool reset = m_reset && m_level;
+ m_reset = false;
if (m_bTriggered != m_bLastTriggered)
{
m_bLastTriggered = m_bTriggered;
@@ -79,7 +79,9 @@ bool KX_TouchSensor::Evaluate(CValue* event)
m_hitObject = NULL;
result = true;
}
-
+ if (reset)
+ // force an event
+ result = true;
return result;
}
@@ -87,18 +89,14 @@ KX_TouchSensor::KX_TouchSensor(SCA_EventManager* eventmgr,KX_GameObject* gameobj
:SCA_ISensor(gameobj,eventmgr,T),
m_touchedpropname(touchedpropname),
m_bFindMaterial(bFindMaterial),
-m_eventmgr(eventmgr),
+m_eventmgr(eventmgr)
/*m_sumoObj(sumoObj),*/
-m_bCollision(false),
-m_bTriggered(false),
-m_bLastTriggered(false)
{
// KX_TouchEventManager* touchmgr = (KX_TouchEventManager*) eventmgr;
// m_resptable = touchmgr->GetResponseTable();
// m_solidHandle = m_sumoObj->getObjectHandle();
- m_hitObject = NULL;
m_colliders = new CListValue();
KX_ClientObjectInfo *client_info = gameobj->getClientInfo();
@@ -108,8 +106,17 @@ m_bLastTriggered(false)
m_physCtrl = dynamic_cast<PHY_IPhysicsController*>(gameobj->GetPhysicsController());
MT_assert( !gameobj->GetPhysicsController() || m_physCtrl );
+ Init();
}
+void KX_TouchSensor::Init()
+{
+ m_bCollision = false;
+ m_bTriggered = false;
+ m_bLastTriggered = (m_invert)?true:false;
+ m_hitObject = NULL;
+ m_reset = true;
+}
KX_TouchSensor::~KX_TouchSensor()
{
@@ -121,10 +128,7 @@ CValue* KX_TouchSensor::GetReplica()
{
KX_TouchSensor* replica = new KX_TouchSensor(*this);
replica->m_colliders = new CListValue();
- replica->m_bCollision = false;
- replica->m_bTriggered= false;
- replica->m_hitObject = NULL;
- replica->m_bLastTriggered = false;
+ replica->Init();
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
return replica;
@@ -157,6 +161,14 @@ void KX_TouchSensor::RegisterSumo(KX_TouchEventManager *touchman)
}
}
+void KX_TouchSensor::UnregisterSumo(KX_TouchEventManager* touchman)
+{
+ if (m_physCtrl)
+ {
+ touchman->GetPhysicsEnvironment()->removeCollisionCallback(m_physCtrl);
+ }
+}
+
bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_CollData* colldata)
{
// KX_TouchEventManager* toucheventmgr = (KX_TouchEventManager*)m_eventmgr;
@@ -172,7 +184,10 @@ bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_Coll
client_info->m_gameobject :
NULL);
- if (gameobj && (gameobj != parent) && client_info->isActor())
+ // add the same check as in SCA_ISensor::Activate(),
+ // we don't want to record collision when the sensor is not active.
+ if (m_links && !m_suspended &&
+ gameobj && (gameobj != parent) && client_info->isActor())
{
if (!m_colliders->SearchValue(gameobj))
m_colliders->Add(gameobj->AddRef());
@@ -236,13 +251,13 @@ PyParentObject KX_TouchSensor::Parents[] = {
PyMethodDef KX_TouchSensor::Methods[] = {
{"setProperty",
- (PyCFunction) KX_TouchSensor::sPySetProperty, METH_VARARGS, SetProperty_doc},
+ (PyCFunction) KX_TouchSensor::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc},
{"getProperty",
- (PyCFunction) KX_TouchSensor::sPyGetProperty, METH_VARARGS, GetProperty_doc},
+ (PyCFunction) KX_TouchSensor::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc},
{"getHitObject",
- (PyCFunction) KX_TouchSensor::sPyGetHitObject, METH_VARARGS, GetHitObject_doc},
+ (PyCFunction) KX_TouchSensor::sPyGetHitObject, METH_VARARGS, (PY_METHODCHAR)GetHitObject_doc},
{"getHitObjectList",
- (PyCFunction) KX_TouchSensor::sPyGetHitObjectList, METH_VARARGS, GetHitObjectList_doc},
+ (PyCFunction) KX_TouchSensor::sPyGetHitObjectList, METH_VARARGS, (PY_METHODCHAR)GetHitObjectList_doc},
{NULL,NULL} //Sentinel
};
@@ -253,7 +268,7 @@ PyObject* KX_TouchSensor::_getattr(const STR_String& attr) {
/* Python API */
/* 1. setProperty */
-char KX_TouchSensor::SetProperty_doc[] =
+const char KX_TouchSensor::SetProperty_doc[] =
"setProperty(name)\n"
"\t- name: string\n"
"\tSet the property or material to collide with. Use\n"
@@ -271,15 +286,15 @@ PyObject* KX_TouchSensor::PySetProperty(PyObject* self,
if (!prop->IsError()) {
m_touchedpropname = nameArg;
- prop->Release();
} else {
; /* not found ... */
}
+ prop->Release();
Py_Return;
}
/* 2. getProperty */
-char KX_TouchSensor::GetProperty_doc[] =
+const char KX_TouchSensor::GetProperty_doc[] =
"getProperty(name)\n"
"\tReturns the property or material to collide with. Use\n"
"\tgetTouchMaterial() to find out whether this sensor\n"
@@ -290,7 +305,7 @@ PyObject* KX_TouchSensor::PyGetProperty(PyObject* self,
return PyString_FromString(m_touchedpropname);
}
-char KX_TouchSensor::GetHitObject_doc[] =
+const char KX_TouchSensor::GetHitObject_doc[] =
"getHitObject()\n"
;
PyObject* KX_TouchSensor::PyGetHitObject(PyObject* self,
@@ -306,7 +321,7 @@ PyObject* KX_TouchSensor::PyGetHitObject(PyObject* self,
Py_Return;
}
-char KX_TouchSensor::GetHitObjectList_doc[] =
+const char KX_TouchSensor::GetHitObjectList_doc[] =
"getHitObjectList()\n"
"\tReturn a list of the objects this object collided with,\n"
"\tbut only those matching the property/material condition.\n";
@@ -348,8 +363,8 @@ PyObject* KX_TouchSensor::PyGetHitObjectList(PyObject* self,
CValue* val = m_colliders->GetValue(i)->FindIdentifier(m_touchedpropname);
if (!val->IsError()) {
newList->Add(m_colliders->GetValue(i)->AddRef());
- val->Release();
}
+ val->Release();
}
i++;
@@ -360,7 +375,7 @@ PyObject* KX_TouchSensor::PyGetHitObjectList(PyObject* self,
}
/* 5. getTouchMaterial */
-char KX_TouchSensor::GetTouchMaterial_doc[] =
+const char KX_TouchSensor::GetTouchMaterial_doc[] =
"getTouchMaterial()\n"
"\tReturns KX_TRUE if this sensor looks for a specific material,\n"
"\tKX_FALSE if it looks for a specific property.\n" ;
@@ -372,7 +387,7 @@ PyObject* KX_TouchSensor::PyGetTouchMaterial(PyObject* self,
}
/* 6. setTouchMaterial */
-char KX_TouchSensor::SetTouchMaterial_doc[] =
+const char KX_TouchSensor::SetTouchMaterial_doc[] =
"setTouchMaterial(flag)\n"
"\t- flag: KX_TRUE or KX_FALSE.\n"
"\tSet flag to KX_TRUE to switch on positive pulse mode,\n"
diff --git a/source/gameengine/Ketsji/KX_TouchSensor.h b/source/gameengine/Ketsji/KX_TouchSensor.h
index dd869fa69c9..8fbb1c676ba 100644
--- a/source/gameengine/Ketsji/KX_TouchSensor.h
+++ b/source/gameengine/Ketsji/KX_TouchSensor.h
@@ -54,8 +54,6 @@ protected:
class SCA_EventManager* m_eventmgr;
class PHY_IPhysicsController* m_physCtrl;
- class PHY_ResponseTable* m_responstTable;
- class PHY_PhysicsController* m_responsObject;
bool m_bCollision;
bool m_bTriggered;
@@ -74,16 +72,23 @@ public:
virtual CValue* GetReplica();
virtual void SynchronizeTransform();
virtual bool Evaluate(CValue* event);
+ virtual void Init();
virtual void ReParent(SCA_IObject* parent);
virtual void RegisterSumo(KX_TouchEventManager* touchman);
+ virtual void UnregisterSumo(KX_TouchEventManager* touchman);
+ virtual void UnregisterToManager();
// virtual DT_Bool HandleCollision(void* obj1,void* obj2,
// const DT_CollData * coll_data);
virtual bool NewHandleCollision(void*obj1,void*obj2,const PHY_CollData* colldata);
- PHY_PhysicsController* GetPhysicsController() { return m_responsObject;}
+ // Allows to do pre-filtering and save computation time
+ // obj1 = sensor physical controller, obj2 = physical controller of second object
+ // return value = true if collision should be checked on pair of object
+ virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2) { return true; }
+
virtual bool IsPositiveTrigger() {
diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp
index dc637bf0837..acc4a6ab5d7 100644
--- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp
+++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp
@@ -42,6 +42,8 @@
#include <iostream>
#include "KX_GameObject.h"
+#include "PyObjectPlus.h"
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -69,12 +71,19 @@ KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj,
m_upflag = upflag;
m_parentobj = 0;
- if (m_object){
- KX_GameObject* curobj = (KX_GameObject*) GetParent();
+ if (m_object)
+ m_object->RegisterActuator(this);
- m_parentobj = curobj->GetParent(); // check if the object is parented
- if (m_parentobj) { // if so, store the initial local rotation
- m_parentlocalmat = m_parentobj->GetSGNode()->GetLocalOrientation();
+ if (gameobj->isA(&KX_GameObject::Type))
+ {
+ // if the object is vertex parented, don't check parent orientation as the link is broken
+ if (!((KX_GameObject*)gameobj)->IsVertexParent()){
+ m_parentobj = ((KX_GameObject*)gameobj)->GetParent(); // check if the object is parented
+ if (m_parentobj) {
+ // if so, store the initial local rotation
+ // this is needed to revert the effect of the parent inverse node (TBC)
+ m_parentlocalmat = m_parentobj->GetSGNode()->GetLocalOrientation();
+ }
}
}
@@ -139,19 +148,19 @@ void compatible_eulFast(float *eul, float *oldrot)
{
float dx, dy, dz;
- /* verschillen van ong 360 graden corrigeren */
+ /* angular difference of 360 degrees */
dx= eul[0] - oldrot[0];
dy= eul[1] - oldrot[1];
dz= eul[2] - oldrot[2];
- if( fabs(dx) > 5.1) {
+ if( fabs(dx) > MT_PI) {
if(dx > 0.0) eul[0] -= MT_2_PI; else eul[0]+= MT_2_PI;
}
- if( fabs(dy) > 5.1) {
+ if( fabs(dy) > MT_PI) {
if(dy > 0.0) eul[1] -= MT_2_PI; else eul[1]+= MT_2_PI;
}
- if( fabs(dz) > 5.1 ) {
+ if( fabs(dz) > MT_PI ) {
if(dz > 0.0) eul[2] -= MT_2_PI; else eul[2]+= MT_2_PI;
}
}
@@ -176,10 +185,53 @@ MT_Matrix3x3 matrix3x3_interpol(MT_Matrix3x3 oldmat, MT_Matrix3x3 mat, int m_tim
KX_TrackToActuator::~KX_TrackToActuator()
-{
- // there's nothing to be done here, really....
+{
+ if (m_object)
+ m_object->UnregisterActuator(this);
+ if (m_parentobj)
+ m_parentobj->Release();
} /* end of destructor */
+void KX_TrackToActuator::ProcessReplica()
+{
+ // the replica is tracking the same object => register it
+ if (m_object)
+ m_object->RegisterActuator(this);
+ if (m_parentobj)
+ m_parentobj->AddRef();
+ SCA_IActuator::ProcessReplica();
+}
+
+
+bool KX_TrackToActuator::UnlinkObject(SCA_IObject* clientobj)
+{
+ if (clientobj == m_object)
+ {
+ // this object is being deleted, we cannot continue to track it.
+ m_object = NULL;
+ return true;
+ }
+ return false;
+}
+
+void KX_TrackToActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
+{
+ void **h_obj = (*obj_map)[m_object];
+ if (h_obj) {
+ if (m_object)
+ m_object->UnregisterActuator(this);
+ m_object = (SCA_IObject*)(*h_obj);
+ m_object->RegisterActuator(this);
+ }
+
+ void **h_parobj = (*obj_map)[m_parentobj];
+ if (h_parobj) {
+ if (m_parentobj)
+ m_parentobj->Release();
+ m_parentobj= (KX_GameObject*)(*h_parobj);
+ m_parentobj->AddRef();
+ }
+}
bool KX_TrackToActuator::Update(double curtime, bool frame)
@@ -196,7 +248,8 @@ bool KX_TrackToActuator::Update(double curtime, bool frame)
{
KX_GameObject* curobj = (KX_GameObject*) GetParent();
MT_Vector3 dir = ((KX_GameObject*)m_object)->NodeGetWorldPosition() - curobj->NodeGetWorldPosition();
- dir.normalize();
+ if (dir.length2())
+ dir.normalize();
MT_Vector3 up(0,0,1);
@@ -222,12 +275,12 @@ bool KX_TrackToActuator::Update(double curtime, bool frame)
#endif
if (m_allow3D)
{
- up = (up - up.dot(dir) * dir).normalized();
+ up = (up - up.dot(dir) * dir).safe_normalized();
}
else
{
- dir = (dir - up.dot(dir)*up).normalized();
+ dir = (dir - up.dot(dir)*up).safe_normalized();
}
MT_Vector3 left;
@@ -238,8 +291,8 @@ bool KX_TrackToActuator::Update(double curtime, bool frame)
case 0: // TRACK X
{
// (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up
- left = dir.normalized();
- dir = (left.cross(up)).normalized();
+ left = dir.safe_normalized();
+ dir = (left.cross(up)).safe_normalized();
mat.setValue (
left[0], dir[0],up[0],
left[1], dir[1],up[1],
@@ -251,7 +304,7 @@ bool KX_TrackToActuator::Update(double curtime, bool frame)
case 1: // TRACK Y
{
// (0.0 , 1.0 , 0.0 ) y direction is forward, z (0.0 , 0.0 , 1.0 ) up
- left = (dir.cross(up)).normalized();
+ left = (dir.cross(up)).safe_normalized();
mat.setValue (
left[0], dir[0],up[0],
left[1], dir[1],up[1],
@@ -263,10 +316,10 @@ bool KX_TrackToActuator::Update(double curtime, bool frame)
case 2: // track Z
{
- left = up.normalized();
- up = dir.normalized();
+ left = up.safe_normalized();
+ up = dir.safe_normalized();
dir = left;
- left = (dir.cross(up)).normalized();
+ left = (dir.cross(up)).safe_normalized();
mat.setValue (
left[0], dir[0],up[0],
left[1], dir[1],up[1],
@@ -278,8 +331,8 @@ bool KX_TrackToActuator::Update(double curtime, bool frame)
case 3: // TRACK -X
{
// (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up
- left = -dir.normalized();
- dir = -(left.cross(up)).normalized();
+ left = -dir.safe_normalized();
+ dir = -(left.cross(up)).safe_normalized();
mat.setValue (
left[0], dir[0],up[0],
left[1], dir[1],up[1],
@@ -291,7 +344,7 @@ bool KX_TrackToActuator::Update(double curtime, bool frame)
case 4: // TRACK -Y
{
// (0.0 , -1.0 , 0.0 ) -y direction is forward, z (0.0 , 0.0 , 1.0 ) up
- left = (-dir.cross(up)).normalized();
+ left = (-dir.cross(up)).safe_normalized();
mat.setValue (
left[0], -dir[0],up[0],
left[1], -dir[1],up[1],
@@ -301,10 +354,10 @@ bool KX_TrackToActuator::Update(double curtime, bool frame)
}
case 5: // track -Z
{
- left = up.normalized();
- up = -dir.normalized();
+ left = up.safe_normalized();
+ up = -dir.safe_normalized();
dir = left;
- left = (dir.cross(up)).normalized();
+ left = (dir.cross(up)).safe_normalized();
mat.setValue (
left[0], dir[0],up[0],
left[1], dir[1],up[1],
@@ -317,8 +370,8 @@ bool KX_TrackToActuator::Update(double curtime, bool frame)
default:
{
// (1.0 , 0.0 , 0.0 ) -x direction is forward, z (0.0 , 0.0 , 1.0 ) up
- left = -dir.normalized();
- dir = -(left.cross(up)).normalized();
+ left = -dir.safe_normalized();
+ dir = -(left.cross(up)).safe_normalized();
mat.setValue (
left[0], dir[0],up[0],
left[1], dir[1],up[1],
@@ -403,12 +456,12 @@ PyParentObject KX_TrackToActuator::Parents[] = {
PyMethodDef KX_TrackToActuator::Methods[] = {
- {"setObject", (PyCFunction) KX_TrackToActuator::sPySetObject, METH_VARARGS, SetObject_doc},
- {"getObject", (PyCFunction) KX_TrackToActuator::sPyGetObject, METH_VARARGS, GetObject_doc},
- {"setTime", (PyCFunction) KX_TrackToActuator::sPySetTime, METH_VARARGS, SetTime_doc},
- {"getTime", (PyCFunction) KX_TrackToActuator::sPyGetTime, METH_VARARGS, GetTime_doc},
- {"setUse3D", (PyCFunction) KX_TrackToActuator::sPySetUse3D, METH_VARARGS, SetUse3D_doc},
- {"getUse3D", (PyCFunction) KX_TrackToActuator::sPyGetUse3D, METH_VARARGS, GetUse3D_doc},
+ {"setObject", (PyCFunction) KX_TrackToActuator::sPySetObject, METH_O, (PY_METHODCHAR)SetObject_doc},
+ {"getObject", (PyCFunction) KX_TrackToActuator::sPyGetObject, METH_VARARGS, (PY_METHODCHAR)GetObject_doc},
+ {"setTime", (PyCFunction) KX_TrackToActuator::sPySetTime, METH_VARARGS, (PY_METHODCHAR)SetTime_doc},
+ {"getTime", (PyCFunction) KX_TrackToActuator::sPyGetTime, METH_VARARGS, (PY_METHODCHAR)GetTime_doc},
+ {"setUse3D", (PyCFunction) KX_TrackToActuator::sPySetUse3D, METH_VARARGS, (PY_METHODCHAR)SetUse3D_doc},
+ {"getUse3D", (PyCFunction) KX_TrackToActuator::sPyGetUse3D, METH_VARARGS, (PY_METHODCHAR)GetUse3D_doc},
{NULL,NULL} //Sentinel
};
@@ -422,49 +475,53 @@ PyObject* KX_TrackToActuator::_getattr(const STR_String& attr)
/* 1. setObject */
-char KX_TrackToActuator::SetObject_doc[] =
+const char KX_TrackToActuator::SetObject_doc[] =
"setObject(object)\n"
-"\t- object: string\n"
+"\t- object: KX_GameObject, string or None\n"
"\tSet the object to track with the parent of this actuator.\n";
-PyObject* KX_TrackToActuator::PySetObject(PyObject* self, PyObject* args, PyObject* kwds) {
- PyObject* gameobj;
- if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj))
- {
- m_object = (SCA_IObject*)gameobj;
-
- Py_Return;
- }
- PyErr_Clear();
+PyObject* KX_TrackToActuator::PySetObject(PyObject* self, PyObject* value)
+{
+ KX_GameObject *gameobj;
- char* objectname;
- if (PyArg_ParseTuple(args, "s", &objectname))
- {
- m_object= static_cast<SCA_IObject*>(SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname)));
-
- Py_Return;
- }
+ if (!ConvertPythonToGameObject(value, &gameobj, true))
+ return NULL; // ConvertPythonToGameObject sets the error
+
+ if (m_object != NULL)
+ m_object->UnregisterActuator(this);
+
+ m_object = (SCA_IObject*)gameobj;
+ if (m_object)
+ m_object->RegisterActuator(this);
- return NULL;
+ Py_RETURN_NONE;
}
/* 2. getObject */
-char KX_TrackToActuator::GetObject_doc[] =
-"getObject()\n"
-"\tReturns the object to track with the parent of this actuator.\n";
-PyObject* KX_TrackToActuator::PyGetObject(PyObject* self, PyObject* args, PyObject* kwds)
+const char KX_TrackToActuator::GetObject_doc[] =
+"getObject(name_only = 1)\n"
+"name_only - optional arg, when true will return the KX_GameObject rather then its name\n"
+"\tReturns the object to track with the parent of this actuator\n";
+PyObject* KX_TrackToActuator::PyGetObject(PyObject* self, PyObject* args)
{
+ int ret_name_only = 1;
+ if (!PyArg_ParseTuple(args, "|i", &ret_name_only))
+ return NULL;
+
if (!m_object)
- Py_Return;
-
- return PyString_FromString(m_object->GetName());
+ Py_RETURN_NONE;
+
+ if (ret_name_only)
+ return PyString_FromString(m_object->GetName());
+ else
+ return m_object->AddRef();
}
/* 3. setTime */
-char KX_TrackToActuator::SetTime_doc[] =
+const char KX_TrackToActuator::SetTime_doc[] =
"setTime(time)\n"
"\t- time: integer\n"
"\tSet the time in frames with which to delay the tracking motion.\n";
@@ -485,7 +542,7 @@ PyObject* KX_TrackToActuator::PySetTime(PyObject* self, PyObject* args, PyObject
/* 4.getTime */
-char KX_TrackToActuator::GetTime_doc[] =
+const char KX_TrackToActuator::GetTime_doc[] =
"getTime()\n"
"\t- time: integer\n"
"\tReturn the time in frames with which the tracking motion is delayed.\n";
@@ -497,7 +554,7 @@ PyObject* KX_TrackToActuator::PyGetTime(PyObject* self, PyObject* args, PyObject
/* 5. getUse3D */
-char KX_TrackToActuator::GetUse3D_doc[] =
+const char KX_TrackToActuator::GetUse3D_doc[] =
"getUse3D()\n"
"\tReturns 1 if the motion is allowed to extend in the z-direction.\n";
PyObject* KX_TrackToActuator::PyGetUse3D(PyObject* self, PyObject* args, PyObject* kwds)
@@ -508,7 +565,7 @@ PyObject* KX_TrackToActuator::PyGetUse3D(PyObject* self, PyObject* args, PyObjec
/* 6. setUse3D */
-char KX_TrackToActuator::SetUse3D_doc[] =
+const char KX_TrackToActuator::SetUse3D_doc[] =
"setUse3D(value)\n"
"\t- value: 0 or 1\n"
"\tSet to 1 to allow the tracking motion to extend in the z-direction,\n"
diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.h b/source/gameengine/Ketsji/KX_TrackToActuator.h
index 944eaadf025..445132a6094 100644
--- a/source/gameengine/Ketsji/KX_TrackToActuator.h
+++ b/source/gameengine/Ketsji/KX_TrackToActuator.h
@@ -66,15 +66,18 @@ class KX_TrackToActuator : public SCA_IActuator
return replica;
};
+ virtual void ProcessReplica();
+ virtual bool UnlinkObject(SCA_IObject* clientobj);
+ virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
virtual bool Update(double curtime, bool frame);
/* Python part */
virtual PyObject* _getattr(const STR_String& attr);
/* 1. setObject */
- KX_PYMETHOD_DOC(KX_TrackToActuator,SetObject);
+ KX_PYMETHOD_DOC_O(KX_TrackToActuator,SetObject);
/* 2. getObject */
- KX_PYMETHOD_DOC(KX_TrackToActuator,GetObject);
+ KX_PYMETHOD_DOC_VARARGS(KX_TrackToActuator,GetObject);
/* 3. setTime */
KX_PYMETHOD_DOC(KX_TrackToActuator,SetTime);
/* 4. getTime */
diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
index fba2ecc223b..028f96f6c5b 100644
--- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
+++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
@@ -1,6 +1,8 @@
#include <Python.h>
+#include "PyObjectPlus.h"
+
#include "KX_VehicleWrapper.h"
#include "PHY_IPhysicsEnvironment.h"
#include "PHY_IVehicle.h"
@@ -47,30 +49,34 @@ PyObject* KX_VehicleWrapper::PyAddWheel(PyObject* self,
if (PyArg_ParseTuple(args,"OOOOffi",&wheelGameObject,&pylistPos,&pylistDir,&pylistAxleDir,&suspensionRestLength,&wheelRadius,&hasSteering))
{
KX_GameObject* gameOb = (KX_GameObject*) wheelGameObject;
+
+ if (gameOb->GetSGNode())
+ {
+ PHY_IMotionState* motionState = new KX_MotionState(gameOb->GetSGNode());
+
+ MT_Vector3 attachPos,attachDir,attachAxle;
+ PyVecTo(pylistPos,attachPos);
+ PyVecTo(pylistDir,attachDir);
+ PyVecTo(pylistAxleDir,attachAxle);
+ PHY__Vector3 aPos,aDir,aAxle;
+ aPos[0] = attachPos[0];
+ aPos[1] = attachPos[1];
+ aPos[2] = attachPos[2];
+ aDir[0] = attachDir[0];
+ aDir[1] = attachDir[1];
+ aDir[2] = attachDir[2];
+ aAxle[0] = -attachAxle[0];//someone reverse some conventions inside Bullet (axle winding)
+ aAxle[1] = -attachAxle[1];
+ aAxle[2] = -attachAxle[2];
+
+ printf("attempt for addWheel: suspensionRestLength%f wheelRadius %f, hasSteering:%d\n",suspensionRestLength,wheelRadius,hasSteering);
+ m_vehicle->AddWheel(motionState,aPos,aDir,aAxle,suspensionRestLength,wheelRadius,hasSteering);
+ }
- PHY_IMotionState* motionState = new KX_MotionState(gameOb->GetSGNode());
-
- MT_Vector3 attachPos,attachDir,attachAxle;
- PyVecTo(pylistPos,attachPos);
- PyVecTo(pylistDir,attachDir);
- PyVecTo(pylistAxleDir,attachAxle);
- PHY__Vector3 aPos,aDir,aAxle;
- aPos[0] = attachPos[0];
- aPos[1] = attachPos[1];
- aPos[2] = attachPos[2];
- aDir[0] = attachDir[0];
- aDir[1] = attachDir[1];
- aDir[2] = attachDir[2];
- aAxle[0] = -attachAxle[0];//someone reverse some conventions inside Bullet (axle winding)
- aAxle[1] = -attachAxle[1];
- aAxle[2] = -attachAxle[2];
-
- printf("attempt for addWheel: suspensionRestLength%f wheelRadius %f, hasSteering:%d\n",suspensionRestLength,wheelRadius,hasSteering);
- m_vehicle->AddWheel(motionState,aPos,aDir,aAxle,suspensionRestLength,wheelRadius,hasSteering);
-
+ } else {
+ return NULL;
}
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
@@ -90,8 +96,7 @@ PyObject* KX_VehicleWrapper::PyGetWheelPosition(PyObject* self,
MT_Vector3 pos(position[0],position[1],position[2]);
return PyObjectFrom(pos);
}
- Py_INCREF(Py_None);
- return Py_None;
+ return NULL;
}
PyObject* KX_VehicleWrapper::PyGetWheelRotation(PyObject* self,
@@ -103,8 +108,7 @@ PyObject* KX_VehicleWrapper::PyGetWheelRotation(PyObject* self,
{
return PyFloat_FromDouble(m_vehicle->GetWheelRotation(wheelIndex));
}
- Py_INCREF(Py_None);
- return Py_None;
+ return NULL;
}
PyObject* KX_VehicleWrapper::PyGetWheelOrientationQuaternion(PyObject* self,
@@ -120,8 +124,7 @@ PyObject* KX_VehicleWrapper::PyGetWheelOrientationQuaternion(PyObject* self,
MT_Matrix3x3 ornmat(quatorn);
return PyObjectFrom(ornmat);
}
- Py_INCREF(Py_None);
- return Py_None;
+ return NULL;
}
@@ -155,8 +158,10 @@ PyObject* KX_VehicleWrapper::PyApplyEngineForce(PyObject* self,
force *= -1.f;//someone reverse some conventions inside Bullet (axle winding)
m_vehicle->ApplyEngineForce(force,wheelIndex);
}
- Py_INCREF(Py_None);
- return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
PyObject* KX_VehicleWrapper::PySetTyreFriction(PyObject* self,
@@ -170,8 +175,10 @@ PyObject* KX_VehicleWrapper::PySetTyreFriction(PyObject* self,
{
m_vehicle->SetWheelFriction(wheelFriction,wheelIndex);
}
- Py_INCREF(Py_None);
- return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
PyObject* KX_VehicleWrapper::PySetSuspensionStiffness(PyObject* self,
@@ -185,8 +192,10 @@ PyObject* KX_VehicleWrapper::PySetSuspensionStiffness(PyObject* self,
{
m_vehicle->SetSuspensionStiffness(suspensionStiffness,wheelIndex);
}
- Py_INCREF(Py_None);
- return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
PyObject* KX_VehicleWrapper::PySetSuspensionDamping(PyObject* self,
@@ -199,9 +208,10 @@ PyObject* KX_VehicleWrapper::PySetSuspensionDamping(PyObject* self,
if (PyArg_ParseTuple(args,"fi",&suspensionDamping,&wheelIndex))
{
m_vehicle->SetSuspensionDamping(suspensionDamping,wheelIndex);
+ } else {
+ return NULL;
}
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
PyObject* KX_VehicleWrapper::PySetSuspensionCompression(PyObject* self,
@@ -214,9 +224,10 @@ PyObject* KX_VehicleWrapper::PySetSuspensionCompression(PyObject* self,
if (PyArg_ParseTuple(args,"fi",&suspensionCompression,&wheelIndex))
{
m_vehicle->SetSuspensionCompression(suspensionCompression,wheelIndex);
+ } else {
+ return NULL;
}
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
PyObject* KX_VehicleWrapper::PySetRollInfluence(PyObject* self,
@@ -230,8 +241,10 @@ PyObject* KX_VehicleWrapper::PySetRollInfluence(PyObject* self,
{
m_vehicle->SetRollInfluence(rollInfluence,wheelIndex);
}
- Py_INCREF(Py_None);
- return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
@@ -246,8 +259,10 @@ PyObject* KX_VehicleWrapper::PyApplyBraking(PyObject* self,
{
m_vehicle->ApplyBraking(braking,wheelIndex);
}
- Py_INCREF(Py_None);
- return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
@@ -264,8 +279,10 @@ PyObject* KX_VehicleWrapper::PySetSteeringValue(PyObject* self,
{
m_vehicle->SetSteeringValue(steeringValue,wheelIndex);
}
- Py_INCREF(Py_None);
- return Py_None;
+ else {
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
diff --git a/source/gameengine/Ketsji/KX_VertexProxy.cpp b/source/gameengine/Ketsji/KX_VertexProxy.cpp
index 5cec65dff1c..25205714308 100644
--- a/source/gameengine/Ketsji/KX_VertexProxy.cpp
+++ b/source/gameengine/Ketsji/KX_VertexProxy.cpp
@@ -82,7 +82,7 @@ PyObject*
KX_VertexProxy::_getattr(const STR_String& attr)
{
if (attr == "XYZ")
- return PyObjectFrom(MT_Vector3(m_vertex->getLocalXYZ()));
+ return PyObjectFrom(MT_Vector3(m_vertex->getXYZ()));
if (attr == "UV")
return PyObjectFrom(MT_Point2(m_vertex->getUV1()));
@@ -102,11 +102,11 @@ KX_VertexProxy::_getattr(const STR_String& attr)
// pos
if (attr == "x")
- return PyFloat_FromDouble(m_vertex->getLocalXYZ()[0]);
+ return PyFloat_FromDouble(m_vertex->getXYZ()[0]);
if (attr == "y")
- return PyFloat_FromDouble(m_vertex->getLocalXYZ()[1]);
+ return PyFloat_FromDouble(m_vertex->getXYZ()[1]);
if (attr == "z")
- return PyFloat_FromDouble(m_vertex->getLocalXYZ()[2]);
+ return PyFloat_FromDouble(m_vertex->getXYZ()[2]);
// Col
if (attr == "r")
@@ -184,7 +184,7 @@ int KX_VertexProxy::_setattr(const STR_String& attr, PyObject *pyvalue)
{
float val = PyFloat_AsDouble(pyvalue);
// pos
- MT_Point3 pos(m_vertex->getLocalXYZ());
+ MT_Point3 pos(m_vertex->getXYZ());
if (attr == "x")
{
pos.x() = val;
@@ -312,7 +312,7 @@ PyObject* KX_VertexProxy::PyGetXYZ(PyObject*,
PyObject*,
PyObject*)
{
- return PyObjectFrom(MT_Point3(m_vertex->getLocalXYZ()));
+ return PyObjectFrom(MT_Point3(m_vertex->getXYZ()));
}
PyObject* KX_VertexProxy::PySetXYZ(PyObject*,
@@ -426,7 +426,7 @@ PyObject* KX_VertexProxy::PySetUV2(PyObject*,
{
if (PyVecTo(list, vec))
{
- m_vertex->SetFlag((m_vertex->getFlag()|TV_2NDUV));
+ m_vertex->SetFlag((m_vertex->getFlag()|RAS_TexVert::SECOND_UV));
m_vertex->SetUnit(unit);
m_vertex->SetUV2(vec);
m_mesh->SetMeshModified(true);
diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp
index b4693a7a7db..4b0db5a7953 100644
--- a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp
+++ b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp
@@ -38,10 +38,12 @@
KX_VisibilityActuator::KX_VisibilityActuator(
SCA_IObject* gameobj,
bool visible,
+ bool recursive,
PyTypeObject* T
)
: SCA_IActuator(gameobj,T),
- m_visible(visible)
+ m_visible(visible),
+ m_recursive(recursive)
{
// intentionally empty
}
@@ -75,10 +77,10 @@ KX_VisibilityActuator::Update()
KX_GameObject *obj = (KX_GameObject*) GetParent();
- obj->SetVisible(m_visible);
- obj->MarkVisible();
+ obj->SetVisible(m_visible, m_recursive);
+ obj->UpdateBuckets(m_recursive);
- return true;
+ return false;
}
/* ------------------------------------------------------------------------- */
@@ -120,7 +122,7 @@ KX_VisibilityActuator::Parents[] = {
PyMethodDef
KX_VisibilityActuator::Methods[] = {
{"set", (PyCFunction) KX_VisibilityActuator::sPySetVisible,
- METH_VARARGS, SetVisible_doc},
+ METH_VARARGS, (PY_METHODCHAR)SetVisible_doc},
{NULL,NULL} //Sentinel
};
@@ -135,7 +137,7 @@ KX_VisibilityActuator::_getattr(
/* set visibility ---------------------------------------------------------- */
-char
+const char
KX_VisibilityActuator::SetVisible_doc[] =
"setVisible(visible?)\n"
"\t - visible? : Make the object visible? (KX_TRUE, KX_FALSE)"
diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.h b/source/gameengine/Ketsji/KX_VisibilityActuator.h
index 9b4753033fb..d1b85ab998c 100644
--- a/source/gameengine/Ketsji/KX_VisibilityActuator.h
+++ b/source/gameengine/Ketsji/KX_VisibilityActuator.h
@@ -39,12 +39,14 @@ class KX_VisibilityActuator : public SCA_IActuator
/** Make visible? */
bool m_visible;
+ bool m_recursive;
public:
KX_VisibilityActuator(
SCA_IObject* gameobj,
bool visible,
+ bool recursive,
PyTypeObject* T=&Type
);
diff --git a/source/gameengine/Ketsji/Makefile b/source/gameengine/Ketsji/Makefile
index fe226f22635..bdc0b335b02 100644
--- a/source/gameengine/Ketsji/Makefile
+++ b/source/gameengine/Ketsji/Makefile
@@ -35,9 +35,13 @@ include nan_compile.mk
CCFLAGS += $(LEVEL_1_CPP_WARNINGS)
+CPPFLAGS += $(NAN_SDLCFLAGS)
CPPFLAGS += $(OGL_CPPFLAGS)
+CPPFLAGS += -I$(NAN_GLEW)/include
CPPFLAGS += -I$(OPENGL_HEADERS)
-CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) -I../../blender/python
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+CPPFLAGS += -I../../blender/python
+CPPFLAGS += -I../../blender/python/api2_2x
CPPFLAGS += -I$(NAN_STRING)/include
CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include
CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO) -I$(NAN_MOTO)/include
@@ -60,6 +64,7 @@ CPPFLAGS += -I../../blender/blenlib
CPPFLAGS += -I../../blender/editors/include
CPPFLAGS += -I../../blender/makesdna
CPPFLAGS += -I../../blender/imbuf
+CPPFLAGS += -I../../blender/gpu
CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
###########################
diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript
index f9f7920d244..7d2cfb403c0 100644
--- a/source/gameengine/Ketsji/SConscript
+++ b/source/gameengine/Ketsji/SConscript
@@ -5,7 +5,22 @@ Import ('env')
sources = env.Glob('*.cpp')
-incs = '. #source/kernel/gen_system #intern/string #intern/guardedalloc'
+#XXX
+# Mathutils C files.
+#sources.extend([\
+# '#source/blender/python/api2_2x/Mathutils.c',\
+# '#source/blender/python/api2_2x/constant.c',\
+# '#source/blender/python/api2_2x/euler.c',\
+# '#source/blender/python/api2_2x/gen_utils.c',\
+# '#source/blender/python/api2_2x/matrix.c',\
+# '#source/blender/python/api2_2x/point.c',\
+# '#source/blender/python/api2_2x/quat.c',\
+# '#source/blender/python/api2_2x/vector.c',\
+#])
+
+incs = '. #source/blender/python/api2_2x' # Only for Mathutils! - no other deps
+
+incs += ' #source/kernel/gen_system #intern/string #intern/guardedalloc'
incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer #intern/bmfont'
incs += ' #intern/SoundSystem #intern/SoundSystem/include #intern/SoundSystem/openal'
incs += ' #intern/SoundSystem/dummy #intern/SoundSystem/intern #source/gameengine/Converter'
@@ -18,7 +33,7 @@ incs += ' #source/gameengine/SceneGraph #source/gameengine/Physics/common #sourc
incs += ' #source/gameengine/Physics/BlOde #source/gameengine/Physics/Dummy'
incs += ' #source/gameengine/Physics/Sumo #source/gameengine/Physics/Sumo/include'
incs += ' #source/gameengine/Physics/Sumo/Fuzzics/include #source/gameengine/Network/LoopBackNetwork'
-incs += ' #source/blender/misc #source/blender/blenloader'
+incs += ' #source/blender/misc #source/blender/blenloader #extern/glew/include #source/blender/gpu'
cflags = []
if env['OURPLATFORM'] == 'win32-vc':
@@ -27,8 +42,10 @@ if env['OURPLATFORM'] == 'win32-vc':
incs += ' ' + env['BF_SOLID_INC']
incs += ' ' + env['BF_PYTHON_INC']
-incs += ' ' + env['BF_SDL_INC']
incs += ' ' + env['BF_BULLET_INC']
incs += ' ' + env['BF_OPENGL_INC']
+if env['WITH_BF_SDL']:
+ incs += ' ' + env['BF_SDL_INC']
+
env.BlenderLib ( 'bf_ketsji', sources, Split(incs), [], libtype=['game','player'], priority=[25, 60], compileflags = cflags )