diff options
Diffstat (limited to 'source/gameengine/Converter')
30 files changed, 3631 insertions, 1304 deletions
diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index 1055c8771ef..4d748948c27 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -49,6 +49,8 @@ #include "BLI_arithb.h" #include "MT_Matrix4x4.h" #include "BKE_utildefines.h" +#include "FloatValue.h" +#include "PyObjectPlus.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -56,24 +58,12 @@ BL_ActionActuator::~BL_ActionActuator() { - - if (m_pose) { - free_pose_channels(m_pose); - MEM_freeN(m_pose); - m_pose = NULL; - }; - - if (m_userpose){ - free_pose_channels(m_userpose); - MEM_freeN(m_userpose); - m_userpose=NULL; - } - if (m_blendpose) { - free_pose_channels(m_blendpose); - MEM_freeN(m_blendpose); - m_blendpose = NULL; - }; - + if (m_pose) + game_free_pose(m_pose); + if (m_userpose) + game_free_pose(m_userpose); + if (m_blendpose) + game_free_pose(m_blendpose); } void BL_ActionActuator::ProcessReplica(){ @@ -134,14 +124,14 @@ void BL_ActionActuator::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_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 BL_ActionActuator::SetLocalTime(float curtime) { - float delta_time = (curtime - m_starttime)*KX_FIXED_FRAME_PER_SEC; + float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate(); if (m_endframe < m_startframe) delta_time = -delta_time; @@ -162,6 +152,8 @@ bool BL_ActionActuator::Update(double curtime, bool frame) bool apply=true; int priority; float newweight; + + curtime -= KX_KetsjiEngine::GetSuspendedDelta(); // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! @@ -183,6 +175,11 @@ bool BL_ActionActuator::Update(double curtime, bool frame) if (bNegativeEvent) { + // dont continue where we left off when restarting + if (m_end_reset) { + m_flag &= ~ACT_FLAG_LOCKINPUT; + } + if (!(m_flag & ACT_FLAG_ACTIVE)) return false; m_flag &= ~ACT_FLAG_ACTIVE; @@ -348,6 +345,18 @@ bool BL_ActionActuator::Update(double curtime, bool frame) break; } + /* Set the property if its defined */ + if (m_framepropname[0] != '\0') { + CValue* propowner = GetParent(); + CValue* oldprop = propowner->GetProperty(m_framepropname); + CValue* newval = new CFloatValue(m_localtime); + if (oldprop) { + oldprop->SetValue(newval); + } else { + propowner->SetProperty(m_framepropname, newval); + } + newval->Release(); + } if (bNegativeEvent) m_blendframe=0.0; @@ -385,7 +394,7 @@ bool BL_ActionActuator::Update(double curtime, bool frame) blend_poses(m_pose, m_blendpose, 1.0 - newweight, ACTSTRIPMODE_BLEND); /* Increment current blending percentage */ - m_blendframe = (curtime - m_blendstart)*KX_FIXED_FRAME_PER_SEC; + m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate(); if (m_blendframe>m_blendin) m_blendframe = m_blendin; @@ -439,26 +448,30 @@ PyParentObject BL_ActionActuator::Parents[] = { }; PyMethodDef BL_ActionActuator::Methods[] = { - {"setAction", (PyCFunction) BL_ActionActuator::sPySetAction, METH_VARARGS, SetAction_doc}, - {"setStart", (PyCFunction) BL_ActionActuator::sPySetStart, METH_VARARGS, SetStart_doc}, - {"setEnd", (PyCFunction) BL_ActionActuator::sPySetEnd, METH_VARARGS, SetEnd_doc}, - {"setBlendin", (PyCFunction) BL_ActionActuator::sPySetBlendin, METH_VARARGS, SetBlendin_doc}, - {"setPriority", (PyCFunction) BL_ActionActuator::sPySetPriority, METH_VARARGS, SetPriority_doc}, - {"setFrame", (PyCFunction) BL_ActionActuator::sPySetFrame, METH_VARARGS, SetFrame_doc}, - {"setProperty", (PyCFunction) BL_ActionActuator::sPySetProperty, METH_VARARGS, SetProperty_doc}, - {"setBlendtime", (PyCFunction) BL_ActionActuator::sPySetBlendtime, METH_VARARGS, SetBlendtime_doc}, - - {"getAction", (PyCFunction) BL_ActionActuator::sPyGetAction, METH_VARARGS, GetAction_doc}, - {"getStart", (PyCFunction) BL_ActionActuator::sPyGetStart, METH_VARARGS, GetStart_doc}, - {"getEnd", (PyCFunction) BL_ActionActuator::sPyGetEnd, METH_VARARGS, GetEnd_doc}, - {"getBlendin", (PyCFunction) BL_ActionActuator::sPyGetBlendin, METH_VARARGS, GetBlendin_doc}, - {"getPriority", (PyCFunction) BL_ActionActuator::sPyGetPriority, METH_VARARGS, GetPriority_doc}, - {"getFrame", (PyCFunction) BL_ActionActuator::sPyGetFrame, METH_VARARGS, GetFrame_doc}, - {"getProperty", (PyCFunction) BL_ActionActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc}, - {"setChannel", (PyCFunction) BL_ActionActuator::sPySetChannel, METH_VARARGS, SetChannel_doc}, + {"setAction", (PyCFunction) BL_ActionActuator::sPySetAction, METH_VARARGS, (PY_METHODCHAR)SetAction_doc}, + {"setStart", (PyCFunction) BL_ActionActuator::sPySetStart, METH_VARARGS, (PY_METHODCHAR)SetStart_doc}, + {"setEnd", (PyCFunction) BL_ActionActuator::sPySetEnd, METH_VARARGS, (PY_METHODCHAR)SetEnd_doc}, + {"setBlendin", (PyCFunction) BL_ActionActuator::sPySetBlendin, METH_VARARGS, (PY_METHODCHAR)SetBlendin_doc}, + {"setPriority", (PyCFunction) BL_ActionActuator::sPySetPriority, METH_VARARGS, (PY_METHODCHAR)SetPriority_doc}, + {"setFrame", (PyCFunction) BL_ActionActuator::sPySetFrame, METH_VARARGS, (PY_METHODCHAR)SetFrame_doc}, + {"setProperty", (PyCFunction) BL_ActionActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, + {"setFrameProperty", (PyCFunction) BL_ActionActuator::sPySetFrameProperty, METH_VARARGS, (PY_METHODCHAR)SetFrameProperty_doc}, + {"setBlendtime", (PyCFunction) BL_ActionActuator::sPySetBlendtime, METH_VARARGS, (PY_METHODCHAR)SetBlendtime_doc}, + + {"getAction", (PyCFunction) BL_ActionActuator::sPyGetAction, METH_VARARGS, (PY_METHODCHAR)GetAction_doc}, + {"getStart", (PyCFunction) BL_ActionActuator::sPyGetStart, METH_VARARGS, (PY_METHODCHAR)GetStart_doc}, + {"getEnd", (PyCFunction) BL_ActionActuator::sPyGetEnd, METH_VARARGS, (PY_METHODCHAR)GetEnd_doc}, + {"getBlendin", (PyCFunction) BL_ActionActuator::sPyGetBlendin, METH_VARARGS, (PY_METHODCHAR)GetBlendin_doc}, + {"getPriority", (PyCFunction) BL_ActionActuator::sPyGetPriority, METH_VARARGS, (PY_METHODCHAR)GetPriority_doc}, + {"getFrame", (PyCFunction) BL_ActionActuator::sPyGetFrame, METH_VARARGS, (PY_METHODCHAR)GetFrame_doc}, + {"getProperty", (PyCFunction) BL_ActionActuator::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc}, + {"getFrameProperty", (PyCFunction) BL_ActionActuator::sPyGetFrameProperty, METH_VARARGS, (PY_METHODCHAR)GetFrameProperty_doc}, + {"setChannel", (PyCFunction) BL_ActionActuator::sPySetChannel, METH_VARARGS, (PY_METHODCHAR)SetChannel_doc}, // {"getChannel", (PyCFunction) BL_ActionActuator::sPyGetChannel, METH_VARARGS}, - {"getType", (PyCFunction) BL_ActionActuator::sPyGetType, METH_VARARGS, GetType_doc}, - {"setType", (PyCFunction) BL_ActionActuator::sPySetType, METH_VARARGS, SetType_doc}, + {"getType", (PyCFunction) BL_ActionActuator::sPyGetType, METH_VARARGS, (PY_METHODCHAR)GetType_doc}, + {"setType", (PyCFunction) BL_ActionActuator::sPySetType, METH_VARARGS, (PY_METHODCHAR)SetType_doc}, + {"getContinue", (PyCFunction) BL_ActionActuator::sPyGetContinue, METH_NOARGS, 0}, + {"setContinue", (PyCFunction) BL_ActionActuator::sPySetContinue, METH_O, 0}, {NULL,NULL} //Sentinel }; @@ -467,28 +480,21 @@ PyObject* BL_ActionActuator::_getattr(const STR_String& attr) { } /* setStart */ -char BL_ActionActuator::GetAction_doc[] = +const char BL_ActionActuator::GetAction_doc[] = "getAction()\n" "\tReturns a string containing the name of the current action.\n"; PyObject* BL_ActionActuator::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 PyString_FromString(m_action->id.name+2); } - - return result; + Py_RETURN_NONE; } /* getProperty */ -char BL_ActionActuator::GetProperty_doc[] = +const char BL_ActionActuator::GetProperty_doc[] = "getProperty()\n" "\tReturns the name of the property to be used in FromProp mode.\n"; @@ -502,8 +508,23 @@ PyObject* BL_ActionActuator::PyGetProperty(PyObject* self, return result; } +/* getProperty */ +const char BL_ActionActuator::GetFrameProperty_doc[] = +"getFrameProperty()\n" +"\tReturns the name of the property, that is set to the current frame number.\n"; + +PyObject* BL_ActionActuator::PyGetFrameProperty(PyObject* self, + PyObject* args, + PyObject* kwds) { + PyObject *result; + + result = Py_BuildValue("s", (const char *)m_framepropname); + + return result; +} + /* getFrame */ -char BL_ActionActuator::GetFrame_doc[] = +const char BL_ActionActuator::GetFrame_doc[] = "getFrame()\n" "\tReturns the current frame number.\n"; @@ -518,7 +539,7 @@ PyObject* BL_ActionActuator::PyGetFrame(PyObject* self, } /* getEnd */ -char BL_ActionActuator::GetEnd_doc[] = +const char BL_ActionActuator::GetEnd_doc[] = "getEnd()\n" "\tReturns the last frame of the action.\n"; @@ -533,7 +554,7 @@ PyObject* BL_ActionActuator::PyGetEnd(PyObject* self, } /* getStart */ -char BL_ActionActuator::GetStart_doc[] = +const char BL_ActionActuator::GetStart_doc[] = "getStart()\n" "\tReturns the starting frame of the action.\n"; @@ -548,7 +569,7 @@ PyObject* BL_ActionActuator::PyGetStart(PyObject* self, } /* getBlendin */ -char BL_ActionActuator::GetBlendin_doc[] = +const char BL_ActionActuator::GetBlendin_doc[] = "getBlendin()\n" "\tReturns the number of interpolation animation frames to be\n" "\tgenerated when this actuator is triggered.\n"; @@ -564,7 +585,7 @@ PyObject* BL_ActionActuator::PyGetBlendin(PyObject* self, } /* getPriority */ -char BL_ActionActuator::GetPriority_doc[] = +const char BL_ActionActuator::GetPriority_doc[] = "getPriority()\n" "\tReturns the priority for this actuator. Actuators with lower\n" "\tPriority numbers will override actuators with higher numbers.\n"; @@ -580,7 +601,7 @@ PyObject* BL_ActionActuator::PyGetPriority(PyObject* self, } /* setAction */ -char BL_ActionActuator::SetAction_doc[] = +const char BL_ActionActuator::SetAction_doc[] = "setAction(action, (reset))\n" "\t - action : The name of the action to set as the current action.\n" "\t - reset : Optional parameter indicating whether to reset the\n" @@ -611,13 +632,15 @@ PyObject* BL_ActionActuator::PySetAction(PyObject* self, m_blendframe = 0; } } + else { + return NULL; + } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } /* setStart */ -char BL_ActionActuator::SetStart_doc[] = +const char BL_ActionActuator::SetStart_doc[] = "setStart(start)\n" "\t - start : Specifies the starting frame of the animation.\n"; @@ -630,13 +653,15 @@ PyObject* BL_ActionActuator::PySetStart(PyObject* self, { m_startframe = start; } + else { + return NULL; + } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } /* setEnd */ -char BL_ActionActuator::SetEnd_doc[] = +const char BL_ActionActuator::SetEnd_doc[] = "setEnd(end)\n" "\t - end : Specifies the ending frame of the animation.\n"; @@ -649,13 +674,15 @@ PyObject* BL_ActionActuator::PySetEnd(PyObject* self, { m_endframe = end; } + else { + return NULL; + } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } /* setBlendin */ -char BL_ActionActuator::SetBlendin_doc[] = +const char BL_ActionActuator::SetBlendin_doc[] = "setBlendin(blendin)\n" "\t - blendin : Specifies the number of frames of animation to generate\n" "\t when making transitions between actions.\n"; @@ -669,13 +696,15 @@ PyObject* BL_ActionActuator::PySetBlendin(PyObject* self, { m_blendin = blendin; } + else { + return NULL; + } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } /* setBlendtime */ -char BL_ActionActuator::SetBlendtime_doc[] = +const char BL_ActionActuator::SetBlendtime_doc[] = "setBlendtime(blendtime)\n" "\t - blendtime : Allows the script to directly modify the internal timer\n" "\t used when generating transitions between actions. This\n" @@ -694,13 +723,15 @@ PyObject* BL_ActionActuator::PySetBlendtime(PyObject* self, if (m_blendframe>m_blendin) m_blendframe = m_blendin; } + else { + return NULL; + } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } /* setPriority */ -char BL_ActionActuator::SetPriority_doc[] = +const char BL_ActionActuator::SetPriority_doc[] = "setPriority(priority)\n" "\t - priority : Specifies the new priority. Actuators will lower\n" "\t priority numbers will override actuators with higher\n" @@ -715,13 +746,15 @@ PyObject* BL_ActionActuator::PySetPriority(PyObject* self, { m_priority = priority; } + else { + return NULL; + } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } /* setFrame */ -char BL_ActionActuator::SetFrame_doc[] = +const char BL_ActionActuator::SetFrame_doc[] = "setFrame(frame)\n" "\t - frame : Specifies the new current frame for the animation\n"; @@ -738,13 +771,15 @@ PyObject* BL_ActionActuator::PySetFrame(PyObject* self, else if (m_localtime>m_endframe) m_localtime=m_endframe; } + else { + return NULL; + } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } /* setProperty */ -char BL_ActionActuator::SetProperty_doc[] = +const char BL_ActionActuator::SetProperty_doc[] = "setProperty(prop)\n" "\t - prop : A string specifying the property name to be used in\n" "\t FromProp playback mode.\n"; @@ -758,9 +793,32 @@ PyObject* BL_ActionActuator::PySetProperty(PyObject* self, { m_propname = string; } + else { + return NULL; + } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; +} + +/* setFrameProperty */ +const char BL_ActionActuator::SetFrameProperty_doc[] = +"setFrameProperty(prop)\n" +"\t - prop : A string specifying the property of the frame set up update.\n"; + +PyObject* BL_ActionActuator::PySetFrameProperty(PyObject* self, + PyObject* args, + PyObject* kwds) { + char *string; + + if (PyArg_ParseTuple(args,"s",&string)) + { + m_framepropname = string; + } + else { + return NULL; + } + + Py_RETURN_NONE; } /* @@ -773,14 +831,16 @@ PyObject* BL_ActionActuator::PyGetChannel(PyObject* self, { m_propname = string; } + else { + return NULL; + } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } */ /* setChannel */ -char BL_ActionActuator::SetChannel_doc[] = +const char BL_ActionActuator::SetChannel_doc[] = "setChannel(channel, matrix)\n" "\t - channel : A string specifying the name of the bone channel.\n" "\t - matrix : A 4x4 matrix specifying the overriding transformation\n" @@ -797,7 +857,8 @@ PyObject* BL_ActionActuator::PySetChannel(PyObject* self, int row,col; int mode = 0; /* 0 for bone space, 1 for armature/world space */ - PyArg_ParseTuple(args,"sO|i", &string, &pylist, &mode); + if (!PyArg_ParseTuple(args,"sO|i", &string, &pylist, &mode)) + return NULL; if (pylist->ob_type == &CListValue::Type) { @@ -859,12 +920,11 @@ PyObject* BL_ActionActuator::PySetChannel(PyObject* self, } } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } /* getType */ -char BL_ActionActuator::GetType_doc[] = +const char BL_ActionActuator::GetType_doc[] = "getType()\n" "\tReturns the operation mode of the actuator.\n"; PyObject* BL_ActionActuator::PyGetType(PyObject* self, @@ -874,7 +934,7 @@ PyObject* BL_ActionActuator::PyGetType(PyObject* self, } /* setType */ -char BL_ActionActuator::SetType_doc[] = +const char BL_ActionActuator::SetType_doc[] = "setType(mode)\n" "\t - mode: Play (0), Flipper (2), LoopStop (3), LoopEnd (4) or Property (6)\n" "\tSet the operation mode of the actuator.\n"; @@ -898,7 +958,26 @@ PyObject* BL_ActionActuator::PySetType(PyObject* self, default: printf("Invalid type for action actuator: %d\n", typeArg); /* error */ } + Py_RETURN_NONE; +} + +PyObject* BL_ActionActuator::PyGetContinue(PyObject* self) { + return PyInt_FromLong((long)(m_end_reset==0)); +} + +PyObject* BL_ActionActuator::PySetContinue(PyObject* self, PyObject* value) { + int param = PyObject_IsTrue( value ); - Py_Return; + if( param == -1 ) { + PyErr_SetString( PyExc_TypeError, "expected True/False or 0/1" ); + return NULL; + } + + if (param) { + m_end_reset = 0; + } else { + m_end_reset = 1; + } + Py_RETURN_NONE; } diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h index 62edcc7fad7..a67b6d29b74 100644 --- a/source/gameengine/Converter/BL_ActionActuator.h +++ b/source/gameengine/Converter/BL_ActionActuator.h @@ -40,12 +40,14 @@ public: Py_Header; BL_ActionActuator(SCA_IObject* gameobj, const STR_String& propname, + const STR_String& framepropname, float starttime, float endtime, struct bAction *action, short playtype, short blendin, short priority, + short end_reset, float stride, PyTypeObject* T=&Type) : SCA_IActuator(gameobj,T), @@ -63,11 +65,13 @@ public: m_stridelength(stride), m_playtype(playtype), m_priority(priority), + m_end_reset(end_reset), m_pose(NULL), m_blendpose(NULL), m_userpose(NULL), m_action(action), - m_propname(propname) + m_propname(propname), + m_framepropname(framepropname) { }; virtual ~BL_ActionActuator(); @@ -84,6 +88,7 @@ public: KX_PYMETHOD_DOC(BL_ActionActuator,SetEnd); KX_PYMETHOD_DOC(BL_ActionActuator,SetFrame); KX_PYMETHOD_DOC(BL_ActionActuator,SetProperty); + KX_PYMETHOD_DOC(BL_ActionActuator,SetFrameProperty); KX_PYMETHOD_DOC(BL_ActionActuator,SetBlendtime); KX_PYMETHOD_DOC(BL_ActionActuator,SetChannel); @@ -94,9 +99,12 @@ public: KX_PYMETHOD_DOC(BL_ActionActuator,GetEnd); KX_PYMETHOD_DOC(BL_ActionActuator,GetFrame); KX_PYMETHOD_DOC(BL_ActionActuator,GetProperty); + KX_PYMETHOD_DOC(BL_ActionActuator,GetFrameProperty); // KX_PYMETHOD(BL_ActionActuator,GetChannel); KX_PYMETHOD_DOC(BL_ActionActuator,GetType); KX_PYMETHOD_DOC(BL_ActionActuator,SetType); + KX_PYMETHOD_NOARGS(BL_ActionActuator,GetContinue); + KX_PYMETHOD_O(BL_ActionActuator,SetContinue); virtual PyObject* _getattr(const STR_String& attr); @@ -133,11 +141,13 @@ protected: float m_stridelength; short m_playtype; short m_priority; + short m_end_reset; struct bPose* m_pose; struct bPose* m_blendpose; struct bPose* m_userpose; struct bAction *m_action; STR_String m_propname; + STR_String m_framepropname; }; enum { diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index ff9c6a75aa9..d2001212f7d 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -45,7 +45,6 @@ #include <config.h> #endif - BL_ArmatureObject::BL_ArmatureObject( void* sgReplicationInfo, SG_Callbacks callbacks, @@ -53,15 +52,20 @@ BL_ArmatureObject::BL_ArmatureObject( : KX_GameObject(sgReplicationInfo,callbacks), m_objArma(armature), - m_mrdPose(NULL), - m_lastframe(0.), + m_framePose(NULL), + m_lastframe(0.0), m_activeAct(NULL), - m_activePriority(999) + m_activePriority(999), + m_lastapplyframe(0.0) { m_armature = get_armature(m_objArma); - m_pose = m_objArma->pose; -} + /* we make a copy of blender object's pose, and then always swap it with + * the original pose before calling into blender functions, to deal with + * replica's or other objects using the same blender object */ + m_pose = NULL; + game_copy_pose(&m_pose, m_objArma->pose); +} CValue* BL_ArmatureObject::GetReplica() { @@ -78,35 +82,37 @@ void BL_ArmatureObject::ProcessReplica(BL_ArmatureObject *replica) { KX_GameObject::ProcessReplica(replica); + replica->m_pose = NULL; + game_copy_pose(&replica->m_pose, m_pose); } BL_ArmatureObject::~BL_ArmatureObject() { - if (m_mrdPose){ - free_pose_channels(m_mrdPose); - MEM_freeN(m_mrdPose); - } + if (m_pose) + game_free_pose(m_pose); } -/* note, you can only call this for exisiting Armature objects, and not mix it with other Armatures */ -/* there is only 1 unique Pose per Armature */ void BL_ArmatureObject::ApplyPose() { - if (m_pose){ - // copy to armature object - extract_pose_from_pose(m_objArma->pose, m_pose); - - // is this needed anymore? - //if (!m_mrdPose) - // copy_pose (&m_mrdPose, m_pose, 0); - //else - // extract_pose_from_pose(m_mrdPose, m_pose); + m_armpose = m_objArma->pose; + m_objArma->pose = m_pose; + + if(m_lastapplyframe != m_lastframe) { + where_is_pose(m_objArma); + m_lastapplyframe = m_lastframe; } } +void BL_ArmatureObject::RestorePose() +{ + m_objArma->pose = m_armpose; + m_armpose = NULL; +} + void BL_ArmatureObject::SetPose(bPose *pose) { - m_pose = pose; + extract_pose_from_pose(m_pose, pose); + m_lastapplyframe = -1.0; } bool BL_ArmatureObject::SetActiveAction(BL_ActionActuator *act, short priority, double curtime) @@ -115,10 +121,15 @@ bool BL_ArmatureObject::SetActiveAction(BL_ActionActuator *act, short priority, m_activePriority = 9999; m_lastframe= curtime; m_activeAct = NULL; + // remember the pose at the start of the frame + m_framePose = m_pose; } if (priority<=m_activePriority) { + if (priority<m_activePriority) + // this action overwrites the previous ones, start from initial pose to cancel their effects + m_pose = m_framePose; if (m_activeAct && (m_activeAct!=act)) m_activeAct->SetBlendTime(0.0); /* Reset the blend timer */ m_activeAct = act; @@ -143,19 +154,22 @@ void BL_ArmatureObject::GetPose(bPose **pose) { /* If the caller supplies a null pose, create a new one. */ /* Otherwise, copy the armature's pose channels into the caller-supplied pose */ - + if (!*pose) { /* probably not to good of an idea to duplicate everying, but it clears up a crash and memory leakage when &BL_ActionActuator::m_pose is freed */ - int copy_constraint_channels_hack = 1; - copy_pose(pose, m_pose, copy_constraint_channels_hack); + game_copy_pose(pose, m_pose); } - else - extract_pose_from_pose(*pose, m_pose); + else { + if (*pose == m_pose) + // no need to copy if the pointers are the same + return; + extract_pose_from_pose(*pose, m_pose); + } } void BL_ArmatureObject::GetMRDPose(bPose **pose) @@ -163,16 +177,10 @@ void BL_ArmatureObject::GetMRDPose(bPose **pose) /* If the caller supplies a null pose, create a new one. */ /* Otherwise, copy the armature's pose channels into the caller-supplied pose */ - // is this needed anymore? - //if (!m_mrdPose){ - // copy_pose (&m_mrdPose, m_pose, 0); - //} - if (!*pose) - copy_pose(pose, m_objArma->pose, 0); + game_copy_pose(pose, m_pose); else - extract_pose_from_pose(*pose, m_objArma->pose); - + extract_pose_from_pose(*pose, m_pose); } short BL_ArmatureObject::GetActivePriority() @@ -185,17 +193,17 @@ double BL_ArmatureObject::GetLastFrame() return m_lastframe; } -bool BL_ArmatureObject::GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix) const +bool BL_ArmatureObject::GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix) { - Object* par_arma = m_objArma; - where_is_pose(par_arma); - bPoseChannel *pchan= get_pose_channel(par_arma->pose, bone->name); + bPoseChannel *pchan; - if(pchan) { + ApplyPose(); + pchan = get_pose_channel(m_objArma->pose, bone->name); + if(pchan) matrix.setValue(&pchan->pose_mat[0][0]); - return true; - } - return false; + RestorePose(); + + return (pchan != NULL); } float BL_ArmatureObject::GetBoneLength(Bone* bone) const diff --git a/source/gameengine/Converter/BL_ArmatureObject.h b/source/gameengine/Converter/BL_ArmatureObject.h index 752bd5eb365..d68e37d9e37 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.h +++ b/source/gameengine/Converter/BL_ArmatureObject.h @@ -59,7 +59,10 @@ public: void GetMRDPose(struct bPose **pose); void GetPose(struct bPose **pose); void SetPose (struct bPose *pose); + void ApplyPose(); + void RestorePose(); + bool SetActiveAction(class BL_ActionActuator *act, short priority, double curtime); struct bArmature * GetArmature() { return m_armature; } @@ -69,7 +72,7 @@ public: /// Retrieve the pose matrix for the specified bone. /// Returns true on success. - bool GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix) const; + bool GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix); /// Returns the bone length. The end of the bone is in the local y direction. float GetBoneLength(Bone* bone) const; @@ -79,10 +82,13 @@ protected: Object *m_objArma; struct bArmature *m_armature; struct bPose *m_pose; - struct bPose *m_mrdPose; + struct bPose *m_armpose; + struct bPose *m_framePose; double m_lastframe; class BL_ActionActuator *m_activeAct; short m_activePriority; + + double m_lastapplyframe; }; #endif diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index f04aa2eac16..dc2a14e1793 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -87,7 +87,10 @@ #include "DNA_action_types.h" #include "BKE_main.h" #include "BKE_global.h" +#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" @@ -126,6 +129,7 @@ #include "DNA_sound_types.h" #include "DNA_key_types.h" #include "DNA_armature_types.h" +#include "DNA_object_force.h" #include "MEM_guardedalloc.h" #include "BKE_utildefines.h" @@ -133,8 +137,12 @@ #include "BKE_mesh.h" #include "MT_Point3.h" +#include "BLI_arithb.h" + extern "C" { - #include "BKE_customdata.h" +#include "BKE_customdata.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_DerivedMesh.h" } #include "BKE_material.h" /* give_current_material */ @@ -221,15 +229,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; } } @@ -300,38 +309,40 @@ static void GetRGB(short type, typedef struct MTF_localLayer { MTFace *face; - char *name; + const char *name; }MTF_localLayer; // ------------------------------------ BL_Material* ConvertMaterial( - Mesh* mesh, Material *mat, MTFace* tface, + const char *tfaceName, MFace* mface, MCol* mmcol, int lightlayer, Object* blenderobj, - MTF_localLayer *layers) + MTF_localLayer *layers, + bool glslmat) { //this needs some type of manager BL_Material *material = new BL_Material(); - int numchan = -1; + int numchan = -1, texalpha = 0; bool validmat = (mat!=0); - bool validface = (mesh->mtface && tface); + bool validface = (tface!=0); short type = 0; if( validmat ) type = 1; // material color material->IdMode = DEFAULT_BLENDER; + material->glslmat = (validmat)? glslmat: false; // -------------------------------- if(validmat) { // use vertex colors by explicitly setting - if(mat->mode &MA_VERTEXCOLP) + if(mat->mode &MA_VERTEXCOLP || glslmat) type = 0; // use lighting? @@ -361,12 +372,14 @@ BL_Material* ConvertMaterial( if(i==0 && facetex ) { Image*tmp = (Image*)(tface->tpage); + if(tmp) { material->img[i] = tmp; material->texname[i] = material->img[i]->id.name; material->flag[i] |= ( tface->transp &TF_ALPHA )?USEALPHA:0; material->flag[i] |= ( tface->transp &TF_ADD )?CALCALPHA:0; - material->ras_mode|= ( tface->transp &(TF_ADD | TF_ALPHA))?TRANSP:0; + material->flag[i] |= MIPMAP; + if(material->img[i]->flag & IMA_REFLECT) material->mapping[i].mapping |= USEREFL; else @@ -424,6 +437,8 @@ BL_Material* ConvertMaterial( material->flag[i] |= ( mttmp->mapto & MAP_ALPHA )?TEXALPHA:0; material->flag[i] |= ( mttmp->texflag& MTEX_NEGATIVE )?TEXNEG:0; + if(!glslmat && (material->flag[i] & TEXALPHA)) + texalpha = 1; } } else if(mttmp->tex->type == TEX_ENVMAP) { @@ -508,6 +523,7 @@ BL_Material* ConvertMaterial( } } } + // above one tex the switches here // are not used switch(valid_index) { @@ -539,20 +555,11 @@ BL_Material* ConvertMaterial( material->ref = mat->ref; material->amb = mat->amb; - // set alpha testing without z-sorting - if( ( validface && (!tface->transp)) && mat->mode & MA_ZTRA) { - // sets the RAS_IPolyMaterial::m_flag |RAS_FORCEALPHA - // this is so we don't have the overhead of the z-sorting code - material->ras_mode|=ALPHA_TEST; - } - else{ - // use regular z-sorting - material->ras_mode |= ((mat->mode & MA_ZTRA) != 0)?ZSORT:0; - } - material->ras_mode |= ((mat->mode & MA_WIRE) != 0)?WIRE:0; + material->ras_mode |= (mat->mode & MA_WIRE)? WIRE: 0; } else { int valid = 0; + // check for tface tex to fallback on if( validface ){ @@ -566,7 +573,6 @@ BL_Material* ConvertMaterial( material->mapping[0].mapping |= ( (material->img[0]->flag & IMA_REFLECT)!=0 )?USEREFL:0; material->flag[0] |= ( tface->transp &TF_ALPHA )?USEALPHA:0; material->flag[0] |= ( tface->transp &TF_ADD )?CALCALPHA:0; - material->ras_mode|= ( tface->transp & (TF_ADD|TF_ALPHA))?TRANSP:0; valid++; } } @@ -585,6 +591,10 @@ BL_Material* ConvertMaterial( } MT_Point2 uv[4]; MT_Point2 uv2[4]; + const char *uvName = "", *uv2Name = ""; + + uv[0]= uv[1]= uv[2]= uv[3]= MT_Point2(0.0f, 0.0f); + uv2[0]= uv2[1]= uv2[2]= uv2[3]= MT_Point2(0.0f, 0.0f); if( validface ) { @@ -593,12 +603,7 @@ BL_Material* ConvertMaterial( (tface->mode & TF_INVISIBLE) )?POLY_VIS:0; - material->ras_mode |= ( (tface->mode & TF_DYNAMIC)!= 0 )?COLLIDER:0; material->transp = tface->transp; - - if(tface->transp) - material->ras_mode |= TRANSP; - material->tile = tface->tile; material->mode = tface->mode; @@ -608,16 +613,33 @@ BL_Material* ConvertMaterial( if (mface->v4) uv[3] = MT_Point2(tface->uv[3]); + + uvName = tfaceName; } else { // nothing at all - material->ras_mode |= (COLLIDER|POLY_VIS| (validmat?0:USE_LIGHT)); + material->ras_mode |= (POLY_VIS| (validmat?0:USE_LIGHT)); material->mode = default_face_mode; material->transp = TF_SOLID; material->tile = 0; } + // with ztransp enabled, enforce alpha blending mode + if(validmat && (mat->mode & MA_ZTRA) && (material->transp == TF_SOLID)) + material->transp = TF_ALPHA; + // always zsort alpha + add + if((material->transp == TF_ALPHA || material->transp == TF_ADD || texalpha) && (material->transp != TF_CLIP)) { + material->ras_mode |= ALPHA; + material->ras_mode |= (material->mode & TF_ALPHASORT)? ZSORT: 0; + } + + // collider or not? + material->ras_mode |= (material->mode & TF_DYNAMIC)? COLLIDER: 0; + + // these flags are irrelevant at this point, remove so they + // don't hurt material bucketing + material->mode &= ~(TF_DYNAMIC|TF_ALPHASORT|TF_TEX); // get uv sets if(validmat) @@ -629,43 +651,43 @@ BL_Material* ConvertMaterial( for (int vind = 0; vind<material->num_enabled; vind++) { BL_Mapping &map = material->mapping[vind]; + if (map.uvCoName.IsEmpty()) isFirstSet = false; else { - MT_Point2 uvSet[4]; for (int lay=0; lay<MAX_MTFACE; lay++) { MTF_localLayer& layer = layers[lay]; if (layer.face == 0) break; - - bool processed = false; if (strcmp(map.uvCoName.ReadPtr(), layer.name)==0) { + MT_Point2 uvSet[4]; + uvSet[0] = MT_Point2(layer.face->uv[0]); uvSet[1] = MT_Point2(layer.face->uv[1]); uvSet[2] = MT_Point2(layer.face->uv[2]); if (mface->v4) uvSet[3] = MT_Point2(layer.face->uv[3]); + else + uvSet[3] = MT_Point2(0.0f, 0.0f); - processed = true; - } - - if (!processed) continue; - - if (isFirstSet) - { - uv[0] = uvSet[0]; uv[1] = uvSet[1]; - uv[2] = uvSet[2]; uv[3] = uvSet[3]; - isFirstSet = false; - } - else - { - uv2[0] = uvSet[0]; uv2[1] = uvSet[1]; - uv2[2] = uvSet[2]; uv2[3] = uvSet[3]; - map.mapping |= USECUSTOMUV; + if (isFirstSet) + { + uv[0] = uvSet[0]; uv[1] = uvSet[1]; + uv[2] = uvSet[2]; uv[3] = uvSet[3]; + isFirstSet = false; + uvName = layer.name; + } + else if(strcmp(layer.name, uvName) != 0) + { + uv2[0] = uvSet[0]; uv2[1] = uvSet[1]; + uv2[2] = uvSet[2]; uv2[3] = uvSet[3]; + map.mapping |= USECUSTOMUV; + uv2Name = layer.name; + } } } } @@ -685,11 +707,9 @@ BL_Material* ConvertMaterial( } material->SetConversionRGB(rgb); - material->SetConversionUV(uv); - material->SetConversionUV2(uv2); + material->SetConversionUV(uvName, uv); + material->SetConversionUV2(uv2Name, uv2); - - material->ras_mode |= (mface->v4==0)?TRIANGLE:0; if(validmat) material->matname =(mat->id.name); @@ -699,399 +719,294 @@ BL_Material* ConvertMaterial( } -static void BL_ComputeTriTangentSpace(const MT_Vector3 &v1, const MT_Vector3 &v2, const MT_Vector3 &v3, - const MT_Vector2 &uv1, const MT_Vector2 &uv2, const MT_Vector2 &uv3, - MFace* mface, MT_Vector3 *tan1, MT_Vector3 *tan2) -{ - MT_Vector3 dx1(v2 - v1), dx2(v3 - v1); - MT_Vector2 duv1(uv2 - uv1), duv2(uv3 - uv1); - - MT_Scalar r = 1.0 / (duv1.x() * duv2.y() - duv2.x() * duv1.y()); - duv1 *= r; - duv2 *= r; - MT_Vector3 sdir(duv2.y() * dx1 - duv1.y() * dx2); - MT_Vector3 tdir(duv1.x() * dx2 - duv2.x() * dx1); - - tan1[mface->v1] += sdir; - tan1[mface->v2] += sdir; - tan1[mface->v3] += sdir; - - tan2[mface->v1] += tdir; - tan2[mface->v2] += tdir; - tan2[mface->v3] += tdir; -} - -static MT_Vector4* BL_ComputeMeshTangentSpace(Mesh* mesh) -{ - MFace* mface = static_cast<MFace*>(mesh->mface); - MTFace* tface = static_cast<MTFace*>(mesh->mtface); - - MT_Vector3 *tan1 = new MT_Vector3[mesh->totvert]; - MT_Vector3 *tan2 = new MT_Vector3[mesh->totvert]; - - unsigned int v; - for (v = 0; v < mesh->totvert; v++) - { - tan1[v] = MT_Vector3(0.0, 0.0, 0.0); - tan2[v] = MT_Vector3(0.0, 0.0, 0.0); - } - - for (unsigned int p = 0; p < mesh->totface; p++, mface++, tface++) - { - MT_Vector3 v1(mesh->mvert[mface->v1].co), - v2(mesh->mvert[mface->v2].co), - v3(mesh->mvert[mface->v3].co); - - MT_Vector2 uv1(tface->uv[0]), - uv2(tface->uv[1]), - uv3(tface->uv[2]); - - BL_ComputeTriTangentSpace(v1, v2, v3, uv1, uv2, uv3, mface, tan1, tan2); - if (mface->v4) - { - MT_Vector3 v4(mesh->mvert[mface->v4].co); - MT_Vector2 uv4(tface->uv[3]); - - BL_ComputeTriTangentSpace(v1, v3, v4, uv1, uv3, uv4, mface, tan1, tan2); - } - } - - MT_Vector4 *tangent = new MT_Vector4[mesh->totvert]; - for (v = 0; v < mesh->totvert; v++) - { - const MT_Vector3 no(mesh->mvert[v].no[0]/32767.0, - mesh->mvert[v].no[1]/32767.0, - mesh->mvert[v].no[2]/32767.0); - // Gram-Schmidt orthogonalize - MT_Vector3 t(tan1[v] - no.cross(no.cross(tan1[v]))); - if (!MT_fuzzyZero(t)) - t /= t.length(); - - tangent[v].x() = t.x(); - tangent[v].y() = t.y(); - tangent[v].z() = t.z(); - // Calculate handedness - tangent[v].w() = no.dot(tan1[v].cross(tan2[v])) < 0.0 ? -1.0 : 1.0; - } - - delete [] tan1; - delete [] tan2; - - return tangent; -} - RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* rendertools, KX_Scene* scene, KX_BlenderSceneConverter *converter) { RAS_MeshObject *meshobj; - bool skinMesh = false; - + bool skinMesh = false; int lightlayer = blenderobj->lay; - - MFace* mface = static_cast<MFace*>(mesh->mface); - MTFace* tface = static_cast<MTFace*>(mesh->mtface); - MCol* mmcol = mesh->mcol; - MT_assert(mface || mesh->totface == 0); + // Get DerivedMesh data + DerivedMesh *dm = CDDM_from_mesh(mesh, blenderobj); + + MVert *mvert = dm->getVertArray(dm); + int totvert = dm->getNumVerts(dm); + + MFace *mface = dm->getFaceArray(dm); + MTFace *tface = static_cast<MTFace*>(dm->getFaceDataArray(dm, CD_MTFACE)); + MCol *mcol = static_cast<MCol*>(dm->getFaceDataArray(dm, CD_MCOL)); + float (*tangent)[3] = NULL; + int totface = dm->getNumFaces(dm); + const char *tfaceName = ""; + + if(tface) { + DM_add_tangent_layer(dm); + tangent = (float(*)[3])dm->getFaceDataArray(dm, CD_TANGENT); + } // Determine if we need to make a skinned mesh - if (mesh->dvert){ - meshobj = new BL_SkinMeshObject(lightlayer); + if (mesh->dvert || mesh->key || ((blenderobj->gameflag & OB_SOFT_BODY) != 0)) + { + meshobj = new BL_SkinMeshObject(mesh, lightlayer); skinMesh = true; } - else { - meshobj = new RAS_MeshObject(lightlayer); - } - MT_Vector4 *tangent = 0; - if (tface) - tangent = BL_ComputeMeshTangentSpace(mesh); - + else + meshobj = new RAS_MeshObject(mesh, lightlayer); // Extract avaiable layers MTF_localLayer *layers = new MTF_localLayer[MAX_MTFACE]; - for (int lay=0; lay<MAX_MTFACE; lay++) - { + for (int lay=0; lay<MAX_MTFACE; lay++) { layers[lay].face = 0; layers[lay].name = ""; } - int validLayers = 0; - for (int i=0; i<mesh->fdata.totlayer; i++) + for (int i=0; i<dm->faceData.totlayer; i++) { - if (mesh->fdata.layers[i].type == CD_MTFACE) + if (dm->faceData.layers[i].type == CD_MTFACE) { assert(validLayers <= 8); - layers[validLayers].face = (MTFace*)mesh->fdata.layers[i].data;; - layers[validLayers].name = mesh->fdata.layers[i].name; + layers[validLayers].face = (MTFace*)(dm->faceData.layers[i].data); + layers[validLayers].name = dm->faceData.layers[i].name; + if(tface == layers[validLayers].face) + tfaceName = layers[validLayers].name; validLayers++; } } - meshobj->SetName(mesh->id.name); - meshobj->m_xyz_index_to_vertex_index_mapping.resize(mesh->totvert); - for (int f=0;f<mesh->totface;f++,mface++) + meshobj->m_sharedvertex_map.resize(totvert); + + for (int f=0;f<totface;f++,mface++) { - + Material* ma = 0; bool collider = true; - - // only add valid polygons - if (mface->v3) - { - MT_Point2 uv0(0.0,0.0),uv1(0.0,0.0),uv2(0.0,0.0),uv3(0.0,0.0); - MT_Point2 uv20(0.0,0.0),uv21(0.0,0.0),uv22(0.0,0.0),uv23(0.0,0.0); - // rgb3 is set from the adjoint face in a square - unsigned int rgb0,rgb1,rgb2,rgb3 = 0; - MT_Vector3 no0(mesh->mvert[mface->v1].no[0], mesh->mvert[mface->v1].no[1], mesh->mvert[mface->v1].no[2]), - no1(mesh->mvert[mface->v2].no[0], mesh->mvert[mface->v2].no[1], mesh->mvert[mface->v2].no[2]), - no2(mesh->mvert[mface->v3].no[0], mesh->mvert[mface->v3].no[1], mesh->mvert[mface->v3].no[2]), - no3(0.0, 0.0, 0.0); - MT_Point3 pt0(mesh->mvert[mface->v1].co), - pt1(mesh->mvert[mface->v2].co), - pt2(mesh->mvert[mface->v3].co), - pt3(0.0, 0.0, 0.0); - MT_Vector4 tan0(0.0, 0.0, 0.0, 0.0), - tan1(0.0, 0.0, 0.0, 0.0), - tan2(0.0, 0.0, 0.0, 0.0), - tan3(0.0, 0.0, 0.0, 0.0); - - no0 /= 32767.0; - no1 /= 32767.0; - no2 /= 32767.0; - if (mface->v4) - { - pt3 = MT_Point3(mesh->mvert[mface->v4].co); - no3 = MT_Vector3(mesh->mvert[mface->v4].no[0], mesh->mvert[mface->v4].no[1], mesh->mvert[mface->v4].no[2]); - no3 /= 32767.0; + MT_Point2 uv0(0.0,0.0),uv1(0.0,0.0),uv2(0.0,0.0),uv3(0.0,0.0); + MT_Point2 uv20(0.0,0.0),uv21(0.0,0.0),uv22(0.0,0.0),uv23(0.0,0.0); + unsigned int rgb0,rgb1,rgb2,rgb3 = 0; + + MT_Point3 pt0, pt1, pt2, pt3; + MT_Vector3 no0(0,0,0), no1(0,0,0), no2(0,0,0), no3(0,0,0); + MT_Vector4 tan0(0,0,0,0), tan1(0,0,0,0), tan2(0,0,0,0), tan3(0,0,0,0); + + /* get coordinates, normals and tangents */ + pt0 = MT_Point3(mvert[mface->v1].co); + pt1 = MT_Point3(mvert[mface->v2].co); + pt2 = MT_Point3(mvert[mface->v3].co); + pt3 = (mface->v4)? MT_Point3(mvert[mface->v4].co): MT_Point3(0.0, 0.0, 0.0); + + if(mface->flag & ME_SMOOTH) { + float n0[3], n1[3], n2[3], n3[3]; + + NormalShortToFloat(n0, mvert[mface->v1].no); + NormalShortToFloat(n1, mvert[mface->v2].no); + NormalShortToFloat(n2, mvert[mface->v3].no); + no0 = n0; + no1 = n1; + no2 = n2; + + if(mface->v4) { + NormalShortToFloat(n3, mvert[mface->v4].no); + no3 = n3; } + } + else { + float fno[3]; + + if(mface->v4) + CalcNormFloat4(mvert[mface->v1].co, mvert[mface->v2].co, + mvert[mface->v3].co, mvert[mface->v4].co, fno); + else + CalcNormFloat(mvert[mface->v1].co, mvert[mface->v2].co, + mvert[mface->v3].co, fno); + + no0 = no1 = no2 = no3 = MT_Vector3(fno); + } + + if(tangent) { + tan0 = tangent[f*4 + 0]; + tan1 = tangent[f*4 + 1]; + tan2 = tangent[f*4 + 2]; + + if (mface->v4) + tan3 = tangent[f*4 + 3]; + } + + /* get material */ + ma = give_current_material(blenderobj, mface->mat_nr+1); - if(!(mface->flag & ME_SMOOTH)) - { - MT_Vector3 norm = ((pt1-pt0).cross(pt2-pt0)).safe_normalized(); - norm[0] = ((int) (10*norm[0]))/10.0; - norm[1] = ((int) (10*norm[1]))/10.0; - norm[2] = ((int) (10*norm[2]))/10.0; - no0=no1=no2=no3= norm; - + { + bool visible = true; + RAS_IPolyMaterial* polymat = NULL; + BL_Material *bl_mat = NULL; + + if(converter->GetMaterials()) { + /* do Blender Multitexture and Blender GLSL materials */ + unsigned int rgb[4]; + MT_Point2 uv[4]; + + /* first is the BL_Material */ + bl_mat = ConvertMaterial(ma, tface, tfaceName, mface, mcol, + lightlayer, blenderobj, layers, converter->GetGLSLMaterials()); + + bl_mat->material_index = (int)mface->mat_nr; + + visible = ((bl_mat->ras_mode & POLY_VIS)!=0); + collider = ((bl_mat->ras_mode & COLLIDER)!=0); + + /* vertex colors and uv's were stored in bl_mat temporarily */ + bl_mat->GetConversionRGB(rgb); + rgb0 = rgb[0]; rgb1 = rgb[1]; + rgb2 = rgb[2]; rgb3 = rgb[3]; + + bl_mat->GetConversionUV(uv); + uv0 = uv[0]; uv1 = uv[1]; + uv2 = uv[2]; uv3 = uv[3]; + + bl_mat->GetConversionUV2(uv); + uv20 = uv[0]; uv21 = uv[1]; + uv22 = uv[2]; uv23 = uv[3]; + + /* then the KX_BlenderMaterial */ + polymat = new KX_BlenderMaterial(scene, bl_mat, skinMesh, lightlayer); } + else { + /* do Texture Face materials */ + Image* bima = (tface)? (Image*)tface->tpage: NULL; + STR_String imastr = (tface)? (bima? (bima)->id.name : "" ) : ""; - { - Material* ma = 0; - bool polyvisible = true; - RAS_IPolyMaterial* polymat = NULL; - - if(converter->GetMaterials()) - { - if(mesh->totcol > 1) - ma = mesh->mat[mface->mat_nr]; - else - ma = give_current_material(blenderobj, 1); - - BL_Material *bl_mat = ConvertMaterial(mesh, ma, tface, mface, mmcol, lightlayer, blenderobj, layers); - // set the index were dealing with - bl_mat->material_index = (int)mface->mat_nr; - - polyvisible = ((bl_mat->ras_mode & POLY_VIS)!=0); - collider = ((bl_mat->ras_mode & COLLIDER)!=0); + char transp=0; + short mode=0, tile=0; + int tilexrep=4,tileyrep = 4; + + if (bima) { + tilexrep = bima->xrep; + tileyrep = bima->yrep; + } + + /* get tface properties if available */ + if(tface) { + /* TF_DYNAMIC means the polygon is a collision face */ + collider = ((tface->mode & TF_DYNAMIC) != 0); + transp = tface->transp; + tile = tface->tile; + mode = tface->mode; - polymat = new KX_BlenderMaterial(scene, bl_mat, skinMesh, lightlayer, blenderobj ); - converter->RegisterBlenderMaterial(bl_mat); + visible = !((mface->flag & ME_HIDE)||(tface->mode & TF_INVISIBLE)); - unsigned int rgb[4]; - bl_mat->GetConversionRGB(rgb); - rgb0 = rgb[0]; rgb1 = rgb[1]; - rgb2 = rgb[2]; rgb3 = rgb[3]; - MT_Point2 uv[4]; - bl_mat->GetConversionUV(uv); - uv0 = uv[0]; uv1 = uv[1]; - uv2 = uv[2]; uv3 = uv[3]; - - bl_mat->GetConversionUV2(uv); - uv20 = uv[0]; uv21 = uv[1]; - uv22 = uv[2]; uv23 = uv[3]; - - if(tangent){ - tan0 = tangent[mface->v1]; - tan1 = tangent[mface->v2]; - tan2 = tangent[mface->v3]; - if (mface->v4) - tan3 = tangent[mface->v4]; - } - // this is needed to free up memory afterwards - converter->RegisterPolyMaterial(polymat); + uv0 = MT_Point2(tface->uv[0]); + uv1 = MT_Point2(tface->uv[1]); + uv2 = MT_Point2(tface->uv[2]); + + if (mface->v4) + uv3 = MT_Point2(tface->uv[3]); + } + else { + /* no texfaces, set COLLSION true and everything else FALSE */ + mode = default_face_mode; + transp = TF_SOLID; + tile = 0; } - else - { - ma = give_current_material(blenderobj, 1); - Image* bima = ((mesh->mtface && tface) ? (Image*) tface->tpage : NULL); - - STR_String imastr = - ((mesh->mtface && tface) ? - (bima? (bima)->id.name : "" ) : "" ); - - char transp=0; - short mode=0, tile=0; - int tilexrep=4,tileyrep = 4; + /* get vertex colors */ + if (mcol) { + /* we have vertex colors */ + rgb0 = KX_Mcol2uint_new(mcol[0]); + rgb1 = KX_Mcol2uint_new(mcol[1]); + rgb2 = KX_Mcol2uint_new(mcol[2]); - if (bima) - { - tilexrep = bima->xrep; - tileyrep = bima->yrep; - - } + if (mface->v4) + rgb3 = KX_Mcol2uint_new(mcol[3]); + } + else { + /* no vertex colors, take from material, otherwise white */ + unsigned int color = 0xFFFFFFFFL; - if (mesh->mtface && tface) + if (ma) { - // Use texface colors if available - //TF_DYNAMIC means the polygon is a collision face - collider = ((tface->mode & TF_DYNAMIC) != 0); - transp = tface->transp; - tile = tface->tile; - mode = tface->mode; - - polyvisible = !((mface->flag & ME_HIDE)||(tface->mode & TF_INVISIBLE)); + union + { + unsigned char cp[4]; + unsigned int integer; + } col_converter; - uv0 = MT_Point2(tface->uv[0]); - uv1 = MT_Point2(tface->uv[1]); - uv2 = MT_Point2(tface->uv[2]); - - if (mface->v4) - uv3 = MT_Point2(tface->uv[3]); - } - else - { - // no texfaces, set COLLSION true and everything else FALSE + col_converter.cp[3] = (unsigned char) (ma->r*255.0); + col_converter.cp[2] = (unsigned char) (ma->g*255.0); + col_converter.cp[1] = (unsigned char) (ma->b*255.0); + col_converter.cp[0] = (unsigned char) (ma->alpha*255.0); - mode = default_face_mode; - transp = TF_SOLID; - tile = 0; + color = col_converter.integer; } - if (mmcol) - { - // Use vertex colors - rgb0 = KX_Mcol2uint_new(mmcol[0]); - rgb1 = KX_Mcol2uint_new(mmcol[1]); - rgb2 = KX_Mcol2uint_new(mmcol[2]); - - if (mface->v4) - rgb3 = KX_Mcol2uint_new(mmcol[3]); - } - else { - // no vertex colors: take from material if we have one, - // otherwise set to white - unsigned int color = 0xFFFFFFFFL; - - if (ma) - { - union - { - unsigned char cp[4]; - unsigned int integer; - } col_converter; - - col_converter.cp[3] = (unsigned char) (ma->r*255.0); - col_converter.cp[2] = (unsigned char) (ma->g*255.0); - col_converter.cp[1] = (unsigned char) (ma->b*255.0); - col_converter.cp[0] = (unsigned char) (ma->alpha*255.0); - - color = col_converter.integer; - } - - rgb0 = KX_rgbaint2uint_new(color); - rgb1 = KX_rgbaint2uint_new(color); - rgb2 = KX_rgbaint2uint_new(color); - - if (mface->v4) - rgb3 = KX_rgbaint2uint_new(color); - } + rgb0 = KX_rgbaint2uint_new(color); + rgb1 = KX_rgbaint2uint_new(color); + rgb2 = KX_rgbaint2uint_new(color); - bool istriangle = (mface->v4==0); - bool zsort = ma?(ma->mode & MA_ZTRA) != 0:false; - - polymat = new KX_PolygonMaterial(imastr, ma, - tile, tilexrep, tileyrep, - mode, transp, zsort, lightlayer, istriangle, blenderobj, tface, (unsigned int*)mmcol); - - if (ma) - { - polymat->m_specular = MT_Vector3(ma->specr, ma->specg, ma->specb)*ma->spec; - polymat->m_shininess = (float)ma->har/4.0; // 0 < ma->har <= 512 - polymat->m_diffuse = MT_Vector3(ma->r, ma->g, ma->b)*(ma->emit + ma->ref); - - } else - { - polymat->m_specular = MT_Vector3(0.0f,0.0f,0.0f); - polymat->m_shininess = 35.0; - } - // this is needed to free up memory afterwards - converter->RegisterPolyMaterial(polymat); - + if (mface->v4) + rgb3 = KX_rgbaint2uint_new(color); } - - RAS_MaterialBucket* bucket = scene->FindBucket(polymat); - - int nverts = mface->v4?4:3; - int vtxarray = meshobj->FindVertexArray(nverts,polymat); - RAS_Polygon* poly = new RAS_Polygon(bucket,polyvisible,nverts,vtxarray); - if (skinMesh) { - int d1, d2, d3, d4=0; - bool flat; - - /* If the face is set to solid, all fnors are the same */ - if (mface->flag & ME_SMOOTH) - flat = false; - else - flat = true; - - d1=((BL_SkinMeshObject*)meshobj)->FindOrAddDeform(vtxarray, mface->v1, &mesh->dvert[mface->v1], polymat); - d2=((BL_SkinMeshObject*)meshobj)->FindOrAddDeform(vtxarray, mface->v2, &mesh->dvert[mface->v2], polymat); - d3=((BL_SkinMeshObject*)meshobj)->FindOrAddDeform(vtxarray, mface->v3, &mesh->dvert[mface->v3], polymat); - if (nverts==4) - d4=((BL_SkinMeshObject*)meshobj)->FindOrAddDeform(vtxarray, mface->v4, &mesh->dvert[mface->v4], polymat); - poly->SetVertex(0,((BL_SkinMeshObject*)meshobj)->FindOrAddVertex(vtxarray,pt0,uv0,uv20,tan0,rgb0,no0,d1,flat, polymat)); - poly->SetVertex(1,((BL_SkinMeshObject*)meshobj)->FindOrAddVertex(vtxarray,pt1,uv1,uv21,tan1,rgb1,no1,d2,flat, polymat)); - poly->SetVertex(2,((BL_SkinMeshObject*)meshobj)->FindOrAddVertex(vtxarray,pt2,uv2,uv22,tan2,rgb2,no2,d3,flat, polymat)); - if (nverts==4) - poly->SetVertex(3,((BL_SkinMeshObject*)meshobj)->FindOrAddVertex(vtxarray,pt3,uv3,uv23,tan3,rgb3,no3,d4, flat,polymat)); + + // only zsort alpha + add + bool alpha = (transp == TF_ALPHA || transp == TF_ADD); + bool zsort = (mode & TF_ALPHASORT)? alpha: 0; + + polymat = new KX_PolygonMaterial(imastr, ma, + tile, tilexrep, tileyrep, + mode, transp, alpha, zsort, lightlayer, tface, (unsigned int*)mcol); + + if (ma) { + polymat->m_specular = MT_Vector3(ma->specr, ma->specg, ma->specb)*ma->spec; + polymat->m_shininess = (float)ma->har/4.0; // 0 < ma->har <= 512 + polymat->m_diffuse = MT_Vector3(ma->r, ma->g, ma->b)*(ma->emit + ma->ref); } - else - { - poly->SetVertex(0,meshobj->FindOrAddVertex(vtxarray,pt0,uv0,uv20,tan0,rgb0,no0,polymat,mface->v1)); - poly->SetVertex(1,meshobj->FindOrAddVertex(vtxarray,pt1,uv1,uv21,tan1,rgb1,no1,polymat,mface->v2)); - poly->SetVertex(2,meshobj->FindOrAddVertex(vtxarray,pt2,uv2,uv22,tan2,rgb2,no2,polymat,mface->v3)); - if (nverts==4) - poly->SetVertex(3,meshobj->FindOrAddVertex(vtxarray,pt3,uv3,uv23,tan3,rgb3,no3,polymat,mface->v4)); + else { + polymat->m_specular = MT_Vector3(0.0f,0.0f,0.0f); + polymat->m_shininess = 35.0; } - meshobj->AddPolygon(poly); - if (poly->IsCollider()) - { - RAS_TriangleIndex idx; - idx.m_index[0] = mface->v1; - idx.m_index[1] = mface->v2; - idx.m_index[2] = mface->v3; - idx.m_collider = collider; - meshobj->m_triangle_indices.push_back(idx); - if (nverts==4) - { - idx.m_index[0] = mface->v1; - idx.m_index[1] = mface->v3; - idx.m_index[2] = mface->v4; - idx.m_collider = collider; - meshobj->m_triangle_indices.push_back(idx); - } + } + + /* mark face as flat, so vertices are split */ + bool flat = (mface->flag & ME_SMOOTH) == 0; + + // see if a bucket was reused or a new one was created + // this way only one KX_BlenderMaterial object has to exist per bucket + bool bucketCreated; + RAS_MaterialBucket* bucket = scene->FindBucket(polymat, bucketCreated); + if (bucketCreated) { + // this is needed to free up memory afterwards + converter->RegisterPolyMaterial(polymat); + if(converter->GetMaterials()) { + converter->RegisterBlenderMaterial(bl_mat); } - -// poly->SetVisibleWireframeEdges(mface->edcode); - poly->SetCollider(collider); + } else { + // delete the material objects since they are no longer needed + // from now on, use the polygon material from the material bucket + delete polymat; + if(converter->GetMaterials()) { + delete bl_mat; + } + polymat = bucket->GetPolyMaterial(); } + + int nverts = (mface->v4)? 4: 3; + RAS_Polygon *poly = meshobj->AddPolygon(bucket, nverts); + + poly->SetVisible(visible); + poly->SetCollider(collider); + //poly->SetEdgeCode(mface->edcode); + + meshobj->AddVertex(poly,0,pt0,uv0,uv20,tan0,rgb0,no0,flat,mface->v1); + meshobj->AddVertex(poly,1,pt1,uv1,uv21,tan1,rgb1,no1,flat,mface->v2); + meshobj->AddVertex(poly,2,pt2,uv2,uv22,tan2,rgb2,no2,flat,mface->v3); + + if (nverts==4) + meshobj->AddVertex(poly,3,pt3,uv3,uv23,tan3,rgb3,no3,flat,mface->v4); } + if (tface) tface++; - if (mmcol) - mmcol+=4; + if (mcol) + mcol+=4; for (int lay=0; lay<MAX_MTFACE; lay++) { @@ -1101,19 +1016,18 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools* layer.face++; } } - meshobj->UpdateMaterialList(); + meshobj->m_sharedvertex_map.clear(); // pre calculate texture generation - for(RAS_MaterialBucket::Set::iterator mit = meshobj->GetFirstMaterial(); + for(list<RAS_MeshMaterial>::iterator mit = meshobj->GetFirstMaterial(); mit != meshobj->GetLastMaterial(); ++ mit) { - (*mit)->GetPolyMaterial()->OnConstruction(); + mit->m_bucket->GetPolyMaterial()->OnConstruction(); } - if(tangent) - delete [] tangent; - if (layers) delete []layers; + + dm->release(dm); return meshobj; } @@ -1367,6 +1281,10 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, //int userigidbody = SYS_GetCommandLineInt(syshandle,"norigidbody",0); //bool bRigidBody = (userigidbody == 0); + // object has physics representation? + if (!(blenderobject->gameflag & OB_COLLISION)) + return; + // get Root Parent of blenderobject struct Object* parent= blenderobject->parent; while(parent && parent->parent) { @@ -1398,19 +1316,97 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, objprop.m_isCompoundChild = isCompoundChild; objprop.m_hasCompoundChildren = (blenderobject->gameflag & OB_CHILD) != 0; - - if ((objprop.m_isactor = (blenderobject->gameflag & OB_ACTOR)!=0)) + objprop.m_margin = blenderobject->margin; + // ACTOR is now a separate feature + objprop.m_isactor = (blenderobject->gameflag & OB_ACTOR)!=0; + objprop.m_dyna = (blenderobject->gameflag & OB_DYNAMIC) != 0; + objprop.m_softbody = (blenderobject->gameflag & OB_SOFT_BODY) != 0; + objprop.m_angular_rigidbody = (blenderobject->gameflag & OB_RIGID_BODY) != 0; + + if (objprop.m_softbody) { - objprop.m_dyna = (blenderobject->gameflag & OB_DYNAMIC) != 0; - objprop.m_angular_rigidbody = (blenderobject->gameflag & OB_RIGID_BODY) != 0; - objprop.m_ghost = (blenderobject->gameflag & OB_GHOST) != 0; - objprop.m_disableSleeping = (blenderobject->gameflag & OB_COLLISION_RESPONSE) != 0;//abuse the OB_COLLISION_RESPONSE flag - } else { - objprop.m_dyna = false; - objprop.m_angular_rigidbody = false; - objprop.m_ghost = false; - objprop.m_disableSleeping = false; + ///for game soft bodies + if (blenderobject->bsoft) + { + objprop.m_gamesoftFlag = blenderobject->bsoft->flag; + /////////////////// + objprop.m_soft_linStiff = blenderobject->bsoft->linStiff; + objprop.m_soft_angStiff = blenderobject->bsoft->angStiff; /* angular stiffness 0..1 */ + objprop.m_soft_volume= blenderobject->bsoft->volume; /* volume preservation 0..1 */ + + objprop.m_soft_viterations= blenderobject->bsoft->viterations; /* Velocities solver iterations */ + objprop.m_soft_piterations= blenderobject->bsoft->piterations; /* Positions solver iterations */ + objprop.m_soft_diterations= blenderobject->bsoft->diterations; /* Drift solver iterations */ + objprop.m_soft_citerations= blenderobject->bsoft->citerations; /* Cluster solver iterations */ + + objprop.m_soft_kSRHR_CL= blenderobject->bsoft->kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */ + objprop.m_soft_kSKHR_CL= blenderobject->bsoft->kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */ + objprop.m_soft_kSSHR_CL= blenderobject->bsoft->kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */ + objprop.m_soft_kSR_SPLT_CL= blenderobject->bsoft->kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + + objprop.m_soft_kSK_SPLT_CL= blenderobject->bsoft->kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + objprop.m_soft_kSS_SPLT_CL= blenderobject->bsoft->kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + objprop.m_soft_kVCF= blenderobject->bsoft->kVCF; /* Velocities correction factor (Baumgarte) */ + objprop.m_soft_kDP= blenderobject->bsoft->kDP; /* Damping coefficient [0,1] */ + + objprop.m_soft_kDG= blenderobject->bsoft->kDG; /* Drag coefficient [0,+inf] */ + objprop.m_soft_kLF= blenderobject->bsoft->kLF; /* Lift coefficient [0,+inf] */ + objprop.m_soft_kPR= blenderobject->bsoft->kPR; /* Pressure coefficient [-inf,+inf] */ + objprop.m_soft_kVC= blenderobject->bsoft->kVC; /* Volume conversation coefficient [0,+inf] */ + + objprop.m_soft_kDF= blenderobject->bsoft->kDF; /* Dynamic friction coefficient [0,1] */ + objprop.m_soft_kMT= blenderobject->bsoft->kMT; /* Pose matching coefficient [0,1] */ + objprop.m_soft_kCHR= blenderobject->bsoft->kCHR; /* Rigid contacts hardness [0,1] */ + objprop.m_soft_kKHR= blenderobject->bsoft->kKHR; /* Kinetic contacts hardness [0,1] */ + + objprop.m_soft_kSHR= blenderobject->bsoft->kSHR; /* Soft contacts hardness [0,1] */ + objprop.m_soft_kAHR= blenderobject->bsoft->kAHR; /* Anchors hardness [0,1] */ + objprop.m_soft_collisionflags= blenderobject->bsoft->collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */ + objprop.m_soft_numclusteriterations= blenderobject->bsoft->numclusteriterations; /* number of iterations to refine collision clusters*/ + + } else + { + objprop.m_gamesoftFlag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT; + + objprop.m_soft_linStiff = 0.5;; + objprop.m_soft_angStiff = 1.f; /* angular stiffness 0..1 */ + objprop.m_soft_volume= 1.f; /* volume preservation 0..1 */ + + + objprop.m_soft_viterations= 0; + objprop.m_soft_piterations= 1; + objprop.m_soft_diterations= 0; + objprop.m_soft_citerations= 4; + + objprop.m_soft_kSRHR_CL= 0.1f; + objprop.m_soft_kSKHR_CL= 1.f; + objprop.m_soft_kSSHR_CL= 0.5; + objprop.m_soft_kSR_SPLT_CL= 0.5f; + + objprop.m_soft_kSK_SPLT_CL= 0.5f; + objprop.m_soft_kSS_SPLT_CL= 0.5f; + objprop.m_soft_kVCF= 1; + objprop.m_soft_kDP= 0; + + objprop.m_soft_kDG= 0; + objprop.m_soft_kLF= 0; + objprop.m_soft_kPR= 0; + objprop.m_soft_kVC= 0; + + objprop.m_soft_kDF= 0.2f; + objprop.m_soft_kMT= 0.05f; + objprop.m_soft_kCHR= 1.0f; + objprop.m_soft_kKHR= 0.1f; + + objprop.m_soft_kSHR= 1.f; + objprop.m_soft_kAHR= 0.7f; + objprop.m_soft_collisionflags= OB_BSB_COL_SDF_RS + OB_BSB_COL_VF_SS; + objprop.m_soft_numclusteriterations= 16; + } } + + objprop.m_ghost = (blenderobject->gameflag & OB_GHOST) != 0; + objprop.m_disableSleeping = (blenderobject->gameflag & OB_COLLISION_RESPONSE) != 0;//abuse the OB_COLLISION_RESPONSE flag //mmm, for now, taks this for the size of the dynamicobject // Blender uses inertia for radius of dynamic object objprop.m_radius = blenderobject->inertia; @@ -1418,6 +1414,12 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, objprop.m_dynamic_parent=NULL; objprop.m_isdeformable = ((blenderobject->gameflag2 & 2)) != 0; objprop.m_boundclass = objprop.m_dyna?KX_BOUNDSPHERE:KX_BOUNDMESH; + + if ((blenderobject->gameflag & OB_SOFT_BODY) && !(blenderobject->gameflag & OB_BOUNDS)) + { + objprop.m_boundclass = KX_BOUNDMESH; + } + KX_BoxBounds bb; my_get_local_bounds(blenderobject,objprop.m_boundobject.box.m_center,bb.m_extends); if (blenderobject->gameflag & OB_BOUNDS) @@ -1511,14 +1513,15 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, default: break; } - + delete shapeprops; + delete smmaterial; } -static KX_LightObject *gamelight_from_blamp(Lamp *la, unsigned int layerflag, KX_Scene *kxscene, RAS_IRenderTools *rendertools, KX_BlenderSceneConverter *converter) { +static KX_LightObject *gamelight_from_blamp(Object *ob, Lamp *la, unsigned int layerflag, KX_Scene *kxscene, RAS_IRenderTools *rendertools, KX_BlenderSceneConverter *converter) { RAS_LightObject lightobj; KX_LightObject *gamelight; @@ -1550,15 +1553,18 @@ static KX_LightObject *gamelight_from_blamp(Lamp *la, unsigned int layerflag, KX } else { lightobj.m_type = RAS_LightObject::LIGHT_NORMAL; } - - gamelight = new KX_LightObject(kxscene, KX_Scene::m_callbacks, rendertools, lightobj); + + gamelight = new KX_LightObject(kxscene, KX_Scene::m_callbacks, rendertools, + lightobj, converter->GetGLSLMaterials()); + BL_ConvertLampIpos(la, gamelight, converter); return gamelight; } -static KX_Camera *gamecamera_from_bcamera(Camera *ca, KX_Scene *kxscene, KX_BlenderSceneConverter *converter) { - RAS_CameraData camdata(ca->lens, ca->clipsta, ca->clipend, ca->type == CAM_PERSP); +static KX_Camera *gamecamera_from_bcamera(Object *ob, KX_Scene *kxscene, KX_BlenderSceneConverter *converter) { + Camera* ca = static_cast<Camera*>(ob->data); + RAS_CameraData camdata(ca->lens, ca->clipsta, ca->clipend, ca->type == CAM_PERSP, dof_camera(ob)); KX_Camera *gamecamera; gamecamera= new KX_Camera(kxscene, KX_Scene::m_callbacks, camdata); @@ -1582,21 +1588,22 @@ static KX_GameObject *gameobject_from_blenderobject( { case OB_LAMP: { - KX_LightObject* gamelight= gamelight_from_blamp(static_cast<Lamp*>(ob->data), ob->lay, kxscene, rendertools, converter); + KX_LightObject* gamelight= gamelight_from_blamp(ob, static_cast<Lamp*>(ob->data), ob->lay, kxscene, rendertools, converter); gameobj = gamelight; gamelight->AddRef(); kxscene->GetLightList()->Add(gamelight); - + break; } case OB_CAMERA: { - KX_Camera* gamecamera = gamecamera_from_bcamera(static_cast<Camera*>(ob->data), kxscene, converter); + KX_Camera* gamecamera = gamecamera_from_bcamera(ob, kxscene, converter); gameobj = gamecamera; - gamecamera->AddRef(); + //don't add a reference: the camera list in kxscene->m_cameras is not released at the end + //gamecamera->AddRef(); kxscene->AddCamera(gamecamera); break; @@ -1617,7 +1624,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); @@ -1628,14 +1635,30 @@ 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){ - BL_SkinDeformer *dcont = new BL_SkinDeformer(ob, (BL_SkinMeshObject*)meshobj ); - ((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont; - } - else if (((Mesh*)ob->data)->dvert){ - BL_MeshDeformer *dcont = new BL_MeshDeformer(ob, (BL_SkinMeshObject*)meshobj ); - ((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont; + // 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 && ob->defbase.first; + 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)->SetDeformer(dcont); + if (bHasArmature) + dcont->LoadShapeDrivers(ob->parent); + } else if (bHasArmature) { + BL_SkinDeformer *dcont = new BL_SkinDeformer((BL_DeformableGameObject*)gameobj, + ob, (BL_SkinMeshObject*)meshobj); + ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont); + } else if (bHasDvert) { + // this case correspond to a mesh that can potentially deform but not with the + // object to which it is attached for the moment. A skin mesh was created in + // BL_ConvertMesh() so must create a deformer too! + BL_MeshDeformer *dcont = new BL_MeshDeformer((BL_DeformableGameObject*)gameobj, + ob, (BL_SkinMeshObject*)meshobj); + ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont); } MT_Point3 min = MT_Point3(center) - MT_Vector3(extents); @@ -1665,7 +1688,14 @@ static KX_GameObject *gameobject_from_blenderobject( break; } } - + if (gameobj) + { + gameobj->SetPhysicsEnvironment(kxscene->GetPhysicsEnvironment()); + gameobj->SetLayer(ob->lay); + gameobj->SetBlenderObject(ob); + /* set the visibility state based on the objects render option in the outliner */ + if(ob->restrictflag & OB_RESTRICT_RENDER) gameobj->SetVisible(0, 0); + } return gameobj; } @@ -1674,20 +1704,6 @@ struct parentChildLink { SG_Node* m_gamechildnode; }; - /** - * Find the specified scene by name, or the first - * scene if nothing matches (shouldn't happen). - */ -static struct Scene *GetSceneForName(struct Main *maggie, const STR_String& scenename) { - Scene *sce; - - for (sce= (Scene*) maggie->scene.first; sce; sce= (Scene*) sce->id.next) - if (scenename == (sce->id.name+2)) - return sce; - - return (Scene*) maggie->scene.first; -} - #include "DNA_constraint_types.h" //XXX #include "BIF_editconstraint.h" @@ -1770,7 +1786,7 @@ KX_GameObject* getGameOb(STR_String busc,CListValue* sumolist){ return 0; } -#include "BLI_arithb.h" + // convert blender objects into ketsji gameobjects void BL_ConvertBlenderObjects(struct Main* maggie, const STR_String& scenename, @@ -1786,7 +1802,10 @@ void BL_ConvertBlenderObjects(struct Main* maggie, ) { - Scene *blenderscene = GetSceneForName(maggie, scenename); + Scene *blenderscene = converter->GetBlenderSceneForName(scenename); + // for SETLOOPER + Scene *sce; + Base *base; // Get the frame settings of the canvas. // Get the aspect ratio of the canvas as designed by the user. @@ -1795,7 +1814,10 @@ void BL_ConvertBlenderObjects(struct Main* maggie, int aspect_width; int aspect_height; vector<MT_Vector3> inivel,iniang; - + set<Group*> grouplist; // list of groups to be converted + set<Object*> allblobj; // all objects converted + set<Object*> groupobj; // objects from groups (never in active layer) + if (alwaysUseExpandFraming) { frame_type = RAS_FrameSettings::e_frame_extend; aspect_width = canvas->GetWidth(); @@ -1842,6 +1864,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, vector<parentChildLink> vec_parent_child; CListValue* objectlist = kxscene->GetObjectList(); + CListValue* inactivelist = kxscene->GetInactiveList(); CListValue* parentlist = kxscene->GetRootParentList(); SCA_LogicManager* logicmgr = kxscene->GetLogicManager(); @@ -1849,7 +1872,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, CListValue* logicbrick_conversionlist = new CListValue(); - SG_TreeFactory tf; + //SG_TreeFactory tf; // Convert actions to actionmap bAction *curAct; @@ -1859,11 +1882,15 @@ void BL_ConvertBlenderObjects(struct Main* maggie, } SetDefaultFaceType(blenderscene); - - Base *base = static_cast<Base*>(blenderscene->base.first); - while(base) + // Let's support scene set. + // Beware of name conflict in linked data, it will not crash but will create confusion + // in Python scripting and in certain actuators (replace mesh). Linked scene *should* have + // no conflicting name for Object, Object data and Action. + for (SETLOOPER(blenderscene, base)) { Object* blenderobject = base->object; + allblobj.insert(blenderobject); + KX_GameObject* gameobj = gameobject_from_blenderobject( base->object, kxscene, @@ -1877,7 +1904,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, if (converter->addInitFromFrame) if (!isInActiveLayer) addobj=false; - + if (gameobj&&addobj) { MT_Point3 posPrev; @@ -1929,10 +1956,8 @@ void BL_ConvertBlenderObjects(struct Main* maggie, gameobj->NodeUpdateGS(0,true); BL_ConvertIpos(blenderobject,gameobj,converter); - // TODO: expand to multiple ipos per mesh - Material *mat = give_current_material(blenderobject, 1); - if(mat) BL_ConvertMaterialIpos(mat, gameobj, converter); - + BL_ConvertMaterialIpos(blenderobject, gameobj, converter); + sumolist->Add(gameobj->AddRef()); BL_ConvertProperties(blenderobject,gameobj,timemgr,kxscene,isInActiveLayer); @@ -1961,7 +1986,29 @@ void BL_ConvertBlenderObjects(struct Main* maggie, float* fl = (float*) blenderobject->parentinv; MT_Transform parinvtrans(fl); parentinversenode->SetLocalPosition(parinvtrans.getOrigin()); - parentinversenode->SetLocalOrientation(parinvtrans.getBasis()); + // problem here: the parent inverse transform combines scaling and rotation + // in the basis but the scenegraph needs separate rotation and scaling. + // This is not important for OpenGL (it uses 4x4 matrix) but it is important + // for the physic engine that needs a separate scaling + //parentinversenode->SetLocalOrientation(parinvtrans.getBasis()); + + // Extract the rotation and the scaling from the basis + MT_Matrix3x3 ori(parinvtrans.getBasis()); + MT_Vector3 x(ori.getColumn(0)); + MT_Vector3 y(ori.getColumn(1)); + MT_Vector3 z(ori.getColumn(2)); + MT_Vector3 scale(x.length(), y.length(), z.length()); + if (!MT_fuzzyZero(scale[0])) + x /= scale[0]; + if (!MT_fuzzyZero(scale[1])) + y /= scale[1]; + if (!MT_fuzzyZero(scale[2])) + z /= scale[2]; + ori.setColumn(0, x); + ori.setColumn(1, y); + ori.setColumn(2, z); + parentinversenode->SetLocalOrientation(ori); + parentinversenode->SetLocalScale(scale); parentinversenode->AddChild(gameobj->GetSGNode()); } @@ -1969,8 +2016,8 @@ void BL_ConvertBlenderObjects(struct Main* maggie, // needed for python scripting logicmgr->RegisterGameObjectName(gameobj->GetName(),gameobj); - // needed for dynamic object morphing - logicmgr->RegisterGameObj(gameobj, blenderobject); + // needed for group duplication + logicmgr->RegisterGameObj(blenderobject, gameobj); for (int i = 0; i < gameobj->GetMeshCount(); i++) logicmgr->RegisterGameMeshName(gameobj->GetMesh(i)->GetName(), blenderobject); @@ -1987,40 +2034,258 @@ void BL_ConvertBlenderObjects(struct Main* maggie, if (isInActiveLayer) { objectlist->Add(gameobj->AddRef()); - tf.Add(gameobj->GetSGNode()); + //tf.Add(gameobj->GetSGNode()); gameobj->NodeUpdateGS(0,true); - gameobj->Bucketize(); - + gameobj->AddMeshUser(); + } + else + { + //we must store this object otherwise it will be deleted + //at the end of this function if it is not a root object + inactivelist->Add(gameobj->AddRef()); + } + if (gameobj->IsDupliGroup()) + grouplist.insert(blenderobject->dup_group); if (converter->addInitFromFrame){ gameobj->NodeSetLocalPosition(posPrev); gameobj->NodeSetLocalOrientation(angor); } } - - base = base->next; + /* Note about memory leak issues: + When a CValue derived class is created, m_refcount is initialized to 1 + so the class must be released after being used to make sure that it won't + hang in memory. If the object needs to be stored for a long time, + use AddRef() so that this Release() does not free the object. + Make sure that for any AddRef() there is a Release()!!!! + Do the same for any object derived from CValue, CExpression and NG_NetworkMessage + */ + if (gameobj) + gameobj->Release(); + + } + + if (!grouplist.empty()) + { + // now convert the group referenced by dupli group object + // keep track of all groups already converted + set<Group*> allgrouplist = grouplist; + set<Group*> tempglist; + // recurse + while (!grouplist.empty()) + { + set<Group*>::iterator git; + tempglist.clear(); + tempglist.swap(grouplist); + for (git=tempglist.begin(); git!=tempglist.end(); git++) + { + Group* group = *git; + GroupObject* go; + for(go=(GroupObject*)group->gobject.first; go; go=(GroupObject*)go->next) + { + Object* blenderobject = go->ob; + if (converter->FindGameObject(blenderobject) == NULL) + { + allblobj.insert(blenderobject); + groupobj.insert(blenderobject); + KX_GameObject* gameobj = gameobject_from_blenderobject( + blenderobject, + kxscene, + rendertools, + converter, + blenderscene); + + // this code is copied from above except that + // object from groups are never in active layer + bool isInActiveLayer = false; + bool addobj=true; + + if (converter->addInitFromFrame) + if (!isInActiveLayer) + addobj=false; + + if (gameobj&&addobj) + { + MT_Point3 posPrev; + MT_Matrix3x3 angor; + if (converter->addInitFromFrame) + blenderscene->r.cfra=blenderscene->r.sfra; + + MT_Point3 pos = MT_Point3( + blenderobject->loc[0]+blenderobject->dloc[0], + blenderobject->loc[1]+blenderobject->dloc[1], + blenderobject->loc[2]+blenderobject->dloc[2] + ); + MT_Vector3 eulxyz = MT_Vector3( + blenderobject->rot[0], + blenderobject->rot[1], + blenderobject->rot[2] + ); + MT_Vector3 scale = MT_Vector3( + blenderobject->size[0], + blenderobject->size[1], + blenderobject->size[2] + ); + if (converter->addInitFromFrame){//rcruiz + float eulxyzPrev[3]; + blenderscene->r.cfra=blenderscene->r.sfra-1; + update_for_newframe(); + MT_Vector3 tmp=pos-MT_Point3(blenderobject->loc[0]+blenderobject->dloc[0], + blenderobject->loc[1]+blenderobject->dloc[1], + blenderobject->loc[2]+blenderobject->dloc[2] + ); + eulxyzPrev[0]=blenderobject->rot[0]; + eulxyzPrev[1]=blenderobject->rot[1]; + eulxyzPrev[2]=blenderobject->rot[2]; + + double fps = (double) blenderscene->r.frs_sec/ + (double) blenderscene->r.frs_sec_base; + + tmp.scale(fps, fps, fps); + inivel.push_back(tmp); + tmp=eulxyz-eulxyzPrev; + tmp.scale(fps, fps, fps); + iniang.push_back(tmp); + blenderscene->r.cfra=blenderscene->r.sfra; + update_for_newframe(); + } + + gameobj->NodeSetLocalPosition(pos); + gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz)); + gameobj->NodeSetLocalScale(scale); + gameobj->NodeUpdateGS(0,true); + + BL_ConvertIpos(blenderobject,gameobj,converter); + BL_ConvertMaterialIpos(blenderobject,gameobj, converter); + + sumolist->Add(gameobj->AddRef()); + + BL_ConvertProperties(blenderobject,gameobj,timemgr,kxscene,isInActiveLayer); + + + gameobj->SetName(blenderobject->id.name); + + // templist to find Root Parents (object with no parents) + templist->Add(gameobj->AddRef()); + + // update children/parent hierarchy + if ((blenderobject->parent != 0)&&(!converter->addInitFromFrame)) + { + // blender has an additional 'parentinverse' offset in each object + SG_Node* parentinversenode = new SG_Node(NULL,NULL,SG_Callbacks()); + + // define a normal parent relationship for this node. + KX_NormalParentRelation * parent_relation = KX_NormalParentRelation::New(); + parentinversenode->SetParentRelation(parent_relation); + + parentChildLink pclink; + pclink.m_blenderchild = blenderobject; + pclink.m_gamechildnode = parentinversenode; + vec_parent_child.push_back(pclink); + + float* fl = (float*) blenderobject->parentinv; + MT_Transform parinvtrans(fl); + parentinversenode->SetLocalPosition(parinvtrans.getOrigin()); + + // Extract the rotation and the scaling from the basis + MT_Matrix3x3 ori(parinvtrans.getBasis()); + MT_Vector3 x(ori.getColumn(0)); + MT_Vector3 y(ori.getColumn(1)); + MT_Vector3 z(ori.getColumn(2)); + MT_Vector3 scale(x.length(), y.length(), z.length()); + if (!MT_fuzzyZero(scale[0])) + x /= scale[0]; + if (!MT_fuzzyZero(scale[1])) + y /= scale[1]; + if (!MT_fuzzyZero(scale[2])) + z /= scale[2]; + ori.setColumn(0, x); + ori.setColumn(1, y); + ori.setColumn(2, z); + parentinversenode->SetLocalOrientation(ori); + parentinversenode->SetLocalScale(scale); + + parentinversenode->AddChild(gameobj->GetSGNode()); + } + + // needed for python scripting + logicmgr->RegisterGameObjectName(gameobj->GetName(),gameobj); + + // needed for group duplication + logicmgr->RegisterGameObj(blenderobject, gameobj); + for (int i = 0; i < gameobj->GetMeshCount(); i++) + logicmgr->RegisterGameMeshName(gameobj->GetMesh(i)->GetName(), blenderobject); + + converter->RegisterGameObject(gameobj, blenderobject); + // this was put in rapidly, needs to be looked at more closely + // only draw/use objects in active 'blender' layers + + logicbrick_conversionlist->Add(gameobj->AddRef()); + + if (converter->addInitFromFrame){ + posPrev=gameobj->NodeGetWorldPosition(); + angor=gameobj->NodeGetWorldOrientation(); + } + if (isInActiveLayer) + { + objectlist->Add(gameobj->AddRef()); + //tf.Add(gameobj->GetSGNode()); + + gameobj->NodeUpdateGS(0,true); + gameobj->AddMeshUser(); + } + else + { + //we must store this object otherwise it will be deleted + //at the end of this function if it is not a root object + inactivelist->Add(gameobj->AddRef()); + + } + if (gameobj->IsDupliGroup()) + { + // check that the group is not already converted + if (allgrouplist.insert(blenderobject->dup_group).second) + grouplist.insert(blenderobject->dup_group); + } + if (converter->addInitFromFrame){ + gameobj->NodeSetLocalPosition(posPrev); + gameobj->NodeSetLocalOrientation(angor); + } + + } + if (gameobj) + gameobj->Release(); + } + } + } + } } - if (blenderscene->camera) { + // non-camera objects not supported as camera currently + if (blenderscene->camera && blenderscene->camera->type == OB_CAMERA) { KX_Camera *gamecamera= (KX_Camera*) converter->FindGameObject(blenderscene->camera); - kxscene->SetActiveCamera(gamecamera); + if(gamecamera) + kxscene->SetActiveCamera(gamecamera); } // Set up armatures - for (base = static_cast<Base*>(blenderscene->base.first); base; base=base->next){ - if (base->object->type==OB_MESH){ - Mesh *me = (Mesh*)base->object->data; + set<Object*>::iterator oit; + for(oit=allblobj.begin(); oit!=allblobj.end(); oit++) + { + Object* blenderobj = *oit; + if (blenderobj->type==OB_MESH) { + Mesh *me = (Mesh*)blenderobj->data; if (me->dvert){ - KX_GameObject *obj = converter->FindGameObject(base->object); + BL_DeformableGameObject *obj = (BL_DeformableGameObject*)converter->FindGameObject(blenderobj); - if (base->object->parent && base->object->parent->type==OB_ARMATURE && base->object->partype==PARSKEL){ - KX_GameObject *par = converter->FindGameObject(base->object->parent); - if (par) - ((BL_SkinDeformer*)(((BL_DeformableGameObject*)obj)->m_pDeformer))->SetArmature((BL_ArmatureObject*) par); + if (obj && blenderobj->parent && blenderobj->parent->type==OB_ARMATURE && blenderobj->partype==PARSKEL){ + KX_GameObject *par = converter->FindGameObject(blenderobj->parent); + if (par && obj->GetDeformer()) + ((BL_SkinDeformer*)obj->GetDeformer())->SetArmature((BL_ArmatureObject*) par); } } } @@ -2034,6 +2299,41 @@ void BL_ConvertBlenderObjects(struct Main* maggie, { struct Object* blenderchild = pcit->m_blenderchild; + struct Object* blenderparent = blenderchild->parent; + KX_GameObject* parentobj = converter->FindGameObject(blenderparent); + KX_GameObject* childobj = converter->FindGameObject(blenderchild); + + assert(childobj); + + if (!parentobj || objectlist->SearchValue(childobj) != objectlist->SearchValue(parentobj)) + { + // special case: the parent and child object are not in the same layer. + // This weird situation is used in Apricot for test purposes. + // Resolve it by not converting the child + childobj->GetSGNode()->DisconnectFromParent(); + delete pcit->m_gamechildnode; + // Now destroy the child object but also all its descendent that may already be linked + // Remove the child reference in the local list! + // Note: there may be descendents already if the children of the child were processed + // by this loop before the child. In that case, we must remove the children also + CListValue* childrenlist = (CListValue*)childobj->PyGetChildrenRecursive(childobj); + childrenlist->Add(childobj->AddRef()); + for ( i=0;i<childrenlist->GetCount();i++) + { + KX_GameObject* obj = static_cast<KX_GameObject*>(childrenlist->GetValue(i)); + if (templist->RemoveValue(obj)) + obj->Release(); + if (sumolist->RemoveValue(obj)) + obj->Release(); + if (logicbrick_conversionlist->RemoveValue(obj)) + obj->Release(); + } + childrenlist->Release(); + // now destroy recursively + kxscene->RemoveObject(childobj); + continue; + } + switch (blenderchild->partype) { case PARVERT1: @@ -2054,8 +2354,11 @@ void BL_ConvertBlenderObjects(struct Main* maggie, { // parent this to a bone Bone *parent_bone = get_named_bone(get_armature(blenderchild->parent), blenderchild->parsubstr); - KX_BoneParentRelation *bone_parent_relation = KX_BoneParentRelation::New(parent_bone); - pcit->m_gamechildnode->SetParentRelation(bone_parent_relation); + + if(parent_bone) { + KX_BoneParentRelation *bone_parent_relation = KX_BoneParentRelation::New(parent_bone); + pcit->m_gamechildnode->SetParentRelation(bone_parent_relation); + } break; } @@ -2070,12 +2373,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, break; } - struct Object* blenderparent = blenderchild->parent; - KX_GameObject* parentobj = converter->FindGameObject(blenderparent); - if (parentobj) - { - parentobj-> GetSGNode()->AddChild(pcit->m_gamechildnode); - } + parentobj-> GetSGNode()->AddChild(pcit->m_gamechildnode); } vec_parent_child.clear(); @@ -2103,7 +2401,8 @@ void BL_ConvertBlenderObjects(struct Main* maggie, { meshobj = gameobj->GetMesh(0); } - BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,activeLayerBitInfo,physics_engine,converter,processCompoundChildren); + int layerMask = (groupobj.find(blenderobject) == groupobj.end()) ? activeLayerBitInfo : 0; + BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,layerMask,physics_engine,converter,processCompoundChildren); } processCompoundChildren = true; @@ -2118,7 +2417,8 @@ void BL_ConvertBlenderObjects(struct Main* maggie, { meshobj = gameobj->GetMesh(0); } - BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,activeLayerBitInfo,physics_engine,converter,processCompoundChildren); + int layerMask = (groupobj.find(blenderobject) == groupobj.end()) ? activeLayerBitInfo : 0; + BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,layerMask,physics_engine,converter,processCompoundChildren); } @@ -2140,70 +2440,71 @@ void BL_ConvertBlenderObjects(struct Main* maggie, { KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); struct Object* blenderobject = converter->FindBlenderObject(gameobj); - int nummeshes = gameobj->GetMeshCount(); - RAS_MeshObject* meshobj = 0; - ListBase *conlist; - bConstraint *curcon; - conlist = get_active_constraints2(blenderobject); - if (conlist) { - for (curcon = (bConstraint *)conlist->first; curcon; curcon=(bConstraint *)curcon->next) { - if (curcon->type==CONSTRAINT_TYPE_RIGIDBODYJOINT){ - bRigidBodyJointConstraint *dat=(bRigidBodyJointConstraint *)curcon->data; - //if (dat->tar) - if (!dat->child){ - PHY_IPhysicsController* physctr2 = 0; - if (dat->tar) - { - KX_GameObject *gotar=getGameOb(dat->tar->id.name,sumolist); - if (gotar && gotar->GetPhysicsController()) - physctr2 = (PHY_IPhysicsController*) gotar->GetPhysicsController()->GetUserData(); - } + ListBase *conlist; + bConstraint *curcon; + conlist = get_active_constraints2(blenderobject); - if (gameobj->GetPhysicsController()) - { - float radsPerDeg = 6.283185307179586232f / 360.f; + if (conlist) { + for (curcon = (bConstraint *)conlist->first; curcon; curcon=(bConstraint *)curcon->next) { + if (curcon->type==CONSTRAINT_TYPE_RIGIDBODYJOINT){ + + bRigidBodyJointConstraint *dat=(bRigidBodyJointConstraint *)curcon->data; + + if (!dat->child){ + + PHY_IPhysicsController* physctr2 = 0; - PHY_IPhysicsController* physctrl = (PHY_IPhysicsController*) gameobj->GetPhysicsController()->GetUserData(); - //we need to pass a full constraint frame, not just axis + if (dat->tar) + { + KX_GameObject *gotar=getGameOb(dat->tar->id.name,sumolist); + if (gotar && gotar->GetPhysicsController()) + physctr2 = (PHY_IPhysicsController*) gotar->GetPhysicsController()->GetUserData(); + } + + if (gameobj->GetPhysicsController()) + { + float radsPerDeg = 6.283185307179586232f / 360.f; + + PHY_IPhysicsController* physctrl = (PHY_IPhysicsController*) gameobj->GetPhysicsController()->GetUserData(); + //we need to pass a full constraint frame, not just axis - //localConstraintFrameBasis - MT_Matrix3x3 localCFrame(MT_Vector3(radsPerDeg*dat->axX,radsPerDeg*dat->axY,radsPerDeg*dat->axZ)); - MT_Vector3 axis0 = localCFrame.getColumn(0); - MT_Vector3 axis1 = localCFrame.getColumn(1); - MT_Vector3 axis2 = localCFrame.getColumn(2); + //localConstraintFrameBasis + MT_Matrix3x3 localCFrame(MT_Vector3(radsPerDeg*dat->axX,radsPerDeg*dat->axY,radsPerDeg*dat->axZ)); + MT_Vector3 axis0 = localCFrame.getColumn(0); + MT_Vector3 axis1 = localCFrame.getColumn(1); + MT_Vector3 axis2 = localCFrame.getColumn(2); - int constraintId = kxscene->GetPhysicsEnvironment()->createConstraint(physctrl,physctr2,(PHY_ConstraintType)dat->type,(float)dat->pivX,(float)dat->pivY,(float)dat->pivZ, + int constraintId = kxscene->GetPhysicsEnvironment()->createConstraint(physctrl,physctr2,(PHY_ConstraintType)dat->type,(float)dat->pivX, + (float)dat->pivY,(float)dat->pivZ, (float)axis0.x(),(float)axis0.y(),(float)axis0.z(), (float)axis1.x(),(float)axis1.y(),(float)axis1.z(), - (float)axis2.x(),(float)axis2.y(),(float)axis2.z() - ); - if (constraintId) + (float)axis2.x(),(float)axis2.y(),(float)axis2.z(),dat->flag); + if (constraintId) + { + //if it is a generic 6DOF constraint, set all the limits accordingly + if (dat->type == PHY_GENERIC_6DOF_CONSTRAINT) { - //if it is a generic 6DOF constraint, set all the limits accordingly - if (dat->type == PHY_GENERIC_6DOF_CONSTRAINT) + int dof; + int dofbit=1; + for (dof=0;dof<6;dof++) { - int dof; - int dofbit=1; - for (dof=0;dof<6;dof++) + if (dat->flag & dofbit) + { + kxscene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,dat->minLimit[dof],dat->maxLimit[dof]); + } else { - if (dat->flag & dofbit) - { - kxscene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,dat->minLimit[dof],dat->maxLimit[dof]); - } else - { - //minLimit > maxLimit means free(disabled limit) for this degree of freedom - kxscene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,1,-1); - } - dofbit<<=1; + //minLimit > maxLimit means free(disabled limit) for this degree of freedom + kxscene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,1,-1); } + dofbit<<=1; } } } - } - } - } - } - + } + } + } + } + } } templist->Release(); @@ -2239,23 +2540,35 @@ void BL_ConvertBlenderObjects(struct Main* maggie, { KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i)); struct Object* blenderobj = converter->FindBlenderObject(gameobj); - bool isInActiveLayer = (blenderobj->lay & activeLayerBitInfo)!=0; - BL_ConvertActuators(maggie->name, blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,executePriority, activeLayerBitInfo,isInActiveLayer,rendertools,converter); + int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; + bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; + BL_ConvertActuators(maggie->name, blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,executePriority, layerMask,isInActiveLayer,rendertools,converter); } for ( i=0;i<logicbrick_conversionlist->GetCount();i++) { KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i)); struct Object* blenderobj = converter->FindBlenderObject(gameobj); - bool isInActiveLayer = (blenderobj->lay & activeLayerBitInfo)!=0; - BL_ConvertControllers(blenderobj,gameobj,logicmgr,pythondictionary,executePriority,activeLayerBitInfo,isInActiveLayer,converter); + int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; + bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; + BL_ConvertControllers(blenderobj,gameobj,logicmgr,pythondictionary,executePriority,layerMask,isInActiveLayer,converter); } for ( i=0;i<logicbrick_conversionlist->GetCount();i++) { KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i)); struct Object* blenderobj = converter->FindBlenderObject(gameobj); - bool isInActiveLayer = (blenderobj->lay & activeLayerBitInfo)!=0; - BL_ConvertSensors(blenderobj,gameobj,logicmgr,kxscene,keydev,executePriority,activeLayerBitInfo,isInActiveLayer,canvas,converter); + int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; + bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; + BL_ConvertSensors(blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,keydev,executePriority,layerMask,isInActiveLayer,canvas,converter); + // set the init state to all objects + gameobj->SetInitState((blenderobj->init_state)?blenderobj->init_state:blenderobj->state); } + // apply the initial state to controllers, only on the active objects as this registers the sensors + for ( i=0;i<objectlist->GetCount();i++) + { + KX_GameObject* gameobj = static_cast<KX_GameObject*>(objectlist->GetValue(i)); + gameobj->ResetState(); + } + #endif //CONVERT_LOGIC logicbrick_conversionlist->Release(); @@ -2263,5 +2576,24 @@ void BL_ConvertBlenderObjects(struct Main* maggie, // Calculate the scene btree - // too slow - commented out. //kxscene->SetNodeTree(tf.MakeTree()); + + // instantiate dupli group, we will loop trough the object + // that are in active layers. Note that duplicating group + // has the effect of adding objects at the end of objectlist. + // Only loop through the first part of the list. + int objcount = objectlist->GetCount(); + for (i=0;i<objcount;i++) + { + KX_GameObject* gameobj = (KX_GameObject*) objectlist->GetValue(i); + if (gameobj->IsDupliGroup()) + { + kxscene->DupliGroupRecurse(gameobj, 0); + } + } + + KX_Camera *activecam = kxscene->GetActiveCamera(); + MT_Scalar distance = (activecam)? activecam->GetCameraFar() - activecam->GetCameraNear(): 100.0f; + RAS_BucketManager *bucketmanager = kxscene->GetBucketManager(); + bucketmanager->OptimizeBuckets(distance); } diff --git a/source/gameengine/Converter/BL_DeformableGameObject.cpp b/source/gameengine/Converter/BL_DeformableGameObject.cpp index 68a2e41ca47..e2610d2b405 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> @@ -39,12 +41,14 @@ BL_DeformableGameObject::~BL_DeformableGameObject() delete m_pDeformer; // __NLA : Temporary until we decide where to put this } -void BL_DeformableGameObject::ProcessReplica(KX_GameObject* replica) +void BL_DeformableGameObject::ProcessReplica(KX_GameObject* replica) { + BL_MeshDeformer *deformer; KX_GameObject::ProcessReplica(replica); - if (m_pDeformer){ - ((BL_DeformableGameObject*)replica)->m_pDeformer = m_pDeformer->GetReplica(); + if (m_pDeformer) { + deformer = (BL_MeshDeformer*)m_pDeformer->GetReplica(replica); + ((BL_DeformableGameObject*)replica)->m_pDeformer = deformer; } } @@ -60,3 +64,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..126a1fcb1e7 100644 --- a/source/gameengine/Converter/BL_DeformableGameObject.h +++ b/source/gameengine/Converter/BL_DeformableGameObject.h @@ -34,29 +34,74 @@ #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) m_pDeformer->Relink (map); + KX_GameObject::Relink(map); }; 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; + } + + virtual void SetDeformer(class RAS_Deformer* deformer) + { + m_pDeformer = deformer; + } + virtual class RAS_Deformer* GetDeformer() + { + return m_pDeformer; + } + +public: + +protected: + + RAS_Deformer *m_pDeformer; + + 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 ab31179b047..fa3b8185fe2 100644 --- a/source/gameengine/Converter/BL_MeshDeformer.cpp +++ b/source/gameengine/Converter/BL_MeshDeformer.cpp @@ -39,118 +39,193 @@ #endif #include "RAS_IPolygonMaterial.h" +#include "BL_DeformableGameObject.h" #include "BL_MeshDeformer.h" #include "BL_SkinMeshObject.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BLI_arithb.h" #include "GEN_Map.h" #include "STR_HashedString.h" - -bool BL_MeshDeformer::Apply(RAS_IPolyMaterial *mat) +bool BL_MeshDeformer::Apply(RAS_IPolyMaterial*) { - size_t i, j, index; - vecVertexArray array; - vecIndexArrays mvarray; - vecIndexArrays diarray; - - RAS_TexVert *tv; - MVert *mvert; - - // For each material - 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 - for (j=0; j<array[i]->size(); j++){ - tv = &((*array[i])[j]); - index = ((*diarray[i])[j]); - - mvert = &(m_bmesh->mvert[((*mvarray[i])[index])]); - tv->SetXYZ(MT_Point3(mvert->co)); + size_t i; + float *co; + + // only apply once per frame if the mesh is actually modified + if(m_pMeshObject->MeshModified() && + m_lastDeformUpdate != m_gameobj->GetLastFrame()) { + // For each material + for(list<RAS_MeshMaterial>::iterator mit= m_pMeshObject->GetFirstMaterial(); + mit != m_pMeshObject->GetLastMaterial(); ++ mit) { + if(!mit->m_slots[(void*)m_gameobj]) + continue; + + RAS_MeshSlot *slot = *mit->m_slots[(void*)m_gameobj]; + RAS_MeshSlot::iterator it; + + // for each array + for(slot->begin(it); !slot->end(it); slot->next(it)) { + // For each vertex + for(i=it.startvertex; i<it.endvertex; i++) { + RAS_TexVert& v = it.vertex[i]; + co = m_bmesh->mvert[v.getOrigIndex()].co; + v.SetXYZ(MT_Point3(co)); + } + } } + + m_lastDeformUpdate = m_gameobj->GetLastFrame(); + + return true; } - return true; + + return false; } BL_MeshDeformer::~BL_MeshDeformer() { if (m_transverts) - delete []m_transverts; + delete [] m_transverts; if (m_transnors) - delete []m_transnors; -}; + delete [] m_transnors; +} + +void BL_MeshDeformer::Relink(GEN_Map<class GEN_HashedPtr, void*>*map) +{ + void **h_obj = (*map)[m_gameobj]; + + if (h_obj) + m_gameobj = (BL_DeformableGameObject*)(*h_obj); + else + m_gameobj = NULL; +} /** * @warning This function is expensive! */ void BL_MeshDeformer::RecalcNormals() { - int v, f; - float fnor[3], co1[3], co2[3], co3[3], co4[3]; + /* We don't normalize for performance, not doing it for faces normals + * gives area-weight normals which often look better anyway, and use + * GL_NORMALIZE so we don't have to do per vertex normalization either + * since the GPU can do it faster */ + list<RAS_MeshMaterial>::iterator mit; + RAS_MeshSlot::iterator it; + size_t i; - /* Clear all vertex normal accumulators */ - for (v =0; v<m_bmesh->totvert; v++){ - m_transnors[v]=MT_Point3(0,0,0); - } - - /* Find the face normals */ - for (f = 0; f<m_bmesh->totface; f++){ - // Make new face normal based on the transverts - MFace *mf= &((MFace*)m_bmesh->mface)[f]; - - if (mf->v3) { - for (int vl=0; vl<3; vl++){ - co1[vl]=m_transverts[mf->v1][vl]; - co2[vl]=m_transverts[mf->v2][vl]; - co3[vl]=m_transverts[mf->v3][vl]; - if (mf->v4) - co4[vl]=m_transverts[mf->v4][vl]; + /* set vertex normals to zero */ + memset(m_transnors, 0, sizeof(float)*3*m_bmesh->totvert); + + /* add face normals to vertices. */ + for(mit = m_pMeshObject->GetFirstMaterial(); + mit != m_pMeshObject->GetLastMaterial(); ++ mit) { + if(!mit->m_slots[(void*)m_gameobj]) + continue; + + RAS_MeshSlot *slot = *mit->m_slots[(void*)m_gameobj]; + + for(slot->begin(it); !slot->end(it); slot->next(it)) { + int nvert = (int)it.array->m_type; + + for(i=0; i<it.totindex; i+=nvert) { + RAS_TexVert& v1 = it.vertex[it.index[i]]; + RAS_TexVert& v2 = it.vertex[it.index[i+1]]; + RAS_TexVert& v3 = it.vertex[it.index[i+2]]; + RAS_TexVert *v4 = NULL; + + const float *co1 = v1.getXYZ(); + const float *co2 = v2.getXYZ(); + const float *co3 = v3.getXYZ(); + const float *co4 = NULL; + + /* compute face normal */ + float fnor[3], n1[3], n2[3]; + + if(nvert == 4) { + v4 = &it.vertex[it.index[i+3]]; + co4 = v4->getXYZ(); + + n1[0]= co1[0]-co3[0]; + n1[1]= co1[1]-co3[1]; + n1[2]= co1[2]-co3[2]; + + n2[0]= co2[0]-co4[0]; + n2[1]= co2[1]-co4[1]; + n2[2]= co2[2]-co4[2]; + } + else { + n1[0]= co1[0]-co2[0]; + n2[0]= co2[0]-co3[0]; + n1[1]= co1[1]-co2[1]; + + n2[1]= co2[1]-co3[1]; + n1[2]= co1[2]-co2[2]; + n2[2]= co2[2]-co3[2]; + } + + fnor[0]= n1[1]*n2[2] - n1[2]*n2[1]; + fnor[1]= n1[2]*n2[0] - n1[0]*n2[2]; + fnor[2]= n1[0]*n2[1] - n1[1]*n2[0]; + + /* add to vertices for smooth normals */ + float *vn1 = m_transnors[v1.getOrigIndex()]; + float *vn2 = m_transnors[v2.getOrigIndex()]; + float *vn3 = m_transnors[v3.getOrigIndex()]; + + vn1[0] += fnor[0]; vn1[1] += fnor[1]; vn1[2] += fnor[2]; + vn2[0] += fnor[0]; vn2[1] += fnor[1]; vn2[2] += fnor[2]; + vn3[0] += fnor[0]; vn3[1] += fnor[1]; vn3[2] += fnor[2]; + + if(v4) { + float *vn4 = m_transnors[v4->getOrigIndex()]; + vn4[0] += fnor[0]; vn4[1] += fnor[1]; vn4[2] += fnor[2]; + } + + /* in case of flat - just assign, the vertices are split */ + if(v1.getFlag() & RAS_TexVert::FLAT) { + v1.SetNormal(fnor); + v2.SetNormal(fnor); + v3.SetNormal(fnor); + if(v4) + v4->SetNormal(fnor); + } } + } + } + + /* assign smooth vertex normals */ + for(mit = m_pMeshObject->GetFirstMaterial(); + mit != m_pMeshObject->GetLastMaterial(); ++ mit) { + if(!mit->m_slots[(void*)m_gameobj]) + continue; + + RAS_MeshSlot *slot = *mit->m_slots[(void*)m_gameobj]; + + for(slot->begin(it); !slot->end(it); slot->next(it)) { + for(i=it.startvertex; i<it.endvertex; i++) { + RAS_TexVert& v = it.vertex[i]; - /* FIXME: Use moto */ - if (mf->v4) - CalcNormFloat4(co1, co2, co3, co4, fnor); - else - CalcNormFloat(co1, co2, co3, fnor); - - /* Decide which normals are affected by this face's normal */ - m_transnors[mf->v1]+=MT_Point3(fnor); - m_transnors[mf->v2]+=MT_Point3(fnor); - m_transnors[mf->v3]+=MT_Point3(fnor); - if (mf->v4) - m_transnors[mf->v4]+=MT_Point3(fnor); + if(!(v.getFlag() & RAS_TexVert::FLAT)) + v.SetNormal(m_transnors[v.getOrigIndex()]); //.safe_normalized() + } } } - - for (v =0; v<m_bmesh->totvert; v++){ -// float nor[3]; - - m_transnors[v]=m_transnors[v].safe_normalized(); -// nor[0]=m_transnors[v][0]; -// nor[1]=m_transnors[v][1]; -// nor[2]=m_transnors[v][2]; - - }; } 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; + delete [] m_transverts; if (m_transnors) - delete []m_transnors; + delete [] m_transnors; - m_transnors =new MT_Point3[m_bmesh->totvert+m_bmesh->totface]; - m_transverts=new float[(sizeof(*m_transverts)*m_bmesh->totvert)][3]; + m_transverts=new float[m_bmesh->totvert][3]; + m_transnors=new float[m_bmesh->totvert][3]; m_tvtot = m_bmesh->totvert; } } - + diff --git a/source/gameengine/Converter/BL_MeshDeformer.h b/source/gameengine/Converter/BL_MeshDeformer.h index a6be11d786e..8de59c1cdf3 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> @@ -39,38 +40,47 @@ #pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning #endif //WIN32 +class BL_DeformableGameObject; + class BL_MeshDeformer : public RAS_Deformer { public: void VerifyStorage(); void RecalcNormals(); - virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map){}; - BL_MeshDeformer(struct Object* obj, class BL_SkinMeshObject *meshobj ): + virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map); + BL_MeshDeformer(BL_DeformableGameObject *gameobj, + struct Object* obj, + class BL_SkinMeshObject *meshobj ): m_pMeshObject(meshobj), m_bmesh((struct Mesh*)(obj->data)), + m_transverts(0), + m_transnors(0), m_objMesh(obj), - m_transnors(NULL), - m_transverts(NULL), - m_tvtot(0) + m_tvtot(0), + m_gameobj(gameobj), + m_lastDeformUpdate(-1) {}; virtual ~BL_MeshDeformer(); virtual void SetSimulatedTime(double time){}; virtual bool Apply(class RAS_IPolyMaterial *mat); - virtual void Update(void){}; - virtual RAS_Deformer* GetReplica(){return NULL;}; + virtual bool Update(void){ return false; }; + virtual RAS_Deformer* GetReplica(class KX_GameObject* replica){return NULL;}; + struct Mesh* GetMesh() { return m_bmesh; }; // virtual void InitDeform(double time){}; + protected: class BL_SkinMeshObject* m_pMeshObject; struct Mesh* m_bmesh; - MT_Point3* m_transnors; - //MT_Point3* m_transverts; // this is so m_transverts doesn't need to be converted // before deformation float (*m_transverts)[3]; + float (*m_transnors)[3]; struct Object* m_objMesh; // -- int m_tvtot; + BL_DeformableGameObject* m_gameobj; + double m_lastDeformUpdate; }; #endif diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.cpp b/source/gameengine/Converter/BL_ShapeActionActuator.cpp new file mode 100644 index 00000000000..46f3141be29 --- /dev/null +++ b/source/gameengine/Converter/BL_ShapeActionActuator.cpp @@ -0,0 +1,842 @@ +/** +* $Id$ +* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** +*/ + +#if defined (__sgi) +#include <math.h> +#else +#include <cmath> +#endif + +#include "SCA_LogicManager.h" +#include "BL_ShapeActionActuator.h" +#include "BL_ActionActuator.h" +#include "BL_ShapeDeformer.h" +#include "KX_GameObject.h" +#include "STR_HashedString.h" +#include "DNA_action_types.h" +#include "DNA_nla_types.h" +#include "DNA_actuator_types.h" +#include "BKE_action.h" +#include "DNA_armature_types.h" +#include "MEM_guardedalloc.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "MT_Matrix4x4.h" +#include "BKE_utildefines.h" +#include "FloatValue.h" +#include "PyObjectPlus.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +BL_ShapeActionActuator::~BL_ShapeActionActuator() +{ +} + +void BL_ShapeActionActuator::ProcessReplica() +{ + m_localtime=m_startframe; + m_lastUpdate=-1; +} + +void BL_ShapeActionActuator::SetBlendTime (float newtime) +{ + m_blendframe = newtime; +} + +CValue* BL_ShapeActionActuator::GetReplica() +{ + BL_ShapeActionActuator* replica = new BL_ShapeActionActuator(*this);//m_float,GetName()); + replica->ProcessReplica(); + + // this will copy properties and so on... + CValue::AddDataToReplica(replica); + return replica; +} + +bool BL_ShapeActionActuator::ClampLocalTime() +{ + if (m_startframe < m_endframe) { + if (m_localtime < m_startframe) + { + m_localtime = m_startframe; + return true; + } + else if (m_localtime > m_endframe) + { + m_localtime = m_endframe; + return true; + } + } else { + if (m_localtime > m_startframe) + { + 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; + 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; + + curtime -= KX_KetsjiEngine::GetSuspendedDelta(); + + // result = true if animation has to be continued, false if animation stops + // maybe there are events for us in the queue ! + 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; + } + + /* 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 (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, (PY_METHODCHAR)SetAction_doc}, + {"setStart", (PyCFunction) BL_ShapeActionActuator::sPySetStart, METH_VARARGS, (PY_METHODCHAR)SetStart_doc}, + {"setEnd", (PyCFunction) BL_ShapeActionActuator::sPySetEnd, METH_VARARGS, (PY_METHODCHAR)SetEnd_doc}, + {"setBlendin", (PyCFunction) BL_ShapeActionActuator::sPySetBlendin, METH_VARARGS, (PY_METHODCHAR)SetBlendin_doc}, + {"setPriority", (PyCFunction) BL_ShapeActionActuator::sPySetPriority, METH_VARARGS, (PY_METHODCHAR)SetPriority_doc}, + {"setFrame", (PyCFunction) BL_ShapeActionActuator::sPySetFrame, METH_VARARGS, (PY_METHODCHAR)SetFrame_doc}, + {"setProperty", (PyCFunction) BL_ShapeActionActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc}, + {"setFrameProperty", (PyCFunction) BL_ShapeActionActuator::sPySetFrameProperty, METH_VARARGS, (PY_METHODCHAR)SetFrameProperty_doc}, + {"setBlendtime", (PyCFunction) BL_ShapeActionActuator::sPySetBlendtime, METH_VARARGS, (PY_METHODCHAR)SetBlendtime_doc}, + + {"getAction", (PyCFunction) BL_ShapeActionActuator::sPyGetAction, METH_NOARGS, (PY_METHODCHAR)GetAction_doc}, + {"getStart", (PyCFunction) BL_ShapeActionActuator::sPyGetStart, METH_NOARGS, (PY_METHODCHAR)GetStart_doc}, + {"getEnd", (PyCFunction) BL_ShapeActionActuator::sPyGetEnd, METH_NOARGS, (PY_METHODCHAR)GetEnd_doc}, + {"getBlendin", (PyCFunction) BL_ShapeActionActuator::sPyGetBlendin, METH_NOARGS, (PY_METHODCHAR)GetBlendin_doc}, + {"getPriority", (PyCFunction) BL_ShapeActionActuator::sPyGetPriority, METH_NOARGS, (PY_METHODCHAR)GetPriority_doc}, + {"getFrame", (PyCFunction) BL_ShapeActionActuator::sPyGetFrame, METH_NOARGS, (PY_METHODCHAR)GetFrame_doc}, + {"getProperty", (PyCFunction) BL_ShapeActionActuator::sPyGetProperty, METH_NOARGS, (PY_METHODCHAR)GetProperty_doc}, + {"getFrameProperty", (PyCFunction) BL_ShapeActionActuator::sPyGetFrameProperty, METH_NOARGS, (PY_METHODCHAR)GetFrameProperty_doc}, + {"getType", (PyCFunction) BL_ShapeActionActuator::sPyGetType, METH_NOARGS, (PY_METHODCHAR)GetType_doc}, + {"setType", (PyCFunction) BL_ShapeActionActuator::sPySetType, METH_NOARGS, (PY_METHODCHAR)SetType_doc}, + {NULL,NULL} //Sentinel +}; + +PyObject* BL_ShapeActionActuator::_getattr(const STR_String& attr) { + _getattr_up(SCA_IActuator); +} + +/* setStart */ +const char BL_ShapeActionActuator::GetAction_doc[] = +"getAction()\n" +"\tReturns a string containing the name of the current action.\n"; + +PyObject* BL_ShapeActionActuator::PyGetAction(PyObject* self) { + if (m_action){ + return PyString_FromString(m_action->id.name+2); + } + Py_RETURN_NONE; +} + +/* getProperty */ +const 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 *result; + + result = Py_BuildValue("s", (const char *)m_propname); + + return result; +} + +/* getFrame */ +const char BL_ShapeActionActuator::GetFrame_doc[] = +"getFrame()\n" +"\tReturns the current frame number.\n"; + +PyObject* BL_ShapeActionActuator::PyGetFrame(PyObject* self) { + PyObject *result; + + result = Py_BuildValue("f", m_localtime); + + return result; +} + +/* getEnd */ +const char BL_ShapeActionActuator::GetEnd_doc[] = +"getEnd()\n" +"\tReturns the last frame of the action.\n"; + +PyObject* BL_ShapeActionActuator::PyGetEnd(PyObject* self) { + PyObject *result; + + result = Py_BuildValue("f", m_endframe); + + return result; +} + +/* getStart */ +const char BL_ShapeActionActuator::GetStart_doc[] = +"getStart()\n" +"\tReturns the starting frame of the action.\n"; + +PyObject* BL_ShapeActionActuator::PyGetStart(PyObject* self) { + PyObject *result; + + result = Py_BuildValue("f", m_startframe); + + return result; +} + +/* getBlendin */ +const char BL_ShapeActionActuator::GetBlendin_doc[] = +"getBlendin()\n" +"\tReturns the number of interpolation animation frames to be\n" +"\tgenerated when this actuator is triggered.\n"; + +PyObject* BL_ShapeActionActuator::PyGetBlendin(PyObject* self) { + PyObject *result; + + result = Py_BuildValue("f", m_blendin); + + return result; +} + +/* getPriority */ +const char BL_ShapeActionActuator::GetPriority_doc[] = +"getPriority()\n" +"\tReturns the priority for this actuator. Actuators with lower\n" +"\tPriority numbers will override actuators with higher numbers.\n"; + +PyObject* BL_ShapeActionActuator::PyGetPriority(PyObject* self) { + PyObject *result; + + result = Py_BuildValue("i", m_priority); + + return result; +} + +/* setAction */ +const char BL_ShapeActionActuator::SetAction_doc[] = +"setAction(action, (reset))\n" +"\t - action : The name of the action to set as the current action.\n" +"\t Should be an action with Shape channels.\n" +"\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; + } + } + else { + return NULL; + } + + Py_RETURN_NONE; +} + +/* setStart */ +const 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; + } + else { + return NULL; + } + + Py_RETURN_NONE; +} + +/* setEnd */ +const 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; + } + else { + return NULL; + } + + Py_RETURN_NONE; +} + +/* setBlendin */ +const char BL_ShapeActionActuator::SetBlendin_doc[] = +"setBlendin(blendin)\n" +"\t - blendin : Specifies the number of frames of animation to generate\n" +"\t when making transitions between actions.\n"; + +PyObject* BL_ShapeActionActuator::PySetBlendin(PyObject* self, + PyObject* args, + PyObject* kwds) { + float blendin; + + if (PyArg_ParseTuple(args,"f",&blendin)) + { + m_blendin = blendin; + } + else { + return NULL; + } + + Py_RETURN_NONE; +} + +/* setBlendtime */ +const char BL_ShapeActionActuator::SetBlendtime_doc[] = +"setBlendtime(blendtime)\n" +"\t - blendtime : Allows the script to directly modify the internal timer\n" +"\t used when generating transitions between actions. This\n" +"\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; + } + else { + return NULL; + } + + Py_RETURN_NONE; +} + +/* setPriority */ +const char BL_ShapeActionActuator::SetPriority_doc[] = +"setPriority(priority)\n" +"\t - priority : Specifies the new priority. Actuators will lower\n" +"\t priority numbers will override actuators with higher\n" +"\t numbers.\n"; + +PyObject* BL_ShapeActionActuator::PySetPriority(PyObject* self, + PyObject* args, + PyObject* kwds) { + int priority; + + if (PyArg_ParseTuple(args,"i",&priority)) + { + m_priority = priority; + } + else { + return NULL; + } + + Py_RETURN_NONE; +} + +/* getProperty */ +const char BL_ShapeActionActuator::GetFrameProperty_doc[] = +"getFrameProperty()\n" +"\tReturns the name of the property, that is set to the current frame number.\n"; + +PyObject* BL_ShapeActionActuator::PyGetFrameProperty(PyObject* self) { + PyObject *result; + + result = Py_BuildValue("s", (const char *)m_framepropname); + + return result; +} + + +/* setFrame */ +const 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; + } + else { + return NULL; + } + + Py_RETURN_NONE; +} + +/* setProperty */ +const char BL_ShapeActionActuator::SetProperty_doc[] = +"setProperty(prop)\n" +"\t - prop : A string specifying the property name to be used in\n" +"\t FromProp playback mode.\n"; + +PyObject* BL_ShapeActionActuator::PySetProperty(PyObject* self, + PyObject* args, + PyObject* kwds) { + char *string; + + if (PyArg_ParseTuple(args,"s",&string)) + { + m_propname = string; + } + else { + return NULL; + } + + Py_RETURN_NONE; +} + +/* setFrameProperty */ +const char BL_ShapeActionActuator::SetFrameProperty_doc[] = +"setFrameProperty(prop)\n" +"\t - prop : A string specifying the property of the frame set up update.\n"; + +PyObject* BL_ShapeActionActuator::PySetFrameProperty(PyObject* self, + PyObject* args, + PyObject* kwds) { + char *string; + + if (PyArg_ParseTuple(args,"s",&string)) + { + m_framepropname = string; + } + else { + return NULL; + } + + Py_RETURN_NONE; +} + +/* getType */ +const char BL_ShapeActionActuator::GetType_doc[] = +"getType()\n" +"\tReturns the operation mode of the actuator.\n"; +PyObject* BL_ShapeActionActuator::PyGetType(PyObject* self) { + return Py_BuildValue("h", m_playtype); +} + +/* setType */ +const char BL_ShapeActionActuator::SetType_doc[] = +"setType(mode)\n" +"\t - mode: Play (0), Flipper (2), LoopStop (3), LoopEnd (4) or Property (6)\n" +"\tSet the operation mode of the actuator.\n"; +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..30b2d41fc67 --- /dev/null +++ b/source/gameengine/Converter/BL_ShapeActionActuator.h @@ -0,0 +1,138 @@ +/** + * $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 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, + const STR_String& framepropname, + 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_framepropname(framepropname), + 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,SetFrameProperty); + KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetBlendtime); + KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetChannel); + + KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetAction); + KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetBlendin); + KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetPriority); + KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetStart); + KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetEnd); + KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetFrame); + KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetProperty); + KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetFrameProperty); +// KX_PYMETHOD(BL_ActionActuator,GetChannel); + KX_PYMETHOD_DOC_NOARGS(BL_ShapeActionActuator,GetType); + KX_PYMETHOD_DOC(BL_ShapeActionActuator,SetType); + + 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; + STR_String m_framepropname; + 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..fc6498579ad --- /dev/null +++ b/source/gameengine/Converter/BL_ShapeDeformer.cpp @@ -0,0 +1,182 @@ +/** + * $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 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 "DNA_ipo_types.h" +#include "DNA_curve_types.h" +#include "BKE_armature.h" +#include "BKE_action.h" +#include "BKE_key.h" +#include "BKE_ipo.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(class KX_GameObject* replica) +{ + BL_ShapeDeformer *result; + + result = new BL_ShapeDeformer(*this); + result->ProcessReplica(); + return result; +} + +void BL_ShapeDeformer::ProcessReplica() +{ +} + +bool BL_ShapeDeformer::LoadShapeDrivers(Object* arma) +{ + IpoCurve *icu; + + m_shapeDrivers.clear(); + // check if this mesh has armature driven shape keys + if (m_bmesh->key->ipo) { + for(icu= (IpoCurve*)m_bmesh->key->ipo->curve.first; icu; icu= (IpoCurve*)icu->next) { + if(icu->driver && + (icu->flag & IPO_MUTE) == 0 && + icu->driver->type == IPO_DRIVER_TYPE_NORMAL && + icu->driver->ob == arma && + icu->driver->blocktype == ID_AR) { + // this shape key ipo curve has a driver on the parent armature + // record this curve in the shape deformer so that the corresponding + m_shapeDrivers.push_back(icu); + } + } + } + return !m_shapeDrivers.empty(); +} + +bool BL_ShapeDeformer::ExecuteShapeDrivers(void) +{ + if (!m_shapeDrivers.empty() && PoseUpdated()) { + vector<IpoCurve*>::iterator it; + void *poin; + int type; + + // the shape drivers use the bone matrix as input. Must + // update the matrix now + m_armobj->ApplyPose(); + + for (it=m_shapeDrivers.begin(); it!=m_shapeDrivers.end(); it++) { + // no need to set a specific time: this curve has a driver + IpoCurve *icu = *it; + calc_icu(icu, 1.0f); + poin = get_ipo_poin((ID*)m_bmesh->key, icu, &type); + if (poin) + write_ipo_poin(poin, type, icu->curval); + } + + ForceUpdate(); + m_armobj->RestorePose(); + + return true; + } + return false; +} + +bool BL_ShapeDeformer::Update(void) +{ + bool bShapeUpdate = false; + bool bSkinUpdate = false; + + ExecuteShapeDrivers(); + + /* 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); + +#ifdef __NLA_DEFNORMALS + RecalcNormals(); +#endif + 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..90b9f5caea1 --- /dev/null +++ b/source/gameengine/Converter/BL_ShapeDeformer.h @@ -0,0 +1,88 @@ +/** + * $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 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> + +struct IpoCurve; + +class BL_ShapeDeformer : public BL_SkinDeformer +{ +public: + BL_ShapeDeformer(BL_DeformableGameObject *gameobj, + Object *bmeshobj, + BL_SkinMeshObject *mesh) + : + BL_SkinDeformer(gameobj,bmeshobj, mesh), + m_lastShapeUpdate(-1) + { + }; + + /* 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(gameobj, bmeshobj_old, bmeshobj_new, mesh, release_object, arma), + m_lastShapeUpdate(-1) + { + }; + + virtual void ProcessReplica(); + virtual RAS_Deformer *GetReplica(class KX_GameObject* replica); + virtual ~BL_ShapeDeformer(); + + bool Update (void); + bool LoadShapeDrivers(Object* arma); + bool ExecuteShapeDrivers(void); + + void ForceUpdate() + { + m_lastShapeUpdate = -1.0; + }; + +protected: + vector<IpoCurve*> m_shapeDrivers; + double m_lastShapeUpdate; + +}; + +#endif + diff --git a/source/gameengine/Converter/BL_SkinDeformer.cpp b/source/gameengine/Converter/BL_SkinDeformer.cpp index d6aee363a16..d8563763954 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.cpp +++ b/source/gameengine/Converter/BL_SkinDeformer.cpp @@ -57,86 +57,96 @@ extern "C"{ #define __NLA_DEFNORMALS //#undef __NLA_DEFNORMALS -BL_SkinDeformer::~BL_SkinDeformer() +BL_SkinDeformer::BL_SkinDeformer(BL_DeformableGameObject *gameobj, + struct Object *bmeshobj, + class BL_SkinMeshObject *mesh, + BL_ArmatureObject* arma) + : // + BL_MeshDeformer(gameobj, bmeshobj, mesh), + m_armobj(arma), + m_lastArmaUpdate(-1), + m_defbase(&bmeshobj->defbase), + m_releaseobject(false), + m_poseApplied(false) { - if(m_releaseobject && m_armobj) - m_armobj->Release(); + Mat4CpyMat4(m_obmat, bmeshobj->obmat); }; -/* XXX note, this __NLA_OLDDEFORM define seems to be obsolete */ +BL_SkinDeformer::BL_SkinDeformer( + BL_DeformableGameObject *gameobj, + struct Object *bmeshobj_old, // Blender object that owns the new mesh + struct Object *bmeshobj_new, // Blender object that owns the original mesh + class BL_SkinMeshObject *mesh, + bool release_object, + BL_ArmatureObject* arma) : + BL_MeshDeformer(gameobj, bmeshobj_old, mesh), + m_armobj(arma), + m_lastArmaUpdate(-1), + m_defbase(&bmeshobj_old->defbase), + m_releaseobject(release_object) + { + // 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 use the matrix of the original object to + // simulate a pure replacement of the mesh. + Mat4CpyMat4(m_obmat, bmeshobj_new->obmat); + } -bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat) +BL_SkinDeformer::~BL_SkinDeformer() { - size_t i, j, index; - vecVertexArray array; -#ifdef __NLA_OLDDEFORM - vecMVertArray mvarray; -#else - vecIndexArrays mvarray; -#endif - vecMDVertArray dvarray; - vecIndexArrays diarray; + if(m_releaseobject && m_armobj) + m_armobj->Release(); +} - RAS_TexVert *tv; -#ifdef __NLA_OLDDEFORM - MVert *mvert; - MDeformVert *dvert; -#endif - MT_Point3 pt; -// float co[3]; +void BL_SkinDeformer::Relink(GEN_Map<class GEN_HashedPtr, void*>*map) +{ + if (m_armobj) { + void **h_obj = (*map)[m_armobj]; - if (!m_armobj) - return false; + if (h_obj) + SetArmature( (BL_ArmatureObject*)(*h_obj) ); + else + m_armobj=NULL; + } - Update(); + BL_MeshDeformer::Relink(map); +} - array = m_pMeshObject->GetVertexCache(mat); -#ifdef __NLA_OLDDEFORM - dvarray = m_pMeshObject->GetDVertCache(mat); -#endif - mvarray = m_pMeshObject->GetMVertCache(mat); - diarray = m_pMeshObject->GetDIndexCache(mat); - +bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat) +{ + RAS_MeshSlot::iterator it; + RAS_MeshMaterial *mmat; + RAS_MeshSlot *slot; + size_t i; - // For each array - for (i=0; i<array.size(); i++){ - // For each vertex - for (j=0; j<array[i]->size(); j++){ - - tv = &((*array[i])[j]); - - index = ((*diarray[i])[j]); -#ifdef __NLA_OLDDEFORM - pt = tv->xyz(); - mvert = ((*mvarray[i])[index]); - dvert = ((*dvarray[i])[index]); -#endif - - // Copy the untransformed data from the original mvert -#ifdef __NLA_OLDDEFORM - co[0]=mvert->co[0]; - co[1]=mvert->co[1]; - co[2]=mvert->co[2]; - - // Do the deformation -/* XXX note, doesnt exist anymore */ -// GB_calc_armature_deform(co, dvert); - tv->SetXYZ(co); -#else - // Set the data - tv->SetXYZ(m_transverts[((*mvarray[i])[index])]); -#ifdef __NLA_DEFNORMALS + // update the vertex in m_transverts + Update(); - tv->SetNormal(m_transnors[((*mvarray[i])[index])]); -#endif -#endif + // 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(mat); + if(!mmat->m_slots[(void*)m_gameobj]) + return true; + + slot = *mmat->m_slots[(void*)m_gameobj]; + + // for each array + for(slot->begin(it); !slot->end(it); slot->next(it)) { + // for each vertex + // copy the untransformed data from the original mvert + for(i=it.startvertex; i<it.endvertex; i++) { + RAS_TexVert& v = it.vertex[i]; + v.SetXYZ(m_transverts[v.getOrigIndex()]); } } - + return true; } -RAS_Deformer *BL_SkinDeformer::GetReplica() +RAS_Deformer *BL_SkinDeformer::GetReplica(class KX_GameObject* replica) { BL_SkinDeformer *result; @@ -151,19 +161,15 @@ 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()){ - - /* Do all of the posing necessary */ - m_armobj->ApplyPose(); - + if (PoseUpdated()){ + float obmat[4][4]; // the original object matrice + /* XXX note: where_is_pose() (from BKE_armature.h) calculates all matrices needed to start deforming */ /* but it requires the blender object pointer... */ - Object* par_arma = m_armobj->GetArmatureObject(); - where_is_pose( par_arma ); /* store verts locally */ VerifyStorage(); @@ -172,12 +178,32 @@ void BL_SkinDeformer::Update(void) for (int v =0; v<m_bmesh->totvert; v++) VECCOPY(m_transverts[v], m_bmesh->mvert[v].co); + m_armobj->ApplyPose(); + + // save matrix first + Mat4CpyMat4(obmat, m_objMesh->obmat); + // set reference matrix + 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(); + + m_armobj->RestorePose(); + + /* 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 f14baf09651..f87860021c6 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.h +++ b/source/gameengine/Converter/BL_SkinDeformer.h @@ -50,56 +50,48 @@ class BL_SkinDeformer : public BL_MeshDeformer { 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) ); - } - else - m_armobj=NULL; - } + virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map); void SetArmature (class BL_ArmatureObject *armobj); - BL_SkinDeformer(struct Object *bmeshobj, + BL_SkinDeformer(BL_DeformableGameObject *gameobj, + 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_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, + BL_SkinDeformer(BL_DeformableGameObject *gameobj, + struct Object *bmeshobj_old, struct Object *bmeshobj_new, class BL_SkinMeshObject *mesh, bool release_object, - BL_ArmatureObject* arma = NULL) - : // - BL_MeshDeformer(bmeshobj_old, mesh), - m_armobj(arma), - m_lastUpdate(-1), - m_defbase(&bmeshobj_old->defbase), - m_releaseobject(release_object) - { - }; + BL_ArmatureObject* arma = NULL); virtual void ProcessReplica(); - virtual RAS_Deformer *GetReplica(); + virtual RAS_Deformer *GetReplica(class KX_GameObject* replica); virtual ~BL_SkinDeformer(); - void Update (void); + bool Update (void); bool Apply (class RAS_IPolyMaterial *polymat); + bool PoseUpdated(void) + { + if (m_armobj && m_lastArmaUpdate!=m_armobj->GetLastFrame()) { + return true; + } + return false; + } + + 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 reference matrix for skeleton deform bool m_releaseobject; + bool m_poseApplied; }; diff --git a/source/gameengine/Converter/BL_SkinMeshObject.cpp b/source/gameengine/Converter/BL_SkinMeshObject.cpp index 8bc78c7f757..eb3f9d0588d 100644 --- a/source/gameengine/Converter/BL_SkinMeshObject.cpp +++ b/source/gameengine/Converter/BL_SkinMeshObject.cpp @@ -28,127 +28,129 @@ * Deformer that supports armature skinning */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #ifdef WIN32 #pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning #endif //WIN32 -#include "RAS_IPolygonMaterial.h" -#include "BL_SkinMeshObject.h" -#include "BL_DeformableGameObject.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_key_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "KX_GameObject.h" + #include "RAS_BucketManager.h" +#include "RAS_IPolygonMaterial.h" -void BL_SkinMeshObject::AddPolygon(RAS_Polygon* poly) -{ - /* We're overriding this so that we can eventually associate faces with verts somehow */ +#include "KX_GameObject.h" - // For vertIndex in poly: - // find the appropriate normal +#include "BL_SkinMeshObject.h" +#include "BL_DeformableGameObject.h" - RAS_MeshObject::AddPolygon(poly); -} +BL_SkinMeshObject::BL_SkinMeshObject(Mesh* mesh, int lightlayer) + : RAS_MeshObject (mesh, lightlayer) +{ + m_bDeformed = true; -#ifdef __NLA_OLDDEFORM -int BL_SkinMeshObject::FindOrAddDeform(int vtxarray, struct MVert *mv, struct MDeformVert *dv, RAS_IPolyMaterial* mat) -#else -int BL_SkinMeshObject::FindOrAddDeform(unsigned int vtxarray, unsigned int mv, struct MDeformVert *dv, RAS_IPolyMaterial* mat) -#endif -{ - BL_SkinArrayOptimizer* ao = (BL_SkinArrayOptimizer*)GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]); - int numvert = ao->m_MvertArrayCache1[vtxarray]->size(); - - /* Check to see if this has already been pushed */ - for (unsigned int i=0; i<ao->m_MvertArrayCache1[vtxarray]->size(); i++){ - if (mv == (*ao->m_MvertArrayCache1[vtxarray])[i]) - return i; + 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); } +} - ao->m_MvertArrayCache1[vtxarray]->push_back(mv); - ao->m_DvertArrayCache1[vtxarray]->push_back(dv); - - return numvert; -}; - -int BL_SkinMeshObject::FindVertexArray(int numverts,RAS_IPolyMaterial* polymat) +BL_SkinMeshObject::~BL_SkinMeshObject() { - int array=-1; - - BL_SkinArrayOptimizer* ao = (BL_SkinArrayOptimizer*)GetArrayOptimizer(polymat); - - - for (size_t i=0;i<ao->m_VertexArrayCache1.size();i++) + if (m_mesh && m_mesh->key) { - if ( (ao->m_TriangleArrayCount[i] + (numverts-2)) < BUCKET_MAX_TRIANGLES) - { - if((ao->m_VertexArrayCache1[i]->size()+numverts < BUCKET_MAX_INDICES)) - { - array = i; - ao->m_TriangleArrayCount[array]+=numverts-2; - break; - } + 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; } } - +} - if (array == -1) - { - array = ao->m_VertexArrayCache1.size(); - - vector<RAS_TexVert>* va = new vector<RAS_TexVert>; - ao->m_VertexArrayCache1.push_back(va); - - KX_IndexArray *ia = new KX_IndexArray(); - ao->m_IndexArrayCache1.push_back(ia); +void BL_SkinMeshObject::UpdateBuckets(void* clientobj,double* oglmatrix,bool useObjectColor,const MT_Vector4& rgbavec, bool visible, bool culled) +{ + list<RAS_MeshMaterial>::iterator it; + list<RAS_MeshSlot*>::iterator sit; -#ifdef __NLA_OLDDEFORM - BL_MVertArray *bva = new BL_MVertArray(); -#else - KX_IndexArray *bva = new KX_IndexArray(); -#endif - ao->m_MvertArrayCache1.push_back(bva); + for(it = m_materials.begin();it!=m_materials.end();++it) { + if(!it->m_slots[clientobj]) + continue; - BL_DeformVertArray *dva = new BL_DeformVertArray(); - ao->m_DvertArrayCache1.push_back(dva); + RAS_MeshSlot *slot = *it->m_slots[clientobj]; + slot->m_pDeformer = ((BL_DeformableGameObject*)clientobj)->GetDeformer(); + } - KX_IndexArray *da = new KX_IndexArray(); - ao->m_DIndexArrayCache1.push_back(da); + RAS_MeshObject::UpdateBuckets(clientobj, oglmatrix, useObjectColor, rgbavec, visible, culled); +} - ao->m_TriangleArrayCount.push_back(numverts-2); +static int 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 array; + return -1; } - -//void BL_SkinMeshObject::Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec,RAS_BucketManager* bucketmgr) -void BL_SkinMeshObject::Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec) +void BL_SkinMeshObject::CheckWeightCache(Object* obj) { + KeyBlock *kb; + int kbindex, defindex; + MDeformVert *dvert= NULL; + int totvert, i, j; + float *weights; - KX_MeshSlot ms; - ms.m_clientObj = clientobj; - ms.m_mesh = this; - ms.m_OpenGLMatrix = oglmatrix; - ms.m_bObjectColor = useObjectColor; - ms.m_RGBAcolor = rgbavec; - ms.m_pDeformer = ((BL_DeformableGameObject*)clientobj)->m_pDeformer; - - for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();it++) - { - - RAS_MaterialBucket* materialbucket = (*it); + if (!m_mesh->key) + return; -// KX_ArrayOptimizer* oa = GetArrayOptimizer(materialbucket->GetPolyMaterial()); - materialbucket->SetMeshSlot(ms); + 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 0ca7428c0f0..8544a2b958c 100644 --- a/source/gameengine/Converter/BL_SkinMeshObject.h +++ b/source/gameengine/Converter/BL_SkinMeshObject.h @@ -40,138 +40,20 @@ #include "BL_MeshDeformer.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" - -typedef vector<struct MVert*> BL_MVertArray; -typedef vector<struct MDeformVert*> BL_DeformVertArray; -typedef vector<class BL_TexVert> BL_VertexArray; - - -typedef vector<vector<struct MDeformVert*>*> vecMDVertArray; -typedef vector<vector<class BL_TexVert>*> vecBVertexArray; - -class BL_SkinArrayOptimizer : public KX_ArrayOptimizer -{ -public: - BL_SkinArrayOptimizer(int index) - :KX_ArrayOptimizer (index) {}; - virtual ~BL_SkinArrayOptimizer(){ - - for (vector<KX_IndexArray*>::iterator itv = m_MvertArrayCache1.begin(); - !(itv == m_MvertArrayCache1.end());itv++) - { - delete (*itv); - } - for (vector<BL_DeformVertArray*>::iterator itd = m_DvertArrayCache1.begin(); - !(itd == m_DvertArrayCache1.end());itd++) - { - delete (*itd); - } - for (vector<KX_IndexArray*>::iterator iti = m_DIndexArrayCache1.begin(); - !(iti == m_DIndexArrayCache1.end());iti++) - { - delete (*iti); - } - - m_MvertArrayCache1.clear(); - m_DvertArrayCache1.clear(); - m_DIndexArrayCache1.clear(); - }; - - vector<KX_IndexArray*> m_MvertArrayCache1; - vector<BL_DeformVertArray*> m_DvertArrayCache1; - vector<KX_IndexArray*> m_DIndexArrayCache1; - -}; - class BL_SkinMeshObject : public RAS_MeshObject { - -// enum { BUCKET_MAX_INDICES = 16384};//2048};//8192}; -// enum { BUCKET_MAX_TRIANGLES = 4096}; - - KX_ArrayOptimizer* GetArrayOptimizer(RAS_IPolyMaterial* polymat) - { - KX_ArrayOptimizer** aop = (m_matVertexArrayS[*polymat]); - if (aop) - return *aop; - int numelements = m_matVertexArrayS.size(); - m_sortedMaterials.push_back(polymat); - - BL_SkinArrayOptimizer* ao = new BL_SkinArrayOptimizer(numelements); - m_matVertexArrayS.insert(*polymat,ao); - return ao; - } - protected: -public: - void Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec); -// void Bucketize(double* oglmatrix,void* clientobj,bool useObjectColor,const MT_Vector4& rgbavec,class RAS_BucketManager* bucketmgr); - - int FindVertexArray(int numverts,RAS_IPolyMaterial* polymat); - BL_SkinMeshObject(int lightlayer) : RAS_MeshObject (lightlayer) - { m_class = 1;}; + vector<int> m_cacheWeightIndex; - virtual ~BL_SkinMeshObject(){ - }; +public: + BL_SkinMeshObject(Mesh* mesh, int lightlayer); + ~BL_SkinMeshObject(); - const vecIndexArrays& GetDIndexCache (RAS_IPolyMaterial* mat) - { - BL_SkinArrayOptimizer* ao = (BL_SkinArrayOptimizer*)GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]); - return ao->m_DIndexArrayCache1; - } - const vecMDVertArray& GetDVertCache (RAS_IPolyMaterial* mat) - { - BL_SkinArrayOptimizer* ao = (BL_SkinArrayOptimizer*)GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]); - return ao->m_DvertArrayCache1; - } - const vecIndexArrays& GetMVertCache (RAS_IPolyMaterial* mat) - { - BL_SkinArrayOptimizer* ao = (BL_SkinArrayOptimizer*)GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]); - return ao->m_MvertArrayCache1; - } + void UpdateBuckets(void* clientobj, double* oglmatrix, + bool useObjectColor, const MT_Vector4& rgbavec, bool visible, bool culled); - void AddPolygon(RAS_Polygon* poly); - int FindOrAddDeform(unsigned int vtxarray, unsigned int mv, struct MDeformVert *dv, RAS_IPolyMaterial* mat); - int FindOrAddVertex(int vtxarray,const MT_Point3& xyz, - const MT_Point2& uv, - const MT_Point2& uv2, - const MT_Vector4& tangent, - const unsigned int rgbacolor, - const MT_Vector3& normal, int defnr, bool flat, RAS_IPolyMaterial* mat) - { - RAS_TexVert tempvert(xyz,uv,uv2, tangent,rgbacolor,normal,flat ? TV_CALCFACENORMAL : 0); - - // KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]); - BL_SkinArrayOptimizer* ao = (BL_SkinArrayOptimizer*)GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]); - - int numverts = ao->m_VertexArrayCache1[vtxarray]->size();//m_VertexArrayCount[vtxarray]; - - int index=-1; - - for (int i=0;i<numverts;i++) - { - const RAS_TexVert& vtx = (*ao->m_VertexArrayCache1[vtxarray])[i]; - if (tempvert.closeTo(&vtx)) - { - index = i; - break; - } - - } - if (index >= 0) - return index; - - // no vertex found, add one - ao->m_VertexArrayCache1[vtxarray]->push_back(tempvert); - ao->m_DIndexArrayCache1[vtxarray]->push_back(defnr); - - return numverts; - - - } - + // for shape keys, + void CheckWeightCache(struct Object* obj); }; #endif diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt index 1b8aa73bf1f..a5219b9e759 100644 --- a/source/gameengine/Converter/CMakeLists.txt +++ b/source/gameengine/Converter/CMakeLists.txt @@ -65,6 +65,7 @@ SET(INC ../../../source/gameengine/Network/LoopBackNetwork ../../../source/blender/misc ../../../source/blender/blenloader + ../../../source/blender/gpu ../../../extern/bullet2/src ../../../extern/solid ${PYTHON_INC} diff --git a/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp b/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp index f58d60b026a..4d79febb7b4 100644 --- a/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp +++ b/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp @@ -28,13 +28,10 @@ #include "KX_BlenderScalarInterpolator.h" -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -extern "C" int IPO_GetChannels(struct Ipo *ipo, short *channels); -extern "C" float IPO_GetFloatValue(struct Ipo *ipo, /*IPO_Channel*/ short channel, float ctime); - +extern "C" { +#include "DNA_ipo_types.h" +#include "BKE_ipo.h" +} static const int BL_MAX_CHANNELS = 32; @@ -42,7 +39,7 @@ float BL_ScalarInterpolator::GetValue(float currentTime) const { return IPO_GetFloatValue(m_blender_ipo, m_channel, currentTime); } -typedef short IPO_Channel; + BL_InterpolatorList::BL_InterpolatorList(struct Ipo *ipo) { IPO_Channel channels[BL_MAX_CHANNELS]; diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index 067fce3eefe..3fcb4765c67 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -100,7 +100,8 @@ KX_BlenderSceneConverter::KX_BlenderSceneConverter( m_sipo(sipo), m_ketsjiEngine(engine), m_alwaysUseExpandFraming(false), - m_usemat(false) + m_usemat(false), + m_useglslmat(false) { m_newfilename = ""; } @@ -120,29 +121,29 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter() delete (ipoList); } - vector<KX_WorldInfo*>::iterator itw = m_worldinfos.begin(); + vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator itw = m_worldinfos.begin(); while (itw != m_worldinfos.end()) { - delete (*itw); + delete (*itw).second; itw++; } - vector<RAS_IPolyMaterial*>::iterator itp = m_polymaterials.begin(); + vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator itp = m_polymaterials.begin(); while (itp != m_polymaterials.end()) { - delete (*itp); + delete (*itp).second; itp++; } // delete after RAS_IPolyMaterial - vector<BL_Material *>::iterator itmat = m_materials.begin(); + vector<pair<KX_Scene*,BL_Material *> >::iterator itmat = m_materials.begin(); while (itmat != m_materials.end()) { - delete (*itmat); + delete (*itmat).second; itmat++; } - vector<RAS_MeshObject*>::iterator itm = m_meshobjects.begin(); + vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator itm = m_meshobjects.begin(); while (itm != m_meshobjects.end()) { - delete (*itm); + delete (*itm).second; itm++; } @@ -183,20 +184,21 @@ bool KX_BlenderSceneConverter::TryAndLoadNewFile() return result; } - +Scene *KX_BlenderSceneConverter::GetBlenderSceneForName(const STR_String& name) +{ + Scene *sce; /** * Find the specified scene by name, or the first * scene if nothing matches (shouldn't happen). */ -static struct Scene *GetSceneForName2(struct Main *maggie, const STR_String& scenename) { - Scene *sce; - for (sce= (Scene*) maggie->scene.first; sce; sce= (Scene*) sce->id.next) - if (scenename == (sce->id.name+2)) + for (sce= (Scene*) m_maggie->scene.first; sce; sce= (Scene*) sce->id.next) + if (name == (sce->id.name+2)) return sce; - return (Scene*) maggie->scene.first; + return (Scene*)m_maggie->scene.first; + } #include "KX_PythonInit.h" @@ -244,6 +246,11 @@ struct BlenderDebugDraw : public btIDebugDraw { return m_debugMode; } + ///todo: find out if Blender can do this + virtual void draw3dText(const btVector3& location,const char* textString) + { + + } }; @@ -257,9 +264,12 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename, class RAS_ICanvas* canvas) { //find out which physics engine - Scene *blenderscene = GetSceneForName2(m_maggie, scenename); + Scene *blenderscene = GetBlenderSceneForName(scenename); e_PhysicsEngine physics_engine = UseBullet; + // hook for registration function during conversion. + m_currentScene = destinationscene; + destinationscene->SetSceneConverter(this); if (blenderscene) { @@ -357,21 +367,102 @@ void KX_BlenderSceneConverter::ConvertScene(const STR_String& scenename, m_alwaysUseExpandFraming ); + //These lookup are not needed during game m_map_blender_to_gameactuator.clear(); m_map_blender_to_gamecontroller.clear(); - m_map_blender_to_gameobject.clear(); - m_map_mesh_to_gamemesh.clear(); - //don't clear it yet, it is needed for the baking physics into ipo animation + //Clearing this lookup table has the effect of disabling the cache of meshes + //between scenes, even if they are shared in the blend file. + //This cache mecanism is buggy so I leave it disable and the memory leak + //that would result from this is fixed in RemoveScene() + m_map_mesh_to_gamemesh.clear(); + //Don't clear this lookup, it is needed for the baking physics into ipo animation + //To avoid it's infinite grows, object will be unregister when they are deleted + //see KX_Scene::NewRemoveObject //m_map_gameobject_to_blender.clear(); } +// This function removes all entities stored in the converter for that scene +// It should be used instead of direct delete scene +// Note that there was some provision for sharing entities (meshes...) between +// scenes but that is now disabled so all scene will have their own copy +// and we can delete them here. If the sharing is reactivated, change this code too.. +// (see KX_BlenderSceneConverter::ConvertScene) +void KX_BlenderSceneConverter::RemoveScene(KX_Scene *scene) +{ + int i, size; + // delete the scene first as it will stop the use of entities + delete scene; + // delete the entities of this scene + vector<pair<KX_Scene*,KX_WorldInfo*> >::iterator worldit; + size = m_worldinfos.size(); + for (i=0, worldit=m_worldinfos.begin(); i<size; ) { + if ((*worldit).first == scene) { + delete (*worldit).second; + *worldit = m_worldinfos.back(); + m_worldinfos.pop_back(); + size--; + } else { + i++; + worldit++; + } + } + + vector<pair<KX_Scene*,RAS_IPolyMaterial*> >::iterator polymit; + size = m_polymaterials.size(); + for (i=0, polymit=m_polymaterials.begin(); i<size; ) { + if ((*polymit).first == scene) { + delete (*polymit).second; + *polymit = m_polymaterials.back(); + m_polymaterials.pop_back(); + size--; + } else { + i++; + polymit++; + } + } + + vector<pair<KX_Scene*,BL_Material*> >::iterator matit; + size = m_materials.size(); + for (i=0, matit=m_materials.begin(); i<size; ) { + if ((*matit).first == scene) { + delete (*matit).second; + *matit = m_materials.back(); + m_materials.pop_back(); + size--; + } else { + i++; + matit++; + } + } + + vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator meshit; + size = m_meshobjects.size(); + for (i=0, meshit=m_meshobjects.begin(); i<size; ) { + if ((*meshit).first == scene) { + delete (*meshit).second; + *meshit = m_meshobjects.back(); + m_meshobjects.pop_back(); + size--; + } else { + i++; + meshit++; + } + } +} // use blender materials void KX_BlenderSceneConverter::SetMaterials(bool val) { m_usemat = val; + m_useglslmat = false; +} + +void KX_BlenderSceneConverter::SetGLSLMaterials(bool val) +{ + m_usemat = val; + m_useglslmat = val; } bool KX_BlenderSceneConverter::GetMaterials() @@ -379,10 +470,14 @@ bool KX_BlenderSceneConverter::GetMaterials() return m_usemat; } +bool KX_BlenderSceneConverter::GetGLSLMaterials() +{ + return m_useglslmat; +} void KX_BlenderSceneConverter::RegisterBlenderMaterial(BL_Material *mat) { - m_materials.push_back(mat); + m_materials.push_back(pair<KX_Scene*,BL_Material *>(m_currentScene,mat)); } @@ -403,6 +498,21 @@ void KX_BlenderSceneConverter::RegisterGameObject( m_map_blender_to_gameobject.insert(CHashedPtr(for_blenderobject),gameobject); } +void KX_BlenderSceneConverter::UnregisterGameObject( + KX_GameObject *gameobject) +{ + CHashedPtr gptr(gameobject); + struct Object **bobp= m_map_gameobject_to_blender[gptr]; + if (bobp) { + CHashedPtr bptr(*bobp); + KX_GameObject **gobp= m_map_blender_to_gameobject[bptr]; + if (gobp && *gobp == gameobject) + // also maintain m_map_blender_to_gameobject if the gameobject + // being removed is matching the blender object + m_map_blender_to_gameobject.remove(bptr); + m_map_gameobject_to_blender.remove(gptr); + } +} KX_GameObject *KX_BlenderSceneConverter::FindGameObject( @@ -430,7 +540,7 @@ void KX_BlenderSceneConverter::RegisterGameMesh( struct Mesh *for_blendermesh) { m_map_mesh_to_gamemesh.insert(CHashedPtr(for_blendermesh),gamemesh); - m_meshobjects.push_back(gamemesh); + m_meshobjects.push_back(pair<KX_Scene*,RAS_MeshObject*>(m_currentScene,gamemesh)); } @@ -455,7 +565,7 @@ RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh( void KX_BlenderSceneConverter::RegisterPolyMaterial(RAS_IPolyMaterial *polymat) { - m_polymaterials.push_back(polymat); + m_polymaterials.push_back(pair<KX_Scene*,RAS_IPolyMaterial*>(m_currentScene,polymat)); } @@ -520,7 +630,7 @@ SCA_IController *KX_BlenderSceneConverter::FindGameController( void KX_BlenderSceneConverter::RegisterWorldInfo( KX_WorldInfo *worldinfo) { - m_worldinfos.push_back(worldinfo); + m_worldinfos.push_back(pair<KX_Scene*,KX_WorldInfo*>(m_currentScene,worldinfo)); } /* @@ -552,13 +662,13 @@ extern "C" { Ipo *add_ipo( char *name, int idcode ); char *getIpoCurveName( IpoCurve * icu ); - struct IpoCurve *verify_ipocurve(struct ID *, short, char *, char *, char *, int); + struct IpoCurve *verify_ipocurve(struct ID *, short, char *, char *, char *, int, short); void testhandles_ipocurve(struct IpoCurve *icu); + void insert_vert_icu(struct IpoCurve *, float, float, short); void Mat3ToEul(float tmat[][3], float *eul); - } -IpoCurve* findIpoCurve(IpoCurve* first,char* searchName) +IpoCurve* findIpoCurve(IpoCurve* first, const char* searchName) { IpoCurve* icu1; for( icu1 = first; icu1; icu1 = icu1->next ) @@ -726,7 +836,7 @@ void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber) KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g); if (gameObj->IsDynamic()) { - KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); + //KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); Object* blenderObject = FindBlenderObject(gameObj); if (blenderObject) @@ -754,7 +864,7 @@ void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber) - const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); + //const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); const MT_Point3& position = gameObj->NodeGetWorldPosition(); Ipo* ipo = blenderObject->ipo; @@ -765,27 +875,27 @@ void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber) IpoCurve *icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z, 1); @@ -882,7 +992,7 @@ void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo() KX_GameObject* gameObj = (KX_GameObject*)parentList->GetValue(g); if (gameObj->IsDynamic()) { - KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); + //KX_IPhysicsController* physCtrl = gameObj->GetPhysicsController(); Object* blenderObject = FindBlenderObject(gameObj); if (blenderObject) @@ -910,8 +1020,8 @@ void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo() - const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); - const MT_Point3& position = gameObj->NodeGetWorldPosition(); + //const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); + //const MT_Point3& position = gameObj->NodeGetWorldPosition(); Ipo* ipo = blenderObject->ipo; if (ipo) @@ -921,27 +1031,27 @@ void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo() IpoCurve *icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y, 1); icu1 = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); if (!icu1) - icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z); + icu1 = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z, 1); diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.h b/source/gameengine/Converter/KX_BlenderSceneConverter.h index 971b45fc786..2317e952a0a 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.h +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.h @@ -45,13 +45,17 @@ class BL_Material; struct IpoCurve; struct Main; struct SpaceIpo; +struct Scene; class KX_BlenderSceneConverter : public KX_ISceneConverter { - vector<KX_WorldInfo*> m_worldinfos; - vector<RAS_IPolyMaterial*> m_polymaterials; - vector<RAS_MeshObject*> m_meshobjects; - vector<BL_Material *> m_materials; + // Use vector of pairs to allow removal of entities between scene switch + vector<pair<KX_Scene*,KX_WorldInfo*> > m_worldinfos; + vector<pair<KX_Scene*,RAS_IPolyMaterial*> > m_polymaterials; + vector<pair<KX_Scene*,RAS_MeshObject*> > m_meshobjects; + vector<pair<KX_Scene*,BL_Material *> > m_materials; + // Should also have a list of collision shapes. + // For the time being this is held in KX_Scene::m_shapes GEN_Map<CHashedPtr,struct Object*> m_map_gameobject_to_blender; GEN_Map<CHashedPtr,KX_GameObject*> m_map_blender_to_gameobject; @@ -69,8 +73,10 @@ class KX_BlenderSceneConverter : public KX_ISceneConverter STR_String m_newfilename; class KX_KetsjiEngine* m_ketsjiEngine; + class KX_Scene* m_currentScene; // Scene being converted bool m_alwaysUseExpandFraming; bool m_usemat; + bool m_useglslmat; void localDel_ipoCurve ( IpoCurve * icu ,struct SpaceIpo* sipo); // struct Ipo* findIpoForName(char* objName); @@ -96,6 +102,7 @@ public: class RAS_IRenderTools* rendertools, class RAS_ICanvas* canvas ); + virtual void RemoveScene(class KX_Scene *scene); void SetNewFileName(const STR_String& filename); bool TryAndLoadNewFile(); @@ -103,6 +110,7 @@ public: void SetAlwaysUseExpandFraming(bool to_what); void RegisterGameObject(KX_GameObject *gameobject, struct Object *for_blenderobject); + void UnregisterGameObject(KX_GameObject *gameobject); KX_GameObject *FindGameObject(struct Object *for_blenderobject); struct Object *FindBlenderObject(KX_GameObject *for_gameobject); @@ -140,6 +148,11 @@ public: virtual void SetMaterials(bool val); virtual bool GetMaterials(); + // use blender glsl materials + virtual void SetGLSLMaterials(bool val); + virtual bool GetGLSLMaterials(); + + struct Scene* GetBlenderSceneForName(const STR_String& name); }; #endif //__KX_BLENDERSCENECONVERTER_H diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 02c07a8eb94..4f152acc918 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -34,6 +34,8 @@ #define BLENDER_HACK_DTIME 0.02 +#include "MEM_guardedalloc.h" + #include "KX_BlenderSceneConverter.h" #include "KX_ConvertActuators.h" @@ -42,7 +44,7 @@ #include "SCA_PropertyActuator.h" #include "SCA_LogicManager.h" #include "SCA_RandomActuator.h" - +#include "SCA_2DFilterActuator.h" // Ketsji specific logicbricks #include "KX_SceneActuator.h" @@ -54,10 +56,13 @@ #include "KX_ConstraintActuator.h" #include "KX_CameraActuator.h" #include "KX_GameActuator.h" +#include "KX_StateActuator.h" #include "KX_VisibilityActuator.h" #include "KX_SCA_AddObjectActuator.h" #include "KX_SCA_EndObjectActuator.h" #include "KX_SCA_ReplaceMeshActuator.h" +#include "KX_ParentActuator.h" +#include "KX_SCA_DynamicActuator.h" #include "KX_Scene.h" #include "KX_KetsjiEngine.h" @@ -66,9 +71,11 @@ #include "KX_GameObject.h" /* This little block needed for linking to Blender... */ - +#include "BKE_text.h" #include "BLI_blenlib.h" +#define FILE_MAX 240 // repeated here to avoid dependency from BKE_utildefines.h + #include "KX_NetworkMessageActuator.h" #ifdef WIN32 @@ -81,6 +88,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" @@ -132,6 +140,7 @@ void BL_ConvertActuators(char* maggiename, MT_Vector3 angvelvec ( KX_BLENDERTRUNC(obact->angularvelocity[0]), KX_BLENDERTRUNC(obact->angularvelocity[1]), KX_BLENDERTRUNC(obact->angularvelocity[2])); + short damping = obact->damping; drotvec /= BLENDER_HACK_DTIME; //drotvec /= BLENDER_HACK_DTIME; @@ -152,7 +161,7 @@ void BL_ConvertActuators(char* maggiename, bitLocalFlag.DRot = bool((obact->flag & ACT_DROT_LOCAL)!=0); bitLocalFlag.LinearVelocity = bool((obact->flag & ACT_LIN_VEL_LOCAL)!=0); bitLocalFlag.AngularVelocity = bool((obact->flag & ACT_ANG_VEL_LOCAL)!=0); - + bitLocalFlag.ServoControl = bool(obact->type == ACT_OBJECT_SERVO); bitLocalFlag.AddOrSetLinV = bool((obact->flag & ACT_ADD_LIN_VEL)!=0); @@ -163,6 +172,7 @@ void BL_ConvertActuators(char* maggiename, drotvec.getValue(), linvelvec.getValue(), angvelvec.getValue(), + damping, bitLocalFlag ); baseact = tmpbaseact; @@ -173,16 +183,19 @@ void BL_ConvertActuators(char* maggiename, if (blenderobject->type==OB_ARMATURE){ bActionActuator* actact = (bActionActuator*) bact->data; STR_String propname = (actact->name ? actact->name : ""); + STR_String propframe = (actact->frameProp ? actact->frameProp : ""); BL_ActionActuator* tmpbaseact = new BL_ActionActuator( gameobj, propname, + propframe, actact->sta, actact->end, actact->act, actact->type, // + 1, because Blender starts to count at zero, actact->blendin, actact->priority, + actact->end_reset, actact->stridelength // Ketsji at 1, because zero is reserved for "NoDef" ); @@ -192,26 +205,55 @@ 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 : ""); + STR_String propframe = (actact->frameProp ? actact->frameProp : ""); + + BL_ShapeActionActuator* tmpbaseact = new BL_ShapeActionActuator( + gameobj, + propname, + propframe, + 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; bool ipochild = (ipoact->flag & ACT_IPOCHILD) !=0; - STR_String propname = ( ipoact->name ? ipoact->name : ""); + STR_String propname = ipoact->name; + STR_String frameProp = ipoact->frameProp; // first bit? bool ipo_as_force = (ipoact->flag & ACT_IPOFORCE); - bool force_local = (ipoact->flag & ACT_IPOFORCE_LOCAL); + bool local = (ipoact->flag & ACT_IPOLOCAL); + bool ipo_add = (ipoact->flag & ACT_IPOADD); KX_IpoActuator* tmpbaseact = new KX_IpoActuator( gameobj, propname , + frameProp, ipoact->sta, ipoact->end, ipochild, ipoact->type + 1, // + 1, because Blender starts to count at zero, // Ketsji at 1, because zero is reserved for "NoDef" ipo_as_force, - force_local - ); + ipo_add, + local); baseact = tmpbaseact; break; } @@ -249,15 +291,19 @@ void BL_ConvertActuators(char* maggiename, STR_String toPropName = (msgAct->toPropName ? (char*) msgAct->toPropName : ""); - /** - * Get the Message Subject to send. + /* BGE Wants "OB" prefix */ + if (toPropName != "") + toPropName = "OB" + toPropName; + + /** + * Get the Message Subject to send. */ STR_String subject = (msgAct->subject ? (char*) msgAct->subject : ""); - /** - * Get the bodyType + /** + * Get the bodyType */ int bodyType = msgAct->bodyType; @@ -319,22 +365,26 @@ void BL_ConvertActuators(char* maggiename, if (soundActuatorType != KX_SoundActuator::KX_SOUNDACT_NODEF) { - SND_SoundObject* sndobj = NULL; + SND_Scene* soundscene = scene->GetSoundScene(); + STR_String samplename = ""; + bool sampleisloaded = false; - if (soundact->sound) - { - SND_Scene* soundscene = scene->GetSoundScene(); - STR_String samplename = soundact->sound->name; + if (soundact->sound) { + /* Need to convert the samplename into absolute path + * before checking if its loaded */ + char fullpath[FILE_MAX]; - bool sampleisloaded = false; + /* dont modify soundact->sound->name, only change a copy */ + BLI_strncpy(fullpath, soundact->sound->name, sizeof(fullpath)); + BLI_convertstringcode(fullpath, maggiename); + samplename = fullpath; /* let's see if the sample was already loaded */ if (soundscene->IsSampleLoaded(samplename)) { sampleisloaded = true; } - else - { + else { /* if not, make it so */ PackedFile* pf = soundact->sound->newpackedfile; @@ -347,21 +397,33 @@ void BL_ConvertActuators(char* maggiename, /* or else load it from disk */ else { - /* but we need to convert the samplename into absolute pathname first */ - BLI_convertstringcode(soundact->sound->name, maggiename, 0); - samplename = soundact->sound->name; - - /* and now we can load it */ - if (soundscene->LoadSample(samplename, NULL, 0) > -1) + if (soundscene->LoadSample(samplename, NULL, 0) > -1) { sampleisloaded = true; + } + else { + std::cout << "WARNING: Sound actuator \"" << bact->name << + "\" from object \"" << blenderobject->id.name+2 << + "\" failed to load sample." << std::endl; + } } } - - if (sampleisloaded) - { - sndobj = new SND_SoundObject(); - sndobj->SetSampleName(samplename.Ptr()); - sndobj->SetObjectName(bact->name); + } else { + std::cout << "WARNING: Sound actuator \"" << bact->name << + "\" from object \"" << blenderobject->id.name+2 << + "\" has no sound datablock." << std::endl; + } + + /* Note, allowing actuators for sounds that are not there was added since 2.47 + * This is because python may expect the actuator and raise an exception if it dosnt find it + * better just to add a dummy sound actuator. */ + SND_SoundObject* sndobj = NULL; + if (sampleisloaded) + { + /* setup the SND_SoundObject */ + sndobj = new SND_SoundObject(); + sndobj->SetSampleName(samplename.Ptr()); + sndobj->SetObjectName(bact->name); + if (soundact->sound) { sndobj->SetRollOffFactor(soundact->sound->attenuation); sndobj->SetGain(soundact->sound->volume); sndobj->SetPitch(exp((soundact->sound->pitch / 12.0) * log(2.0))); @@ -374,8 +436,9 @@ void BL_ConvertActuators(char* maggiename, else sndobj->SetLoopMode(SND_LOOP_NORMAL); } - else + else { sndobj->SetLoopMode(SND_LOOP_OFF); + } if (soundact->sound->flags & SOUND_FLAGS_PRIORITY) sndobj->SetHighPriority(true); @@ -386,22 +449,30 @@ void BL_ConvertActuators(char* maggiename, sndobj->Set3D(true); else sndobj->Set3D(false); - - KX_SoundActuator* tmpsoundact = - new KX_SoundActuator(gameobj, - sndobj, - scene->GetSoundScene(), // needed for replication! - soundActuatorType, - startFrame, - stopFrame); - - tmpsoundact->SetName(bact->name); - baseact = tmpsoundact; - soundscene->AddObject(sndobj); - } else { - std::cout << "WARNING: Sound actuator " << bact->name << " failed to load sample." << std::endl; + } + else { + /* dummy values for a NULL sound + * see editsound.c - defaults are unlikely to change soon */ + sndobj->SetRollOffFactor(1.0); + sndobj->SetGain(1.0); + sndobj->SetPitch(1.0); + sndobj->SetLoopMode(SND_LOOP_OFF); + sndobj->SetHighPriority(false); + sndobj->Set3D(false); } } + KX_SoundActuator* tmpsoundact = + new KX_SoundActuator(gameobj, + sndobj, + scene->GetSoundScene(), // needed for replication! + soundActuatorType, + startFrame, + stopFrame); + + tmpsoundact->SetName(bact->name); + baseact = tmpsoundact; + if (sndobj) + soundscene->AddObject(sndobj); } break; } @@ -467,7 +538,7 @@ void BL_ConvertActuators(char* maggiename, case ACT_PROPERTY: { bPropertyActuator* propact = (bPropertyActuator*) bact->data; - CValue* destinationObj = NULL; + SCA_IObject* destinationObj = NULL; /* here the destinationobject is searched. problem with multiple scenes: other scenes @@ -503,14 +574,27 @@ void BL_ConvertActuators(char* maggiename, // does the 'original' for replication exists, and // is it in a non-active layer ? - CValue* originalval = NULL; - if (editobact->ob && !(editobact->ob->lay & activeLayerBitInfo)) - originalval = converter->FindGameObject(editobact->ob); - - MT_Vector3 linvelvec ( KX_BLENDERTRUNC(editobact->linVelocity[0]), + SCA_IObject* originalval = NULL; + if (editobact->ob) + { + if (editobact->ob->lay & activeLayerBitInfo) + { + fprintf(stderr, "Warning, object \"%s\" from AddObject actuator \"%s\" is not in a hidden layer.\n", objectname.Ptr(), uniquename.Ptr()); + } + else { + originalval = converter->FindGameObject(editobact->ob); + } + } + MT_Vector3 linvelvec ( + KX_BLENDERTRUNC(editobact->linVelocity[0]), KX_BLENDERTRUNC(editobact->linVelocity[1]), KX_BLENDERTRUNC(editobact->linVelocity[2])); - + + MT_Vector3 angvelvec ( + KX_BLENDERTRUNC(editobact->angVelocity[0]), + KX_BLENDERTRUNC(editobact->angVelocity[1]), + KX_BLENDERTRUNC(editobact->angVelocity[2])); + KX_SCA_AddObjectActuator* tmpaddact = new KX_SCA_AddObjectActuator( gameobj, @@ -518,7 +602,9 @@ void BL_ConvertActuators(char* maggiename, editobact->time, scene, linvelvec.getValue(), - editobact->localflag!=0 + (editobact->localflag & ACT_EDOB_LOCAL_LINV)!=0, + angvelvec.getValue(), + (editobact->localflag & ACT_EDOB_LOCAL_ANGV)!=0 ); //editobact->ob to gameobj @@ -569,6 +655,15 @@ void BL_ConvertActuators(char* maggiename, blenderobject->upflag ); baseact = tmptrackact; + break; + } + case ACT_EDOB_DYNAMICS: + { + KX_SCA_DynamicActuator* tmpdynact + = new KX_SCA_DynamicActuator(gameobj, + editobact->dyn_operation + ); + baseact = tmpdynact; } } break; @@ -576,51 +671,141 @@ void BL_ConvertActuators(char* maggiename, case ACT_CONSTRAINT: { float min = 0.0, max = 0.0; + char *prop = NULL; KX_ConstraintActuator::KX_CONSTRAINTTYPE locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_NODEF; bConstraintActuator *conact = (bConstraintActuator*) bact->data; /* convert settings... degrees in the ui become radians */ /* internally */ - switch (conact->flag) { - case ACT_CONST_LOCX: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCX; - min = conact->minloc[0]; - max = conact->maxloc[0]; - break; - case ACT_CONST_LOCY: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCY; - min = conact->minloc[1]; - max = conact->maxloc[1]; - break; - case ACT_CONST_LOCZ: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCZ; - min = conact->minloc[2]; - max = conact->maxloc[2]; - break; - case ACT_CONST_ROTX: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTX; - min = MT_2_PI * conact->minrot[0] / 360.0; - max = MT_2_PI * conact->maxrot[0] / 360.0; - break; - case ACT_CONST_ROTY: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTY; - min = MT_2_PI * conact->minrot[1] / 360.0; - max = MT_2_PI * conact->maxrot[1] / 360.0; - break; - case ACT_CONST_ROTZ: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTZ; - min = MT_2_PI * conact->minrot[2] / 360.0; - max = MT_2_PI * conact->maxrot[2] / 360.0; - break; - default: - ; /* error */ + if (conact->type == ACT_CONST_TYPE_ORI) { + min = (MT_2_PI * conact->minloc[0])/360.0; + max = (MT_2_PI * conact->maxloc[0])/360.0; + switch (conact->mode) { + case ACT_CONST_DIRPX: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIX; + break; + case ACT_CONST_DIRPY: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIY; + break; + case ACT_CONST_DIRPZ: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIZ; + break; + } + } else if (conact->type == ACT_CONST_TYPE_DIST) { + switch (conact->mode) { + case ACT_CONST_DIRPX: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + case ACT_CONST_DIRPY: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + case ACT_CONST_DIRPZ: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + case ACT_CONST_DIRNX: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + case ACT_CONST_DIRNY: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + case ACT_CONST_DIRNZ: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + } + prop = conact->matprop; + } else if (conact->type == ACT_CONST_TYPE_FH) { + switch (conact->mode) { + case ACT_CONST_DIRPX: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + case ACT_CONST_DIRPY: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + case ACT_CONST_DIRPZ: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + case ACT_CONST_DIRNX: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + case ACT_CONST_DIRNY: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + case ACT_CONST_DIRNZ: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + } + prop = conact->matprop; + } else { + switch (conact->flag) { + case ACT_CONST_LOCX: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + case ACT_CONST_LOCY: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + case ACT_CONST_LOCZ: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + case ACT_CONST_ROTX: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTX; + min = MT_2_PI * conact->minrot[0] / 360.0; + max = MT_2_PI * conact->maxrot[0] / 360.0; + break; + case ACT_CONST_ROTY: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTY; + min = MT_2_PI * conact->minrot[1] / 360.0; + max = MT_2_PI * conact->maxrot[1] / 360.0; + break; + case ACT_CONST_ROTZ: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTZ; + min = MT_2_PI * conact->minrot[2] / 360.0; + max = MT_2_PI * conact->maxrot[2] / 360.0; + break; + default: + ; /* error */ + } } KX_ConstraintActuator *tmpconact = new KX_ConstraintActuator(gameobj, - conact->damp, - min, - max, - locrot); + conact->damp, + conact->rotdamp, + min, + max, + conact->maxrot, + locrot, + conact->time, + conact->flag, + prop); baseact = tmpconact; break; } @@ -678,15 +863,11 @@ void BL_ConvertActuators(char* maggiename, break; } case ACT_SCENE_CAMERA: + mode = KX_SceneActuator::KX_SCENE_SET_CAMERA; if (sceneact->camera) { - mode = KX_SceneActuator::KX_SCENE_SET_CAMERA; cam = (KX_Camera*) converter->FindGameObject(sceneact->camera); } - else - { - // TODO:warn user - } break; case ACT_SCENE_RESTART: { @@ -739,6 +920,16 @@ void BL_ConvertActuators(char* maggiename, mode = KX_GameActuator::KX_GAME_QUIT; break; } + case ACT_GAME_SAVECFG: + { + mode = KX_GameActuator::KX_GAME_SAVECFG; + break; + } + case ACT_GAME_LOADCFG: + { + mode = KX_GameActuator::KX_GAME_LOADCFG; + break; + } default: ; /* flag error */ } @@ -825,15 +1016,129 @@ void BL_ConvertActuators(char* maggiename, bVisibilityActuator *vis_act = (bVisibilityActuator *) bact->data; KX_VisibilityActuator * tmp_vis_act = NULL; bool v = ((vis_act->flag & ACT_VISIBILITY_INVISIBLE) != 0); + bool recursive = ((vis_act->flag & ACT_VISIBILITY_RECURSIVE) != 0); - tmp_vis_act = - new KX_VisibilityActuator(gameobj, - !v); + tmp_vis_act = new KX_VisibilityActuator(gameobj, !v, recursive); baseact = tmp_vis_act; } break; + case ACT_STATE: + { + bStateActuator *sta_act = (bStateActuator *) bact->data; + KX_StateActuator * tmp_sta_act = NULL; + + tmp_sta_act = + new KX_StateActuator(gameobj, sta_act->type, sta_act->mask); + + baseact = tmp_sta_act; + } + break; + + case ACT_2DFILTER: + { + bTwoDFilterActuator *_2dfilter = (bTwoDFilterActuator*) bact->data; + SCA_2DFilterActuator *tmp = NULL; + + RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode; + switch(_2dfilter->type) + { + case ACT_2DFILTER_MOTIONBLUR: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_MOTIONBLUR; + break; + case ACT_2DFILTER_BLUR: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_BLUR; + break; + case ACT_2DFILTER_SHARPEN: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_SHARPEN; + break; + case ACT_2DFILTER_DILATION: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_DILATION; + break; + case ACT_2DFILTER_EROSION: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_EROSION; + break; + case ACT_2DFILTER_LAPLACIAN: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_LAPLACIAN; + break; + case ACT_2DFILTER_SOBEL: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_SOBEL; + break; + case ACT_2DFILTER_PREWITT: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_PREWITT; + break; + case ACT_2DFILTER_GRAYSCALE: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_GRAYSCALE; + break; + case ACT_2DFILTER_SEPIA: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_SEPIA; + break; + case ACT_2DFILTER_INVERT: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_INVERT; + break; + case ACT_2DFILTER_CUSTOMFILTER: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_CUSTOMFILTER; + break; + case ACT_2DFILTER_NOFILTER: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_NOFILTER; + break; + case ACT_2DFILTER_DISABLED: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_DISABLED; + break; + case ACT_2DFILTER_ENABLED: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_ENABLED; + break; + default: + filtermode = RAS_2DFilterManager::RAS_2DFILTER_NOFILTER; + break; + } + + tmp = new SCA_2DFilterActuator(gameobj, filtermode, _2dfilter->flag, + _2dfilter->float_arg,_2dfilter->int_arg,ketsjiEngine->GetRasterizer(),rendertools); + + if (_2dfilter->text) + { + char *buf; + // this is some blender specific code + buf = txt_to_buf(_2dfilter->text); + if (buf) + { + tmp->SetShaderText(STR_String(buf)); + MEM_freeN(buf); + } + } + + baseact = tmp; + + } + break; + case ACT_PARENT: + { + bParentActuator *parAct = (bParentActuator *) bact->data; + int mode = KX_ParentActuator::KX_PARENT_NODEF; + KX_GameObject *tmpgob = NULL; + + switch(parAct->type) + { + case ACT_PARENT_SET: + mode = KX_ParentActuator::KX_PARENT_SET; + tmpgob = converter->FindGameObject(parAct->ob); + break; + case ACT_PARENT_REMOVE: + mode = KX_ParentActuator::KX_PARENT_REMOVE; + tmpgob = NULL; + break; + } + + KX_ParentActuator *tmpparact + = new KX_ParentActuator(gameobj, + mode, + tmpgob); + baseact = tmpparact; + break; + } + default: ; /* generate some error */ } @@ -851,9 +1156,12 @@ void BL_ConvertActuators(char* maggiename, gameobj->AddActuator(baseact); converter->RegisterGameActuator(baseact, bact); + // done with baseact, release it + baseact->Release(); } bact = bact->next; } } + diff --git a/source/gameengine/Converter/KX_ConvertControllers.cpp b/source/gameengine/Converter/KX_ConvertControllers.cpp index a6ac2707db6..da490b4ee85 100644 --- a/source/gameengine/Converter/KX_ConvertControllers.cpp +++ b/source/gameengine/Converter/KX_ConvertControllers.cpp @@ -35,6 +35,10 @@ // Controller #include "SCA_ANDController.h" #include "SCA_ORController.h" +#include "SCA_NANDController.h" +#include "SCA_NORController.h" +#include "SCA_XORController.h" +#include "SCA_XNORController.h" #include "SCA_PythonController.h" #include "SCA_ExpressionController.h" @@ -112,6 +116,30 @@ void BL_ConvertControllers( LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); break; } + case CONT_LOGIC_NAND: + { + gamecontroller = new SCA_NANDController(gameobj); + LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); + break; + } + case CONT_LOGIC_NOR: + { + gamecontroller = new SCA_NORController(gameobj); + LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); + break; + } + case CONT_LOGIC_XOR: + { + gamecontroller = new SCA_XORController(gameobj); + LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); + break; + } + case CONT_LOGIC_XNOR: + { + gamecontroller = new SCA_XNORController(gameobj); + LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); + break; + } case CONT_EXPRESSION: { bExpressionCont* bexpcont = (bExpressionCont*) bcontr->data; @@ -161,6 +189,7 @@ void BL_ConvertControllers( if (gamecontroller) { gamecontroller->SetExecutePriority(executePriority++); + gamecontroller->SetState(bcontr->state_mask); STR_String uniquename = bcontr->name; uniquename += "#CONTR#"; uniqueint++; @@ -171,6 +200,8 @@ void BL_ConvertControllers( gameobj->AddController(gamecontroller); converter->RegisterGameController(gamecontroller, bcontr); + //done with gamecontroller + gamecontroller->Release(); } bcontr = bcontr->next; diff --git a/source/gameengine/Converter/KX_ConvertProperties.cpp b/source/gameengine/Converter/KX_ConvertProperties.cpp index 13fa5708e16..dfbc6f0c48d 100644 --- a/source/gameengine/Converter/KX_ConvertProperties.cpp +++ b/source/gameengine/Converter/KX_ConvertProperties.cpp @@ -102,8 +102,9 @@ void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventMan // set a subproperty called 'timer' so that // we can register the replica of this property // at the time a game object is replicated (AddObjectActuator triggers this) - - timeval->SetProperty("timer",new CBoolValue(true)); + CValue *bval = new CBoolValue(true); + timeval->SetProperty("timer",bval); + bval->Release(); if (isInActiveLayer) { timemgr->AddTimeProperty(timeval); @@ -125,10 +126,16 @@ void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventMan { scene->AddDebugProperty(gameobj,STR_String(prop->name)); } + // done with propval, release it + propval->Release(); } prop = prop->next; } - - + // check if state needs to be debugged + if (object->scaflag & OB_DEBUGSTATE) + { + // reserve name for object state + scene->AddDebugProperty(gameobj,STR_String("__state__")); + } } diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp index 1ac80df1ee7..4cf302b1f64 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.cpp +++ b/source/gameengine/Converter/KX_ConvertSensors.cpp @@ -65,6 +65,8 @@ probably misplaced */ #include "KX_MouseFocusSensor.h" #include "SCA_JoystickSensor.h" #include "KX_NetworkMessageSensor.h" +#include "SCA_ActuatorSensor.h" +#include "SCA_DelaySensor.h" #include "SCA_PropertySensor.h" @@ -91,6 +93,7 @@ void BL_ConvertSensors(struct Object* blenderobject, class KX_GameObject* gameobj, SCA_LogicManager* logicmgr, KX_Scene* kxscene, + KX_KetsjiEngine* kxengine, SCA_IInputDevice* keydev, int & executePriority, int activeLayerBitInfo, @@ -260,6 +263,7 @@ void BL_ConvertSensors(struct Object* blenderobject, bool neg_pulsemode = false; int frequency = 0; bool invert = false; + bool level = false; while(sens) { @@ -272,7 +276,8 @@ void BL_ConvertSensors(struct Object* blenderobject, frequency = sens->freq; invert = !(sens->invert == 0); - + level = !(sens->level == 0); + switch (sens->type) { case SENS_ALWAYS: @@ -287,6 +292,22 @@ void BL_ConvertSensors(struct Object* blenderobject, break; } + case SENS_DELAY: + { + // we can reuse the Always event manager for the delay sensor + SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::ALWAYS_EVENTMGR); + if (eventmgr) + { + bDelaySensor* delaysensor = (bDelaySensor*)sens->data; + gamesensor = new SCA_DelaySensor(eventmgr, + gameobj, + delaysensor->delay, + delaysensor->duration, + (delaysensor->flag & SENS_DELAY_REPEAT) != 0); + } + break; + } + case SENS_COLLISION: { SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR); @@ -392,8 +413,9 @@ void BL_ConvertSensors(struct Object* blenderobject, bool bFindMaterial = false; PHY_IPhysicsController* physCtrl = kxscene->GetPhysicsEnvironment()->CreateSphereController(radius,pos); - if (isInActiveLayer) - kxscene->GetPhysicsEnvironment()->addSensor(physCtrl); + //will be done in KX_TouchEventManager::RegisterSensor() + //if (isInActiveLayer) + // kxscene->GetPhysicsEnvironment()->addSensor(physCtrl); @@ -420,8 +442,8 @@ void BL_ConvertSensors(struct Object* blenderobject, { gamesensor = new SCA_KeyboardSensor(eventmgr, gReverseKeyTranslateTable[blenderkeybdsensor->key], - blenderkeybdsensor->qual, - blenderkeybdsensor->qual2, + gReverseKeyTranslateTable[blenderkeybdsensor->qual], + gReverseKeyTranslateTable[blenderkeybdsensor->qual2], (blenderkeybdsensor->type == SENS_ALL_KEYS), blenderkeybdsensor->targetName, blenderkeybdsensor->toggleName, @@ -496,6 +518,7 @@ void BL_ConvertSensors(struct Object* blenderobject, trackfocus, canvas, kxscene, + kxengine, gameobj); } } else { @@ -544,6 +567,19 @@ void BL_ConvertSensors(struct Object* blenderobject, break; } + case SENS_ACTUATOR: + { + bActuatorSensor* blenderactsensor = (bActuatorSensor*) sens->data; + // we will reuse the property event manager, there is nothing special with this sensor + SCA_EventManager* eventmgr + = logicmgr->FindEventManager(SCA_EventManager::ACTUATOR_EVENTMGR); + if (eventmgr) + { + STR_String propname=blenderactsensor->name; + gamesensor = new SCA_ActuatorSensor(eventmgr,gameobj,propname); + } + break; + } case SENS_RADAR: { @@ -608,6 +644,7 @@ void BL_ConvertSensors(struct Object* blenderobject, if (eventmgr) { bool bFindMaterial = (blenderraysensor->mode & SENS_COLLISION_MATERIAL); + bool bXRay = (blenderraysensor->mode & SENS_RAY_XRAY); STR_String checkname = (bFindMaterial? blenderraysensor->matname : blenderraysensor->propname); @@ -620,6 +657,7 @@ void BL_ConvertSensors(struct Object* blenderobject, gameobj, checkname, bFindMaterial, + bXRay, distance, axis, kxscene); @@ -656,7 +694,6 @@ void BL_ConvertSensors(struct Object* blenderobject, int axis =0; int axisf =0; int button =0; - int buttonf =0; int hat =0; int hatf =0; int prec =0; @@ -671,7 +708,6 @@ void BL_ConvertSensors(struct Object* blenderobject, break; case SENS_JOY_BUTTON: button = bjoy->button; - buttonf = bjoy->buttonf; joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_BUTTON; break; case SENS_JOY_HAT: @@ -686,11 +722,13 @@ void BL_ConvertSensors(struct Object* blenderobject, gamesensor = new SCA_JoystickSensor( eventmgr, gameobj, + bjoy->joyindex, joysticktype, axis,axisf, prec, - button,buttonf, - hat,hatf); + button, + hat,hatf, + (bjoy->flag & SENS_JOY_ANY_EVENT)); } else { @@ -719,25 +757,49 @@ void BL_ConvertSensors(struct Object* blenderobject, neg_pulsemode, frequency); gamesensor->SetInvert(invert); + gamesensor->SetLevel(level); gamesensor->SetName(STR_String(sens->name)); gameobj->AddSensor(gamesensor); // only register to manager if it's in an active layer - - if (isInActiveLayer) - gamesensor->RegisterToManager(); + // Make registration dynamic: only when sensor is activated + //if (isInActiveLayer) + // gamesensor->RegisterToManager(); for (int i=0;i<sens->totlinks;i++) { bController* linkedcont = (bController*) sens->links[i]; - SCA_IController* gamecont = converter->FindGameController(linkedcont); + if (linkedcont) { + SCA_IController* gamecont = converter->FindGameController(linkedcont); - if (gamecont) { - logicmgr->RegisterToSensor(gamecont,gamesensor); + if (gamecont) { + logicmgr->RegisterToSensor(gamecont,gamesensor); + } else { + printf( + "Warning, sensor \"%s\" could not find its controller " + "(link %d of %d) from object \"%s\"\n" + "\tthere has been an error converting the blender controller for the game engine," + "logic may be incorrect\n", sens->name, i+1, sens->totlinks, blenderobject->id.name+2); + } + } else { + printf( + "Warning, sensor \"%s\" has lost a link to a controller " + "(link %d of %d) from object \"%s\"\n" + "\tpossible causes are partially appended objects or an error reading the file," + "logic may be incorrect\n", sens->name, i+1, sens->totlinks, blenderobject->id.name+2); } } + // special case: Keyboard sensor with no link + // this combination is usually used for key logging. + if (sens->type == SENS_KEYBOARD && sens->totlinks == 0) { + // Force the registration so that the sensor runs + gamesensor->IncLink(); + } + + // done with gamesensor + gamesensor->Release(); } sens=sens->next; diff --git a/source/gameengine/Converter/KX_ConvertSensors.h b/source/gameengine/Converter/KX_ConvertSensors.h index 73da51f47f0..b18ffc10a2a 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.h +++ b/source/gameengine/Converter/KX_ConvertSensors.h @@ -33,6 +33,7 @@ void BL_ConvertSensors(struct Object* blenderobject, class KX_GameObject* gameobj, class SCA_LogicManager* logicmgr, class KX_Scene* kxscene, + class KX_KetsjiEngine* kxengine, class SCA_IInputDevice* keydev, int & executePriority , int activeLayerBitInfo, diff --git a/source/gameengine/Converter/KX_IpoConvert.cpp b/source/gameengine/Converter/KX_IpoConvert.cpp index 4d1fb7323f3..ce004fa0504 100644 --- a/source/gameengine/Converter/KX_IpoConvert.cpp +++ b/source/gameengine/Converter/KX_IpoConvert.cpp @@ -36,6 +36,7 @@ #pragma warning (disable:4786) #endif +#include "BKE_material.h" /* give_current_material */ #include "KX_GameObject.h" #include "KX_IpoConvert.h" @@ -68,6 +69,8 @@ #include "SG_Node.h" +#include "STR_HashedString.h" + static BL_InterpolatorList *GetIpoList(struct Ipo *for_ipo, KX_BlenderSceneConverter *converter) { BL_InterpolatorList *ipoList= converter->FindInterpolatorList(for_ipo); @@ -97,9 +100,9 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend ipocontr->GetIPOTransform().SetPosition( MT_Point3( - blenderobject->loc[0]+blenderobject->dloc[0], - blenderobject->loc[1]+blenderobject->dloc[1], - blenderobject->loc[2]+blenderobject->dloc[2] + blenderobject->loc[0]/*+blenderobject->dloc[0]*/, + blenderobject->loc[1]/*+blenderobject->dloc[1]*/, + blenderobject->loc[2]/*+blenderobject->dloc[2]*/ ) ); ipocontr->GetIPOTransform().SetEulerAngles( @@ -131,7 +134,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetPosition()[0]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyPosition(true); + ipocontr->SetIPOChannelActive(OB_LOC_X, true); } @@ -142,7 +145,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetPosition()[1]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyPosition(true); + ipocontr->SetIPOChannelActive(OB_LOC_Y, true); } ipo = ipoList->GetScalarInterpolator(OB_LOC_Z); @@ -152,7 +155,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetPosition()[2]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyPosition(true); + ipocontr->SetIPOChannelActive(OB_LOC_Z, true); } // Master the art of cut & paste programming... @@ -164,7 +167,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetDeltaPosition()[0]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyPosition(true); + ipocontr->SetIPOChannelActive(OB_DLOC_X, true); } ipo = ipoList->GetScalarInterpolator(OB_DLOC_Y); @@ -174,7 +177,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetDeltaPosition()[1]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyPosition(true); + ipocontr->SetIPOChannelActive(OB_DLOC_Y, true); } ipo = ipoList->GetScalarInterpolator(OB_DLOC_Z); @@ -184,7 +187,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetDeltaPosition()[2]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyPosition(true); + ipocontr->SetIPOChannelActive(OB_DLOC_Z, true); } // Explore the finesse of reuse and slight modification @@ -196,7 +199,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetEulerAngles()[0]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyOrientation(true); + ipocontr->SetIPOChannelActive(OB_ROT_X, true); } ipo = ipoList->GetScalarInterpolator(OB_ROT_Y); if (ipo) { @@ -205,7 +208,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetEulerAngles()[1]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyOrientation(true); + ipocontr->SetIPOChannelActive(OB_ROT_Y, true); } ipo = ipoList->GetScalarInterpolator(OB_ROT_Z); if (ipo) { @@ -214,7 +217,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetEulerAngles()[2]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyOrientation(true); + ipocontr->SetIPOChannelActive(OB_ROT_Z, true); } // Hmmm, the need for a macro comes to mind... @@ -226,7 +229,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[0]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyOrientation(true); + ipocontr->SetIPOChannelActive(OB_DROT_X, true); } ipo = ipoList->GetScalarInterpolator(OB_DROT_Y); if (ipo) { @@ -235,7 +238,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[1]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyOrientation(true); + ipocontr->SetIPOChannelActive(OB_DROT_Y, true); } ipo = ipoList->GetScalarInterpolator(OB_DROT_Z); if (ipo) { @@ -244,7 +247,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[2]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyOrientation(true); + ipocontr->SetIPOChannelActive(OB_DROT_Z, true); } // Hang on, almost there... @@ -256,7 +259,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetScaling()[0]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyScaling(true); + ipocontr->SetIPOChannelActive(OB_SIZE_X, true); } ipo = ipoList->GetScalarInterpolator(OB_SIZE_Y); if (ipo) { @@ -265,7 +268,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetScaling()[1]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyScaling(true); + ipocontr->SetIPOChannelActive(OB_SIZE_Y, true); } ipo = ipoList->GetScalarInterpolator(OB_SIZE_Z); if (ipo) { @@ -274,7 +277,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetScaling()[2]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyScaling(true); + ipocontr->SetIPOChannelActive(OB_SIZE_Z, true); } // The last few... @@ -286,7 +289,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetDeltaScaling()[0]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyScaling(true); + ipocontr->SetIPOChannelActive(OB_DSIZE_X, true); } ipo = ipoList->GetScalarInterpolator(OB_DSIZE_Y); if (ipo) { @@ -295,7 +298,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetDeltaScaling()[1]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyScaling(true); + ipocontr->SetIPOChannelActive(OB_DSIZE_Y, true); } ipo = ipoList->GetScalarInterpolator(OB_DSIZE_Z); if (ipo) { @@ -304,7 +307,7 @@ void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_Blend &(ipocontr->GetIPOTransform().GetDeltaScaling()[2]), ipo); ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyScaling(true); + ipocontr->SetIPOChannelActive(OB_DSIZE_Z, true); } { @@ -560,16 +563,15 @@ void BL_ConvertWorldIpos(struct World* blenderworld,KX_BlenderSceneConverter *co } } - -void BL_ConvertMaterialIpos( - Material* blendermaterial, +static void ConvertMaterialIpos( + Material* blendermaterial, + dword matname_hash, KX_GameObject* gameobj, KX_BlenderSceneConverter *converter ) { if (blendermaterial->ipo) { - - KX_MaterialIpoController* ipocontr = new KX_MaterialIpoController(); + KX_MaterialIpoController* ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); @@ -596,7 +598,7 @@ void BL_ConvertMaterialIpos( ipo = ipoList->GetScalarInterpolator(MA_COL_R); if (ipo) { if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(); + ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } @@ -610,7 +612,7 @@ void BL_ConvertMaterialIpos( ipo = ipoList->GetScalarInterpolator(MA_COL_G); if (ipo) { if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(); + ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } @@ -624,7 +626,7 @@ void BL_ConvertMaterialIpos( ipo = ipoList->GetScalarInterpolator(MA_COL_B); if (ipo) { if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(); + ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } @@ -638,7 +640,7 @@ void BL_ConvertMaterialIpos( ipo = ipoList->GetScalarInterpolator(MA_ALPHA); if (ipo) { if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(); + ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } @@ -653,7 +655,7 @@ void BL_ConvertMaterialIpos( ipo = ipoList->GetScalarInterpolator(MA_SPEC_R ); if (ipo) { if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(); + ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } @@ -667,7 +669,7 @@ void BL_ConvertMaterialIpos( ipo = ipoList->GetScalarInterpolator(MA_SPEC_G); if (ipo) { if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(); + ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } @@ -681,7 +683,7 @@ void BL_ConvertMaterialIpos( ipo = ipoList->GetScalarInterpolator(MA_SPEC_B); if (ipo) { if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(); + ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } @@ -696,7 +698,7 @@ void BL_ConvertMaterialIpos( ipo = ipoList->GetScalarInterpolator(MA_HARD); if (ipo) { if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(); + ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } @@ -710,7 +712,7 @@ void BL_ConvertMaterialIpos( ipo = ipoList->GetScalarInterpolator(MA_SPEC); if (ipo) { if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(); + ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } @@ -725,7 +727,7 @@ void BL_ConvertMaterialIpos( ipo = ipoList->GetScalarInterpolator(MA_REF); if (ipo) { if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(); + ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } @@ -739,7 +741,7 @@ void BL_ConvertMaterialIpos( ipo = ipoList->GetScalarInterpolator(MA_EMIT); if (ipo) { if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(); + ipocontr = new KX_MaterialIpoController(matname_hash); gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); } @@ -752,3 +754,31 @@ void BL_ConvertMaterialIpos( } } +void BL_ConvertMaterialIpos( + struct Object* blenderobject, + KX_GameObject* gameobj, + KX_BlenderSceneConverter *converter + ) +{ + if (blenderobject->totcol==1) + { + Material *mat = give_current_material(blenderobject, 1); + // if there is only one material attached to the mesh then set material_index in BL_ConvertMaterialIpos to NULL + // --> this makes the UpdateMaterialData function in KX_GameObject.cpp use the old hack of using SetObjectColor + // because this yields a better performance as not all the vertex colors need to be edited + if(mat) ConvertMaterialIpos(mat, 0, gameobj, converter); + } + else + { + for (int material_index=1; material_index <= blenderobject->totcol; material_index++) + { + Material *mat = give_current_material(blenderobject, material_index); + STR_HashedString matname; + if(mat) { + matname= mat->id.name; + ConvertMaterialIpos(mat, matname.hash(), gameobj, converter); + } + } + } +} + diff --git a/source/gameengine/Converter/KX_IpoConvert.h b/source/gameengine/Converter/KX_IpoConvert.h index afcb1b22821..4ec9bd31062 100644 --- a/source/gameengine/Converter/KX_IpoConvert.h +++ b/source/gameengine/Converter/KX_IpoConvert.h @@ -46,7 +46,7 @@ void BL_ConvertCameraIpos(struct Camera* blendercamera, class KX_GameObject* cameraobj, class KX_BlenderSceneConverter *converter); -void BL_ConvertMaterialIpos(struct Material* blendermaterial, +void BL_ConvertMaterialIpos(struct Object* blenderobject, class KX_GameObject* materialobj, class KX_BlenderSceneConverter *converter); diff --git a/source/gameengine/Converter/Makefile b/source/gameengine/Converter/Makefile index 4a76b661d4f..938994e8b62 100644 --- a/source/gameengine/Converter/Makefile +++ b/source/gameengine/Converter/Makefile @@ -52,6 +52,7 @@ CPPFLAGS += -I../../blender/editors/include CPPFLAGS += -I../../blender/blenlib CPPFLAGS += -I../../blender/blenkernel CPPFLAGS += -I../../blender/render/extern/include +CPPFLAGS += -I../../blender/gpu CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I../Expressions -I../Rasterizer -I../GameLogic CPPFLAGS += -I../Ketsji -I../BlenderRoutines -I../SceneGraph diff --git a/source/gameengine/Converter/SConscript b/source/gameengine/Converter/SConscript index a63881f3ef0..434fad0f544 100644 --- a/source/gameengine/Converter/SConscript +++ b/source/gameengine/Converter/SConscript @@ -16,7 +16,7 @@ incs += ' #source/gameengine/Expressions #source/gameengine/Network #source/game incs += ' #source/gameengine/Physics/common #source/gameengine/Physics/Bullet #source/gameengine/Physics/BlOde' incs += ' #source/gameengine/Physics/Dummy #source/gameengine/Physics/Sumo' incs += ' #source/gameengine/Physics/Sumo/Fuzzics/include #source/gameengine/Network/LoopBackNetwork' -incs += ' #source/blender/misc #source/blender/blenloader' +incs += ' #source/blender/misc #source/blender/blenloader #source/blender/gpu' incs += ' #source/blender/windowmanager' incs += ' ' + env['BF_PYTHON_INC'] |