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:
Diffstat (limited to 'source/gameengine/Converter')
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp37
-rw-r--r--source/gameengine/Converter/BL_DeformableGameObject.cpp47
-rw-r--r--source/gameengine/Converter/BL_DeformableGameObject.h40
-rw-r--r--source/gameengine/Converter/BL_MeshDeformer.cpp2
-rw-r--r--source/gameengine/Converter/BL_MeshDeformer.h4
-rw-r--r--source/gameengine/Converter/BL_ShapeActionActuator.cpp797
-rw-r--r--source/gameengine/Converter/BL_ShapeActionActuator.h133
-rw-r--r--source/gameengine/Converter/BL_ShapeDeformer.cpp125
-rw-r--r--source/gameengine/Converter/BL_ShapeDeformer.h93
-rw-r--r--source/gameengine/Converter/BL_SkinDeformer.cpp50
-rw-r--r--source/gameengine/Converter/BL_SkinDeformer.h35
-rw-r--r--source/gameengine/Converter/BL_SkinMeshObject.cpp58
-rw-r--r--source/gameengine/Converter/BL_SkinMeshObject.h36
-rw-r--r--source/gameengine/Converter/KX_ConvertActuators.cpp25
14 files changed, 1428 insertions, 54 deletions
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index 0ad9258bcc0..32946267202 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -90,6 +90,7 @@
#include "BKE_object.h"
#include "BKE_scene.h"
#include "BL_SkinMeshObject.h"
+#include "BL_ShapeDeformer.h"
#include "BL_SkinDeformer.h"
#include "BL_MeshDeformer.h"
//#include "BL_ArmatureController.h"
@@ -223,15 +224,16 @@ static unsigned int KX_Mcol2uint_new(MCol col)
static void SetDefaultFaceType(Scene* scene)
{
default_face_mode = TF_DYNAMIC;
- Base *base = static_cast<Base*>(scene->base.first);
- while(base)
+ Scene *sce;
+ Base *base;
+
+ for(SETLOOPER(scene,base))
{
if (base->object->type == OB_LAMP)
{
default_face_mode = TF_DYNAMIC|TF_LIGHT;
return;
}
- base = base->next;
}
}
@@ -800,12 +802,12 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools*
// Determine if we need to make a skinned mesh
- if (mesh->dvert){
- meshobj = new BL_SkinMeshObject(lightlayer);
+ if (mesh->dvert || mesh->key){
+ meshobj = new BL_SkinMeshObject(mesh, lightlayer);
skinMesh = true;
}
else {
- meshobj = new RAS_MeshObject(lightlayer);
+ meshobj = new RAS_MeshObject(mesh, lightlayer);
}
MT_Vector4 *tangent = 0;
if (tface)
@@ -1644,7 +1646,7 @@ static KX_GameObject *gameobject_from_blenderobject(
// needed for python scripting
kxscene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj);
- gameobj = new BL_DeformableGameObject(kxscene,KX_Scene::m_callbacks);
+ gameobj = new BL_DeformableGameObject(ob,kxscene,KX_Scene::m_callbacks);
// set transformation
gameobj->AddMesh(meshobj);
@@ -1655,12 +1657,24 @@ static KX_GameObject *gameobject_from_blenderobject(
((ob->gameflag2 & OB_NEVER_DO_ACTIVITY_CULLING)!=0);
gameobj->SetIgnoreActivityCulling(ignoreActivityCulling);
- // If this is a skin object, make Skin Controller
- if (ob->parent && ob->parent->type == OB_ARMATURE && ob->partype==PARSKEL && ((Mesh*)ob->data)->dvert){
+ // two options exists for deform: shape keys and armature
+ // only support relative shape key
+ bool bHasShapeKey = mesh->key != NULL && mesh->key->type==KEY_RELATIVE;
+ bool bHasDvert = mesh->dvert != NULL;
+ bool bHasArmature = (ob->parent && ob->parent->type == OB_ARMATURE && ob->partype==PARSKEL && bHasDvert);
+
+ if (bHasShapeKey) {
+ // not that we can have shape keys without dvert!
+ BL_ShapeDeformer *dcont = new BL_ShapeDeformer((BL_DeformableGameObject*)gameobj,
+ ob, (BL_SkinMeshObject*)meshobj);
+ ((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont;
+ } else if (bHasArmature) {
BL_SkinDeformer *dcont = new BL_SkinDeformer(ob, (BL_SkinMeshObject*)meshobj );
((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont;
- }
- else if (((Mesh*)ob->data)->dvert){
+ } else if (bHasDvert) {
+ // this case correspond to a mesh that can potentially deform but not with the
+ // object to which it is attached for the moment. A skin mesh was created in
+ // BL_ConvertMesh() so must create a deformer too!
BL_MeshDeformer *dcont = new BL_MeshDeformer(ob, (BL_SkinMeshObject*)meshobj );
((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont;
}
@@ -1696,6 +1710,7 @@ static KX_GameObject *gameobject_from_blenderobject(
{
gameobj->SetPhysicsEnvironment(kxscene->GetPhysicsEnvironment());
gameobj->SetLayer(ob->lay);
+ gameobj->SetBlenderObject(ob);
}
return gameobj;
}
diff --git a/source/gameengine/Converter/BL_DeformableGameObject.cpp b/source/gameengine/Converter/BL_DeformableGameObject.cpp
index 68a2e41ca47..d23274324ee 100644
--- a/source/gameengine/Converter/BL_DeformableGameObject.cpp
+++ b/source/gameengine/Converter/BL_DeformableGameObject.cpp
@@ -28,6 +28,8 @@
*/
#include "BL_DeformableGameObject.h"
+#include "BL_ShapeDeformer.h"
+#include "BL_ShapeActionActuator.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -60,3 +62,48 @@ CValue* BL_DeformableGameObject::GetReplica()
ProcessReplica(replica);
return replica;
}
+
+bool BL_DeformableGameObject::SetActiveAction(BL_ShapeActionActuator *act, short priority, double curtime)
+{
+ if (curtime != m_lastframe){
+ m_activePriority = 9999;
+ m_lastframe= curtime;
+ m_activeAct = NULL;
+ }
+
+ if (priority<=m_activePriority)
+ {
+ if (m_activeAct && (m_activeAct!=act))
+ m_activeAct->SetBlendTime(0.0f); /* Reset the blend timer */
+ m_activeAct = act;
+ m_activePriority = priority;
+ m_lastframe = curtime;
+
+ return true;
+ }
+ else{
+ act->SetBlendTime(0.0f);
+ return false;
+ }
+}
+
+bool BL_DeformableGameObject::GetShape(vector<float> &shape)
+{
+ shape.clear();
+ if (m_pDeformer)
+ {
+ Mesh* mesh = ((BL_MeshDeformer*)m_pDeformer)->GetMesh();
+ // this check is normally superfluous: a shape deformer can only be created if the mesh
+ // has relative keys
+ if (mesh && mesh->key && mesh->key->type==KEY_RELATIVE)
+ {
+ KeyBlock *kb;
+ for (kb = (KeyBlock*)mesh->key->block.first; kb; kb = (KeyBlock*)kb->next)
+ {
+ shape.push_back(kb->curval);
+ }
+ }
+ }
+ return !shape.empty();
+}
+
diff --git a/source/gameengine/Converter/BL_DeformableGameObject.h b/source/gameengine/Converter/BL_DeformableGameObject.h
index d943cc7388a..57a404ad72b 100644
--- a/source/gameengine/Converter/BL_DeformableGameObject.h
+++ b/source/gameengine/Converter/BL_DeformableGameObject.h
@@ -34,15 +34,28 @@
#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
#endif //WIN32
+#include "DNA_mesh_types.h"
#include "KX_GameObject.h"
-#include "RAS_Deformer.h"
+#include "BL_MeshDeformer.h"
+#include <vector>
+
+class BL_ShapeActionActuator;
+struct Key;
class BL_DeformableGameObject : public KX_GameObject
{
public:
- RAS_Deformer *m_pDeformer;
CValue* GetReplica();
+
+ double GetLastFrame ()
+ {
+ return m_lastframe;
+ }
+ Object* GetBlendObject()
+ {
+ return m_blendobj;
+ }
virtual void Relink(GEN_Map<GEN_HashedPtr, void*>*map)
{
if (m_pDeformer)
@@ -50,13 +63,32 @@ public:
};
void ProcessReplica(KX_GameObject* replica);
- BL_DeformableGameObject(void* sgReplicationInfo, SG_Callbacks callbacks) :
+ BL_DeformableGameObject(Object* blendobj, void* sgReplicationInfo, SG_Callbacks callbacks) :
KX_GameObject(sgReplicationInfo,callbacks),
- m_pDeformer(NULL)
+ m_pDeformer(NULL),
+ m_activeAct(NULL),
+ m_lastframe(0.),
+ m_blendobj(blendobj),
+ m_activePriority(9999)
{
m_isDeformable = true;
};
virtual ~BL_DeformableGameObject();
+ bool SetActiveAction(class BL_ShapeActionActuator *act, short priority, double curtime);
+
+ bool GetShape(vector<float> &shape);
+ Key* GetKey()
+ {
+ return (m_pDeformer) ? ((BL_MeshDeformer*)m_pDeformer)->GetMesh()->key : NULL;
+ }
+
+public:
+ RAS_Deformer *m_pDeformer;
+protected:
+ class BL_ShapeActionActuator *m_activeAct;
+ double m_lastframe;
+ Object* m_blendobj;
+ short m_activePriority;
};
diff --git a/source/gameengine/Converter/BL_MeshDeformer.cpp b/source/gameengine/Converter/BL_MeshDeformer.cpp
index 85ba894f9a5..212827a660f 100644
--- a/source/gameengine/Converter/BL_MeshDeformer.cpp
+++ b/source/gameengine/Converter/BL_MeshDeformer.cpp
@@ -198,7 +198,7 @@ void BL_MeshDeformer::RecalcNormals()
void BL_MeshDeformer::VerifyStorage()
{
/* Ensure that we have the right number of verts assigned */
- if (m_tvtot!=m_bmesh->totvert+m_bmesh->totface) {
+ if (m_tvtot!=m_bmesh->totvert){
if (m_transverts)
delete [] m_transverts;
if (m_transnors)
diff --git a/source/gameengine/Converter/BL_MeshDeformer.h b/source/gameengine/Converter/BL_MeshDeformer.h
index 88dc2500859..8d8b56b1eed 100644
--- a/source/gameengine/Converter/BL_MeshDeformer.h
+++ b/source/gameengine/Converter/BL_MeshDeformer.h
@@ -32,6 +32,7 @@
#include "RAS_Deformer.h"
#include "DNA_object_types.h"
+#include "DNA_key_types.h"
#include "MT_Point3.h"
#include <stdlib.h>
@@ -56,8 +57,9 @@ public:
virtual ~BL_MeshDeformer();
virtual void SetSimulatedTime(double time){};
virtual bool Apply(class RAS_IPolyMaterial *mat);
- virtual void Update(void){};
+ virtual bool Update(void){ return false; };
virtual RAS_Deformer* GetReplica(){return NULL;};
+ struct Mesh* GetMesh() { return m_bmesh; };
// virtual void InitDeform(double time){};
protected:
class BL_SkinMeshObject* m_pMeshObject;
diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.cpp b/source/gameengine/Converter/BL_ShapeActionActuator.cpp
new file mode 100644
index 00000000000..3e1369e1e9f
--- /dev/null
+++ b/source/gameengine/Converter/BL_ShapeActionActuator.cpp
@@ -0,0 +1,797 @@
+/**
+* $Id: BL_ShapeActionActuator.cpp 14444 2008-04-16 22:40:48Z hos $
+*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+*/
+
+#if defined (__sgi)
+#include <math.h>
+#else
+#include <cmath>
+#endif
+
+#include "SCA_LogicManager.h"
+#include "BL_ShapeActionActuator.h"
+#include "BL_ActionActuator.h"
+#include "BL_ShapeDeformer.h"
+#include "KX_GameObject.h"
+#include "STR_HashedString.h"
+#include "DNA_action_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_actuator_types.h"
+#include "BKE_action.h"
+#include "DNA_armature_types.h"
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "MT_Matrix4x4.h"
+#include "BKE_utildefines.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+BL_ShapeActionActuator::~BL_ShapeActionActuator()
+{
+}
+
+void BL_ShapeActionActuator::ProcessReplica()
+{
+ m_localtime=m_startframe;
+ m_lastUpdate=-1;
+}
+
+void BL_ShapeActionActuator::SetBlendTime (float newtime)
+{
+ m_blendframe = newtime;
+}
+
+CValue* BL_ShapeActionActuator::GetReplica()
+{
+ BL_ShapeActionActuator* replica = new BL_ShapeActionActuator(*this);//m_float,GetName());
+ replica->ProcessReplica();
+
+ // this will copy properties and so on...
+ CValue::AddDataToReplica(replica);
+ return replica;
+}
+
+bool BL_ShapeActionActuator::ClampLocalTime()
+{
+ if (m_startframe < m_endframe) {
+ if (m_localtime < m_startframe)
+ {
+ m_localtime = m_startframe;
+ return true;
+ }
+ else if (m_localtime > m_endframe)
+ {
+ m_localtime = m_endframe;
+ return true;
+ }
+ } else {
+ if (m_localtime > m_startframe)
+ {
+ m_localtime = m_startframe;
+ return true;
+ }
+ else if (m_localtime < m_endframe)
+ {
+ m_localtime = m_endframe;
+ return true;
+ }
+ }
+ return false;
+}
+
+void BL_ShapeActionActuator::SetStartTime(float curtime)
+{
+ float direction = m_startframe < m_endframe ? 1.0 : -1.0;
+
+ if (!(m_flag & ACT_FLAG_REVERSE))
+ m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate();
+ else
+ m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate();
+}
+
+void BL_ShapeActionActuator::SetLocalTime(float curtime)
+{
+ float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate();
+
+ if (m_endframe < m_startframe)
+ delta_time = -delta_time;
+
+ if (!(m_flag & ACT_FLAG_REVERSE))
+ m_localtime = m_startframe + delta_time;
+ else
+ m_localtime = m_endframe - delta_time;
+}
+
+void BL_ShapeActionActuator::BlendShape(Key* key, float srcweight)
+{
+ vector<float>::const_iterator it;
+ float dstweight;
+ int i;
+ KeyBlock *kb;
+
+ dstweight = 1.0F - srcweight;
+
+ for (it=m_blendshape.begin(), kb = (KeyBlock*)key->block.first;
+ kb && it != m_blendshape.end();
+ kb = (KeyBlock*)kb->next, it++) {
+ kb->curval = kb->curval * dstweight + (*it) * srcweight;
+ }
+}
+
+bool BL_ShapeActionActuator::Update(double curtime, bool frame)
+{
+ bool bNegativeEvent = false;
+ bool bPositiveEvent = false;
+ bool keepgoing = true;
+ bool wrap = false;
+ bool apply=true;
+ int priority;
+ float newweight;
+
+ // result = true if animation has to be continued, false if animation stops
+ // maybe there are events for us in the queue !
+ if (frame)
+ {
+ for (vector<CValue*>::iterator i=m_events.begin(); !(i==m_events.end());i++)
+ {
+ if ((*i)->GetNumber() == 0.0f)
+ bNegativeEvent = true;
+ else
+ bPositiveEvent= true;
+ (*i)->Release();
+
+ }
+ m_events.clear();
+
+ if (bPositiveEvent)
+ m_flag |= ACT_FLAG_ACTIVE;
+
+ if (bNegativeEvent)
+ {
+ if (!(m_flag & ACT_FLAG_ACTIVE))
+ return false;
+ m_flag &= ~ACT_FLAG_ACTIVE;
+ }
+ }
+
+ /* This action can only be attached to a deform object */
+ BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent();
+ float length = m_endframe - m_startframe;
+
+ priority = m_priority;
+
+ /* Determine pre-incrementation behaviour and set appropriate flags */
+ switch (m_playtype){
+ case ACT_ACTION_MOTION:
+ if (bNegativeEvent){
+ keepgoing=false;
+ apply=false;
+ };
+ break;
+ case ACT_ACTION_FROM_PROP:
+ if (bNegativeEvent){
+ apply=false;
+ keepgoing=false;
+ }
+ break;
+ case ACT_ACTION_LOOP_END:
+ if (bPositiveEvent){
+ if (!(m_flag & ACT_FLAG_LOCKINPUT)){
+ m_flag &= ~ACT_FLAG_KEYUP;
+ m_flag &= ~ACT_FLAG_REVERSE;
+ m_flag |= ACT_FLAG_LOCKINPUT;
+ m_localtime = m_startframe;
+ m_starttime = curtime;
+ }
+ }
+ if (bNegativeEvent){
+ m_flag |= ACT_FLAG_KEYUP;
+ }
+ break;
+ case ACT_ACTION_LOOP_STOP:
+ if (bPositiveEvent){
+ if (!(m_flag & ACT_FLAG_LOCKINPUT)){
+ m_flag &= ~ACT_FLAG_REVERSE;
+ m_flag &= ~ACT_FLAG_KEYUP;
+ m_flag |= ACT_FLAG_LOCKINPUT;
+ SetStartTime(curtime);
+ }
+ }
+ if (bNegativeEvent){
+ m_flag |= ACT_FLAG_KEYUP;
+ m_flag &= ~ACT_FLAG_LOCKINPUT;
+ keepgoing=false;
+ apply=false;
+ }
+ break;
+ case ACT_ACTION_FLIPPER:
+ if (bPositiveEvent){
+ if (!(m_flag & ACT_FLAG_LOCKINPUT)){
+ m_flag &= ~ACT_FLAG_REVERSE;
+ m_flag |= ACT_FLAG_LOCKINPUT;
+ SetStartTime(curtime);
+ }
+ }
+ else if (bNegativeEvent){
+ m_flag |= ACT_FLAG_REVERSE;
+ m_flag &= ~ACT_FLAG_LOCKINPUT;
+ SetStartTime(curtime);
+ }
+ break;
+ case ACT_ACTION_PLAY:
+ if (bPositiveEvent){
+ if (!(m_flag & ACT_FLAG_LOCKINPUT)){
+ m_flag &= ~ACT_FLAG_REVERSE;
+ m_localtime = m_starttime;
+ m_starttime = curtime;
+ m_flag |= ACT_FLAG_LOCKINPUT;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Perform increment */
+ if (keepgoing){
+ if (m_playtype == ACT_ACTION_MOTION){
+ MT_Point3 newpos;
+ MT_Point3 deltapos;
+
+ newpos = obj->NodeGetWorldPosition();
+
+ /* Find displacement */
+ deltapos = newpos-m_lastpos;
+ m_localtime += (length/m_stridelength) * deltapos.length();
+ m_lastpos = newpos;
+ }
+ else{
+ SetLocalTime(curtime);
+ }
+ }
+
+ /* Check if a wrapping response is needed */
+ if (length){
+ if (m_localtime < m_startframe || m_localtime > m_endframe)
+ {
+ m_localtime = m_startframe + fmod(m_localtime, length);
+ wrap = true;
+ }
+ }
+ else
+ m_localtime = m_startframe;
+
+ /* Perform post-increment tasks */
+ switch (m_playtype){
+ case ACT_ACTION_FROM_PROP:
+ {
+ CValue* propval = GetParent()->GetProperty(m_propname);
+ if (propval)
+ m_localtime = propval->GetNumber();
+
+ if (bNegativeEvent){
+ keepgoing=false;
+ }
+ }
+ break;
+ case ACT_ACTION_MOTION:
+ break;
+ case ACT_ACTION_LOOP_STOP:
+ break;
+ case ACT_ACTION_FLIPPER:
+ if (wrap){
+ if (!(m_flag & ACT_FLAG_REVERSE)){
+ m_localtime=m_endframe;
+ //keepgoing = false;
+ }
+ else {
+ m_localtime=m_startframe;
+ keepgoing = false;
+ }
+ }
+ break;
+ case ACT_ACTION_LOOP_END:
+ if (wrap){
+ if (m_flag & ACT_FLAG_KEYUP){
+ keepgoing = false;
+ m_localtime = m_endframe;
+ m_flag &= ~ACT_FLAG_LOCKINPUT;
+ }
+ SetStartTime(curtime);
+ }
+ break;
+ case ACT_ACTION_PLAY:
+ if (wrap){
+ m_localtime = m_endframe;
+ keepgoing = false;
+ m_flag &= ~ACT_FLAG_LOCKINPUT;
+ }
+ break;
+ default:
+ keepgoing = false;
+ break;
+ }
+
+
+ if (bNegativeEvent)
+ m_blendframe=0.0f;
+
+ /* Apply the pose if necessary*/
+ if (apply) {
+
+ /* Priority test */
+ if (obj->SetActiveAction(this, priority, curtime)){
+ Key *key = obj->GetKey();
+
+ if (!key) {
+ // this could happen if the mesh was changed in the middle of an action
+ // and the new mesh has no key, stop the action
+ keepgoing = false;
+ }
+ else {
+ ListBase tchanbase= {NULL, NULL};
+
+ if (m_blendin && m_blendframe==0.0f){
+ // this is the start of the blending, remember the startup shape
+ obj->GetShape(m_blendshape);
+ m_blendstart = curtime;
+ }
+ // only interested in shape channel
+ extract_ipochannels_from_action(&tchanbase, &key->id, m_action, "Shape", m_localtime);
+
+ if (!execute_ipochannels(&tchanbase)) {
+ // no update, this is possible if action does not match the keys, stop the action
+ keepgoing = false;
+ }
+ else {
+ // the key have changed, apply blending if needed
+ if (m_blendin && (m_blendframe<m_blendin)){
+ newweight = (m_blendframe/(float)m_blendin);
+
+ BlendShape(key, 1.0f - newweight);
+
+ /* Increment current blending percentage */
+ m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
+ if (m_blendframe>m_blendin)
+ m_blendframe = m_blendin;
+ }
+ m_lastUpdate = m_localtime;
+ }
+ BLI_freelistN(&tchanbase);
+ }
+ }
+ else{
+ m_blendframe = 0.0f;
+ }
+ }
+
+ if (!keepgoing){
+ m_blendframe = 0.0f;
+ }
+ return keepgoing;
+};
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+
+PyTypeObject BL_ShapeActionActuator::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "BL_ShapeActionActuator",
+ sizeof(BL_ShapeActionActuator),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject BL_ShapeActionActuator::Parents[] = {
+ &BL_ShapeActionActuator::Type,
+ &SCA_IActuator::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef BL_ShapeActionActuator::Methods[] = {
+ {"setAction", (PyCFunction) BL_ShapeActionActuator::sPySetAction, METH_VARARGS, SetAction_doc},
+ {"setStart", (PyCFunction) BL_ShapeActionActuator::sPySetStart, METH_VARARGS, SetStart_doc},
+ {"setEnd", (PyCFunction) BL_ShapeActionActuator::sPySetEnd, METH_VARARGS, SetEnd_doc},
+ {"setBlendin", (PyCFunction) BL_ShapeActionActuator::sPySetBlendin, METH_VARARGS, SetBlendin_doc},
+ {"setPriority", (PyCFunction) BL_ShapeActionActuator::sPySetPriority, METH_VARARGS, SetPriority_doc},
+ {"setFrame", (PyCFunction) BL_ShapeActionActuator::sPySetFrame, METH_VARARGS, SetFrame_doc},
+ {"setProperty", (PyCFunction) BL_ShapeActionActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
+ {"setBlendtime", (PyCFunction) BL_ShapeActionActuator::sPySetBlendtime, METH_VARARGS, SetBlendtime_doc},
+
+ {"getAction", (PyCFunction) BL_ShapeActionActuator::sPyGetAction, METH_VARARGS, GetAction_doc},
+ {"getStart", (PyCFunction) BL_ShapeActionActuator::sPyGetStart, METH_VARARGS, GetStart_doc},
+ {"getEnd", (PyCFunction) BL_ShapeActionActuator::sPyGetEnd, METH_VARARGS, GetEnd_doc},
+ {"getBlendin", (PyCFunction) BL_ShapeActionActuator::sPyGetBlendin, METH_VARARGS, GetBlendin_doc},
+ {"getPriority", (PyCFunction) BL_ShapeActionActuator::sPyGetPriority, METH_VARARGS, GetPriority_doc},
+ {"getFrame", (PyCFunction) BL_ShapeActionActuator::sPyGetFrame, METH_VARARGS, GetFrame_doc},
+ {"getProperty", (PyCFunction) BL_ShapeActionActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc},
+ {"getType", (PyCFunction) BL_ShapeActionActuator::sPyGetType, METH_VARARGS, GetType_doc},
+ {"setType", (PyCFunction) BL_ShapeActionActuator::sPySetType, METH_VARARGS, SetType_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* BL_ShapeActionActuator::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_IActuator);
+}
+
+/* setStart */
+char BL_ShapeActionActuator::GetAction_doc[] =
+"getAction()\n"
+"\tReturns a string containing the name of the current action.\n";
+
+PyObject* BL_ShapeActionActuator::PyGetAction(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ if (m_action){
+ result = Py_BuildValue("s", m_action->id.name+2);
+ }
+ else{
+ Py_INCREF(Py_None);
+ result = Py_None;
+ }
+
+ return result;
+}
+
+/* getProperty */
+char BL_ShapeActionActuator::GetProperty_doc[] =
+"getProperty()\n"
+"\tReturns the name of the property to be used in FromProp mode.\n";
+
+PyObject* BL_ShapeActionActuator::PyGetProperty(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ result = Py_BuildValue("s", (const char *)m_propname);
+
+ return result;
+}
+
+/* getFrame */
+char BL_ShapeActionActuator::GetFrame_doc[] =
+"getFrame()\n"
+"\tReturns the current frame number.\n";
+
+PyObject* BL_ShapeActionActuator::PyGetFrame(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ result = Py_BuildValue("f", m_localtime);
+
+ return result;
+}
+
+/* getEnd */
+char BL_ShapeActionActuator::GetEnd_doc[] =
+"getEnd()\n"
+"\tReturns the last frame of the action.\n";
+
+PyObject* BL_ShapeActionActuator::PyGetEnd(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ result = Py_BuildValue("f", m_endframe);
+
+ return result;
+}
+
+/* getStart */
+char BL_ShapeActionActuator::GetStart_doc[] =
+"getStart()\n"
+"\tReturns the starting frame of the action.\n";
+
+PyObject* BL_ShapeActionActuator::PyGetStart(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ result = Py_BuildValue("f", m_startframe);
+
+ return result;
+}
+
+/* getBlendin */
+char BL_ShapeActionActuator::GetBlendin_doc[] =
+"getBlendin()\n"
+"\tReturns the number of interpolation animation frames to be\n"
+"\tgenerated when this actuator is triggered.\n";
+
+PyObject* BL_ShapeActionActuator::PyGetBlendin(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ result = Py_BuildValue("f", m_blendin);
+
+ return result;
+}
+
+/* getPriority */
+char BL_ShapeActionActuator::GetPriority_doc[] =
+"getPriority()\n"
+"\tReturns the priority for this actuator. Actuators with lower\n"
+"\tPriority numbers will override actuators with higher numbers.\n";
+
+PyObject* BL_ShapeActionActuator::PyGetPriority(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ PyObject *result;
+
+ result = Py_BuildValue("i", m_priority);
+
+ return result;
+}
+
+/* setAction */
+char BL_ShapeActionActuator::SetAction_doc[] =
+"setAction(action, (reset))\n"
+"\t - action : The name of the action to set as the current action.\n"
+"\t Should be an action with Shape channels.\n"
+"\t - reset : Optional parameter indicating whether to reset the\n"
+"\t blend timer or not. A value of 1 indicates that the\n"
+"\t timer should be reset. A value of 0 will leave it\n"
+"\t unchanged. If reset is not specified, the timer will"
+"\t be reset.\n";
+
+PyObject* BL_ShapeActionActuator::PySetAction(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ char *string;
+ int reset = 1;
+
+ if (PyArg_ParseTuple(args,"s|i",&string, &reset))
+ {
+ bAction *action;
+
+ action = (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(STR_String(string));
+
+ if (!action){
+ /* NOTE! Throw an exception or something */
+ // printf ("setAction failed: Action not found\n", string);
+ }
+ else{
+ m_action=action;
+ if (reset)
+ m_blendframe = 0.f;
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setStart */
+char BL_ShapeActionActuator::SetStart_doc[] =
+"setStart(start)\n"
+"\t - start : Specifies the starting frame of the animation.\n";
+
+PyObject* BL_ShapeActionActuator::PySetStart(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float start;
+
+ if (PyArg_ParseTuple(args,"f",&start))
+ {
+ m_startframe = start;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setEnd */
+char BL_ShapeActionActuator::SetEnd_doc[] =
+"setEnd(end)\n"
+"\t - end : Specifies the ending frame of the animation.\n";
+
+PyObject* BL_ShapeActionActuator::PySetEnd(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float end;
+
+ if (PyArg_ParseTuple(args,"f",&end))
+ {
+ m_endframe = end;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setBlendin */
+char BL_ShapeActionActuator::SetBlendin_doc[] =
+"setBlendin(blendin)\n"
+"\t - blendin : Specifies the number of frames of animation to generate\n"
+"\t when making transitions between actions.\n";
+
+PyObject* BL_ShapeActionActuator::PySetBlendin(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float blendin;
+
+ if (PyArg_ParseTuple(args,"f",&blendin))
+ {
+ m_blendin = blendin;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setBlendtime */
+char BL_ShapeActionActuator::SetBlendtime_doc[] =
+"setBlendtime(blendtime)\n"
+"\t - blendtime : Allows the script to directly modify the internal timer\n"
+"\t used when generating transitions between actions. This\n"
+"\t parameter must be in the range from 0.0 to 1.0.\n";
+
+PyObject* BL_ShapeActionActuator::PySetBlendtime(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float blendframe;
+
+ if (PyArg_ParseTuple(args,"f",&blendframe))
+ {
+ m_blendframe = blendframe * m_blendin;
+ if (m_blendframe<0.f)
+ m_blendframe = 0.f;
+ if (m_blendframe>m_blendin)
+ m_blendframe = m_blendin;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setPriority */
+char BL_ShapeActionActuator::SetPriority_doc[] =
+"setPriority(priority)\n"
+"\t - priority : Specifies the new priority. Actuators will lower\n"
+"\t priority numbers will override actuators with higher\n"
+"\t numbers.\n";
+
+PyObject* BL_ShapeActionActuator::PySetPriority(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int priority;
+
+ if (PyArg_ParseTuple(args,"i",&priority))
+ {
+ m_priority = priority;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setFrame */
+char BL_ShapeActionActuator::SetFrame_doc[] =
+"setFrame(frame)\n"
+"\t - frame : Specifies the new current frame for the animation\n";
+
+PyObject* BL_ShapeActionActuator::PySetFrame(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float frame;
+
+ if (PyArg_ParseTuple(args,"f",&frame))
+ {
+ m_localtime = frame;
+ if (m_localtime<m_startframe)
+ m_localtime=m_startframe;
+ else if (m_localtime>m_endframe)
+ m_localtime=m_endframe;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* setProperty */
+char BL_ShapeActionActuator::SetProperty_doc[] =
+"setProperty(prop)\n"
+"\t - prop : A string specifying the property name to be used in\n"
+"\t FromProp playback mode.\n";
+
+PyObject* BL_ShapeActionActuator::PySetProperty(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ char *string;
+
+ if (PyArg_ParseTuple(args,"s",&string))
+ {
+ m_propname = string;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* getType */
+char BL_ShapeActionActuator::GetType_doc[] =
+"getType()\n"
+"\tReturns the operation mode of the actuator.\n";
+PyObject* BL_ShapeActionActuator::PyGetType(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ return Py_BuildValue("h", m_playtype);
+}
+
+/* setType */
+char BL_ShapeActionActuator::SetType_doc[] =
+"setType(mode)\n"
+"\t - mode: Play (0), Flipper (2), LoopStop (3), LoopEnd (4) or Property (6)\n"
+"\tSet the operation mode of the actuator.\n";
+PyObject* BL_ShapeActionActuator::PySetType(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ short typeArg;
+
+ if (!PyArg_ParseTuple(args, "h", &typeArg)) {
+ return NULL;
+ }
+
+ switch (typeArg) {
+ case ACT_ACTION_PLAY:
+ case ACT_ACTION_FLIPPER:
+ case ACT_ACTION_LOOP_STOP:
+ case ACT_ACTION_LOOP_END:
+ case ACT_ACTION_FROM_PROP:
+ m_playtype = typeArg;
+ break;
+ default:
+ printf("Invalid type for action actuator: %d\n", typeArg); /* error */
+ }
+
+ Py_Return;
+}
+
diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.h b/source/gameengine/Converter/BL_ShapeActionActuator.h
new file mode 100644
index 00000000000..c4236a5208e
--- /dev/null
+++ b/source/gameengine/Converter/BL_ShapeActionActuator.h
@@ -0,0 +1,133 @@
+/**
+ * $Id: BL_ShapeActionActuator.h 14444 2008-04-16 22:40:48Z hos $
+ *
+ * ***** 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 BL_SHAPEACTIONACTUATOR
+#define BL_SHAPEACTIONACTUATOR
+
+#include "GEN_HashedPtr.h"
+#include "SCA_IActuator.h"
+#include "MT_Point3.h"
+#include <vector>
+
+struct Key;
+class BL_ShapeActionActuator : public SCA_IActuator
+{
+public:
+ Py_Header;
+ BL_ShapeActionActuator(SCA_IObject* gameobj,
+ const STR_String& propname,
+ float starttime,
+ float endtime,
+ struct bAction *action,
+ short playtype,
+ short blendin,
+ short priority,
+ float stride,
+ PyTypeObject* T=&Type)
+ : SCA_IActuator(gameobj,T),
+
+ m_lastpos(0, 0, 0),
+ m_blendframe(0),
+ m_flag(0),
+ m_startframe (starttime),
+ m_endframe(endtime) ,
+ m_starttime(0),
+ m_localtime(starttime),
+ m_lastUpdate(-1),
+ m_blendin(blendin),
+ m_blendstart(0),
+ m_stridelength(stride),
+ m_playtype(playtype),
+ m_priority(priority),
+ m_action(action),
+ m_propname(propname)
+ {
+ };
+ virtual ~BL_ShapeActionActuator();
+ virtual bool Update(double curtime, bool frame);
+ virtual CValue* GetReplica();
+ virtual void ProcessReplica();
+
+ void SetBlendTime (float newtime);
+ void BlendShape(struct Key* key, float weigth);
+
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetAction);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetBlendin);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetPriority);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetStart);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetEnd);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetFrame);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetProperty);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetBlendtime);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetChannel);
+
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,GetAction);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,GetBlendin);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,GetPriority);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,GetStart);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,GetEnd);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,GetFrame);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,GetProperty);
+// KX_PYMETHOD(BL_ActionActuator,GetChannel);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,GetType);
+ KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetType);
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+protected:
+
+ void SetStartTime(float curtime);
+ void SetLocalTime(float curtime);
+ bool ClampLocalTime();
+
+ MT_Point3 m_lastpos;
+ float m_blendframe;
+ int m_flag;
+ /** The frame this action starts */
+ float m_startframe;
+ /** The frame this action ends */
+ float m_endframe;
+ /** The time this action started */
+ float m_starttime;
+ /** The current time of the action */
+ float m_localtime;
+
+ float m_lastUpdate;
+ float m_blendin;
+ float m_blendstart;
+ float m_stridelength;
+ short m_playtype;
+ short m_priority;
+ struct bAction *m_action;
+ STR_String m_propname;
+ vector<float> m_blendshape;
+};
+
+#endif
+
diff --git a/source/gameengine/Converter/BL_ShapeDeformer.cpp b/source/gameengine/Converter/BL_ShapeDeformer.cpp
new file mode 100644
index 00000000000..54b1041c328
--- /dev/null
+++ b/source/gameengine/Converter/BL_ShapeDeformer.cpp
@@ -0,0 +1,125 @@
+/**
+ * $Id: BL_ShapeDeformer.cpp 14444 2008-04-16 22:40:48Z hos $
+ *
+ * ***** 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 WIN32
+#pragma warning (disable : 4786)
+#endif //WIN32
+
+#include "MEM_guardedalloc.h"
+#include "BL_ShapeDeformer.h"
+#include "GEN_Map.h"
+#include "STR_HashedString.h"
+#include "RAS_IPolygonMaterial.h"
+#include "BL_SkinMeshObject.h"
+
+//#include "BL_ArmatureController.h"
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h"
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "BKE_armature.h"
+#include "BKE_action.h"
+#include "BKE_key.h"
+#include "MT_Point3.h"
+
+extern "C"{
+ #include "BKE_lattice.h"
+}
+ #include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#define __NLA_DEFNORMALS
+//#undef __NLA_DEFNORMALS
+
+
+BL_ShapeDeformer::~BL_ShapeDeformer()
+{
+};
+
+RAS_Deformer *BL_ShapeDeformer::GetReplica()
+{
+ BL_ShapeDeformer *result;
+
+ result = new BL_ShapeDeformer(*this);
+ result->ProcessReplica();
+ return result;
+}
+
+void BL_ShapeDeformer::ProcessReplica()
+{
+}
+
+bool BL_ShapeDeformer::Update(void)
+{
+ bool bShapeUpdate = false;
+ bool bSkinUpdate = false;
+
+ /* See if the object shape has changed */
+ if (m_lastShapeUpdate != m_gameobj->GetLastFrame()) {
+ /* the key coefficient have been set already, we just need to blend the keys */
+ Object* blendobj = m_gameobj->GetBlendObject();
+
+ // make sure the vertex weight cache is in line with this object
+ m_pMeshObject->CheckWeightCache(blendobj);
+
+ /* we will blend the key directly in mvert array: it is used by armature as the start position */
+ do_rel_key(0, m_bmesh->totvert, m_bmesh->totvert, (char *)m_bmesh->mvert->co, m_bmesh->key, 0);
+
+ // Don't release the weight array as in Blender, it will most likely be reusable on next frame
+ // The weight array are ultimately deleted when the skin mesh is destroyed
+
+ /* Update the current frame */
+ m_lastShapeUpdate=m_gameobj->GetLastFrame();
+
+ // As we have changed, the mesh, the skin deformer must update as well.
+ // This will force the update
+ BL_SkinDeformer::ForceUpdate();
+ bShapeUpdate = true;
+ }
+ // check for armature deform
+ bSkinUpdate = BL_SkinDeformer::Update();
+
+ if (!bSkinUpdate && bShapeUpdate) {
+ // this means that there is no armature, we still need to copy the vertex to m_transverts
+ // and update the normal (was not done after shape key calculation)
+
+ /* store verts locally */
+ VerifyStorage();
+
+ for (int v =0; v<m_bmesh->totvert; v++)
+ VECCOPY(m_transverts[v], m_bmesh->mvert[v].co);
+
+ RecalcNormals();
+ bSkinUpdate = true;
+ }
+ return bSkinUpdate;
+}
diff --git a/source/gameengine/Converter/BL_ShapeDeformer.h b/source/gameengine/Converter/BL_ShapeDeformer.h
new file mode 100644
index 00000000000..920eae86b7e
--- /dev/null
+++ b/source/gameengine/Converter/BL_ShapeDeformer.h
@@ -0,0 +1,93 @@
+/**
+ * $Id: BL_SkinDeformer.h 14444 2008-04-16 22:40:48Z hos $
+ *
+ * ***** 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 BL_SHAPEDEFORMER
+#define BL_SHAPEDEFORMER
+
+#ifdef WIN32
+#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
+#endif //WIN32
+
+#include "BL_SkinDeformer.h"
+#include "BL_DeformableGameObject.h"
+#include <vector>
+
+
+class BL_ShapeDeformer : public BL_SkinDeformer
+{
+public:
+ virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map)
+ {
+ void **h_obj = (*map)[m_gameobj];
+ if (h_obj){
+ m_gameobj = (BL_DeformableGameObject*)(*h_obj);
+ }
+ else
+ m_gameobj=NULL;
+ // relink the underlying skin deformer
+ BL_SkinDeformer::Relink(map);
+ };
+ BL_ShapeDeformer(BL_DeformableGameObject *gameobj,
+ Object *bmeshobj,
+ BL_SkinMeshObject *mesh)
+ :
+ BL_SkinDeformer(bmeshobj, mesh),
+ m_lastShapeUpdate(-1),
+ m_gameobj(gameobj)
+ {
+ };
+
+ /* this second constructor is needed for making a mesh deformable on the fly. */
+ BL_ShapeDeformer(BL_DeformableGameObject *gameobj,
+ struct Object *bmeshobj_old,
+ struct Object *bmeshobj_new,
+ class BL_SkinMeshObject *mesh,
+ bool release_object,
+ BL_ArmatureObject* arma = NULL)
+ :
+ BL_SkinDeformer(bmeshobj_old, bmeshobj_new, mesh, release_object, arma),
+ m_lastShapeUpdate(-1),
+ m_gameobj(gameobj)
+ {
+ };
+
+ virtual void ProcessReplica();
+ virtual RAS_Deformer *GetReplica();
+ virtual ~BL_ShapeDeformer();
+
+ bool Update (void);
+
+protected:
+ double m_lastShapeUpdate;
+ BL_DeformableGameObject* m_gameobj;
+
+};
+
+#endif
+
diff --git a/source/gameengine/Converter/BL_SkinDeformer.cpp b/source/gameengine/Converter/BL_SkinDeformer.cpp
index 0f884674c09..78fc73f21a1 100644
--- a/source/gameengine/Converter/BL_SkinDeformer.cpp
+++ b/source/gameengine/Converter/BL_SkinDeformer.cpp
@@ -57,6 +57,19 @@ extern "C"{
#define __NLA_DEFNORMALS
//#undef __NLA_DEFNORMALS
+BL_SkinDeformer::BL_SkinDeformer(struct Object *bmeshobj,
+ class BL_SkinMeshObject *mesh,
+ BL_ArmatureObject* arma)
+ : //
+ BL_MeshDeformer(bmeshobj, mesh),
+ m_armobj(arma),
+ m_lastArmaUpdate(-1),
+ m_defbase(&bmeshobj->defbase),
+ m_releaseobject(false)
+{
+ Mat4CpyMat4(m_obmat, bmeshobj->obmat);
+};
+
BL_SkinDeformer::BL_SkinDeformer(
struct Object *bmeshobj_old, // Blender object that owns the new mesh
struct Object *bmeshobj_new, // Blender object that owns the original mesh
@@ -65,25 +78,22 @@ BL_SkinDeformer::BL_SkinDeformer(
BL_ArmatureObject* arma) :
BL_MeshDeformer(bmeshobj_old, mesh),
m_armobj(arma),
- m_lastUpdate(-1),
+ m_lastArmaUpdate(-1),
m_defbase(&bmeshobj_old->defbase),
m_releaseobject(release_object)
{
- Mat4CpyMat4(m_obmat, bmeshobj_old->obmat);
- m_restoremat = true;
// this is needed to ensure correct deformation of mesh:
// the deformation is done with Blender's armature_deform_verts() function
// that takes an object as parameter and not a mesh. The object matrice is used
- // in the calculation, so we must force the same matrice to simulate a pure replacement of mesh
- Mat4CpyMat4(bmeshobj_old->obmat, bmeshobj_new->obmat);
+ // in the calculation, so we must use the matrix of the original object to
+ // simulate a pure replacement of the mesh.
+ Mat4CpyMat4(m_obmat, bmeshobj_new->obmat);
}
BL_SkinDeformer::~BL_SkinDeformer()
{
if(m_releaseobject && m_armobj)
m_armobj->Release();
- if (m_restoremat)
- Mat4CpyMat4(m_objMesh->obmat, m_obmat);
}
bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat)
@@ -98,15 +108,13 @@ bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat)
MT_Point3 pt;
// float co[3];
- if (!m_armobj)
+ if (!Update())
+ // no need to update the cache
return false;
- Update();
-
array = m_pMeshObject->GetVertexCache(mat);
mvarray = m_pMeshObject->GetMVertCache(mat);
diarray = m_pMeshObject->GetDIndexCache(mat);
-
// For each array
for (i=0; i<array.size(); i++) {
// For each vertex
@@ -140,10 +148,11 @@ void BL_SkinDeformer::ProcessReplica()
//void where_is_pose (Object *ob);
//void armature_deform_verts(Object *armOb, Object *target, float (*vertexCos)[3], int numVerts, int deformflag);
-void BL_SkinDeformer::Update(void)
+bool BL_SkinDeformer::Update(void)
{
/* See if the armature has been updated for this frame */
- if (m_lastUpdate!=m_armobj->GetLastFrame()){
+ if (m_armobj && m_lastArmaUpdate!=m_armobj->GetLastFrame()){
+ float obmat[4][4]; // the original object matrice
/* Do all of the posing necessary */
m_armobj->ApplyPose();
@@ -161,14 +170,27 @@ void BL_SkinDeformer::Update(void)
for (int v =0; v<m_bmesh->totvert; v++)
VECCOPY(m_transverts[v], m_bmesh->mvert[v].co);
+ // save matrix first
+ Mat4CpyMat4(obmat, m_objMesh->obmat);
+ // set reference matrix
+ Mat4CpyMat4(m_objMesh->obmat, m_obmat);
+
armature_deform_verts( par_arma, m_objMesh, NULL, m_transverts, NULL, m_bmesh->totvert, ARM_DEF_VGROUP, NULL, NULL );
+
+ // restore matrix
+ Mat4CpyMat4(m_objMesh->obmat, obmat);
+
#ifdef __NLA_DEFNORMALS
RecalcNormals();
#endif
/* Update the current frame */
- m_lastUpdate=m_armobj->GetLastFrame();
+ m_lastArmaUpdate=m_armobj->GetLastFrame();
+
+ /* indicate that the m_transverts and normals are up to date */
+ return true;
}
+ return false;
}
/* XXX note: I propose to drop this function */
diff --git a/source/gameengine/Converter/BL_SkinDeformer.h b/source/gameengine/Converter/BL_SkinDeformer.h
index 79f6453a25d..603e716fb1e 100644
--- a/source/gameengine/Converter/BL_SkinDeformer.h
+++ b/source/gameengine/Converter/BL_SkinDeformer.h
@@ -52,27 +52,20 @@ public:
// void SetArmatureController (BL_ArmatureController *cont);
virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map)
{
- void **h_obj = (*map)[m_armobj];
- if (h_obj){
- SetArmature( (BL_ArmatureObject*)(*h_obj) );
+ if (m_armobj){
+ void **h_obj = (*map)[m_armobj];
+ if (h_obj){
+ SetArmature( (BL_ArmatureObject*)(*h_obj) );
+ }
+ else
+ m_armobj=NULL;
}
- else
- m_armobj=NULL;
}
void SetArmature (class BL_ArmatureObject *armobj);
BL_SkinDeformer(struct Object *bmeshobj,
class BL_SkinMeshObject *mesh,
- BL_ArmatureObject* arma = NULL)
- : //
- BL_MeshDeformer(bmeshobj, mesh),
- m_armobj(arma),
- m_lastUpdate(-1),
- m_defbase(&bmeshobj->defbase),
- m_restoremat(false),
- m_releaseobject(false)
- {
- };
+ BL_ArmatureObject* arma = NULL);
/* this second constructor is needed for making a mesh deformable on the fly. */
BL_SkinDeformer(struct Object *bmeshobj_old,
@@ -84,16 +77,20 @@ public:
virtual void ProcessReplica();
virtual RAS_Deformer *GetReplica();
virtual ~BL_SkinDeformer();
- void Update (void);
+ bool Update (void);
bool Apply (class RAS_IPolyMaterial *polymat);
+ void ForceUpdate()
+ {
+ m_lastArmaUpdate = -1.0;
+ };
+
protected:
BL_ArmatureObject* m_armobj; // Our parent object
float m_time;
- double m_lastUpdate;
+ double m_lastArmaUpdate;
ListBase* m_defbase;
- float m_obmat[4][4]; // the original object matrice in case of dynamic mesh replacement
- bool m_restoremat;
+ float m_obmat[4][4]; // the reference matrix for skeleton deform
bool m_releaseobject;
};
diff --git a/source/gameengine/Converter/BL_SkinMeshObject.cpp b/source/gameengine/Converter/BL_SkinMeshObject.cpp
index 69feb72f5dc..9d3702b53a2 100644
--- a/source/gameengine/Converter/BL_SkinMeshObject.cpp
+++ b/source/gameengine/Converter/BL_SkinMeshObject.cpp
@@ -150,5 +150,63 @@ void BL_SkinMeshObject::Bucketize(double* oglmatrix,void* clientobj,bool useObje
}
+static get_def_index(Object* ob, const char* vgroup)
+{
+ bDeformGroup *curdef;
+ int index = 0;
+
+ for (curdef = (bDeformGroup*)ob->defbase.first; curdef; curdef=(bDeformGroup*)curdef->next, index++)
+ if (!strcmp(curdef->name, vgroup))
+ return index;
+ return -1;
+}
+
+void BL_SkinMeshObject::CheckWeightCache(Object* obj)
+{
+ KeyBlock *kb;
+ int kbindex, defindex;
+ MDeformVert *dvert= NULL;
+ int totvert, i, j;
+ float *weights;
+
+ if (!m_mesh->key)
+ return;
+
+ for(kbindex=0, kb= (KeyBlock*)m_mesh->key->block.first; kb; kb= (KeyBlock*)kb->next, kbindex++)
+ {
+ // first check the cases where the weight must be cleared
+ if (kb->vgroup[0] == 0 ||
+ m_mesh->dvert == NULL ||
+ (defindex = get_def_index(obj, kb->vgroup)) == -1) {
+ if (kb->weights) {
+ MEM_freeN(kb->weights);
+ kb->weights = NULL;
+ }
+ m_cacheWeightIndex[kbindex] = -1;
+ } else if (m_cacheWeightIndex[kbindex] != defindex) {
+ // a weight array is required but the cache is not matching
+ if (kb->weights) {
+ MEM_freeN(kb->weights);
+ kb->weights = NULL;
+ }
+
+ dvert= m_mesh->dvert;
+ totvert= m_mesh->totvert;
+
+ weights= (float*)MEM_callocN(totvert*sizeof(float), "weights");
+
+ for (i=0; i < totvert; i++, dvert++) {
+ for(j=0; j<dvert->totweight; j++) {
+ if (dvert->dw[j].def_nr == defindex) {
+ weights[i]= dvert->dw[j].weight;
+ break;
+ }
+ }
+ }
+ kb->weights = weights;
+ m_cacheWeightIndex[kbindex] = defindex;
+ }
+ }
+}
diff --git a/source/gameengine/Converter/BL_SkinMeshObject.h b/source/gameengine/Converter/BL_SkinMeshObject.h
index 2422d4cd4c9..cc2b8de600e 100644
--- a/source/gameengine/Converter/BL_SkinMeshObject.h
+++ b/source/gameengine/Converter/BL_SkinMeshObject.h
@@ -33,7 +33,7 @@
#ifdef WIN32
#pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning
#endif //WIN32
-
+#include "MEM_guardedalloc.h"
#include "RAS_MeshObject.h"
#include "RAS_Deformer.h"
#include "RAS_IPolygonMaterial.h"
@@ -41,6 +41,7 @@
#include "BL_MeshDeformer.h"
#include "DNA_mesh_types.h"
+#include "DNA_key_types.h"
#include "DNA_meshdata_types.h"
typedef vector<struct MVert*> BL_MVertArray;
@@ -105,6 +106,8 @@ class BL_SkinMeshObject : public RAS_MeshObject
}
protected:
+ vector<int> m_cacheWeightIndex;
+
public:
struct BL_MDVertMap { RAS_IPolyMaterial *mat; int index; };
vector<vector<BL_MDVertMap> > m_mvert_to_dvert_mapping;
@@ -113,10 +116,33 @@ public:
// void Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec,class RAS_BucketManager* bucketmgr);
int FindVertexArray(int numverts,RAS_IPolyMaterial* polymat);
- BL_SkinMeshObject(int lightlayer) : RAS_MeshObject (lightlayer)
- { m_class = 1;};
+ BL_SkinMeshObject(Mesh* mesh, int lightlayer) : RAS_MeshObject (mesh, lightlayer)
+ {
+ m_class = 1;
+ if (m_mesh && m_mesh->key)
+ {
+ KeyBlock *kb;
+ int count=0;
+ // initialize weight cache for shape objects
+ // count how many keys in this mesh
+ for(kb= (KeyBlock*)m_mesh->key->block.first; kb; kb= (KeyBlock*)kb->next)
+ count++;
+ m_cacheWeightIndex.resize(count,-1);
+ }
+ };
- virtual ~BL_SkinMeshObject(){
+ virtual ~BL_SkinMeshObject()
+ {
+ if (m_mesh && m_mesh->key)
+ {
+ KeyBlock *kb;
+ // remove the weight cache to avoid memory leak
+ for(kb= (KeyBlock*)m_mesh->key->block.first; kb; kb= (KeyBlock*)kb->next) {
+ if(kb->weights)
+ MEM_freeN(kb->weights);
+ kb->weights= NULL;
+ }
+ }
};
const vecIndexArrays& GetDIndexCache (RAS_IPolyMaterial* mat)
@@ -154,6 +180,8 @@ public:
return index;
}
+ // for shape keys,
+ void CheckWeightCache(struct Object* obj);
};
diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp
index 6b594e2e70b..f219c3a1472 100644
--- a/source/gameengine/Converter/KX_ConvertActuators.cpp
+++ b/source/gameengine/Converter/KX_ConvertActuators.cpp
@@ -84,6 +84,7 @@
#include "DNA_actuator_types.h"
#include "DNA_packedFile_types.h"
#include "BL_ActionActuator.h"
+#include "BL_ShapeActionActuator.h"
/* end of blender include block */
#include "BL_BlenderDataConversion.h"
@@ -195,6 +196,30 @@ void BL_ConvertActuators(char* maggiename,
else
printf ("Discarded action actuator from non-armature object [%s]\n", blenderobject->id.name+2);
}
+ case ACT_SHAPEACTION:
+ {
+ if (blenderobject->type==OB_MESH){
+ bActionActuator* actact = (bActionActuator*) bact->data;
+ STR_String propname = (actact->name ? actact->name : "");
+
+ BL_ShapeActionActuator* tmpbaseact = new BL_ShapeActionActuator(
+ gameobj,
+ propname,
+ actact->sta,
+ actact->end,
+ actact->act,
+ actact->type, // + 1, because Blender starts to count at zero,
+ actact->blendin,
+ actact->priority,
+ actact->stridelength
+ // Ketsji at 1, because zero is reserved for "NoDef"
+ );
+ baseact= tmpbaseact;
+ break;
+ }
+ else
+ printf ("Discarded shape action actuator from non-mesh object [%s]\n", blenderobject->id.name+2);
+ }
case ACT_IPO:
{
bIpoActuator* ipoact = (bIpoActuator*) bact->data;