diff options
Diffstat (limited to 'source/gameengine')
42 files changed, 2082 insertions, 852 deletions
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index f00dd279361..40f1701e44a 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -95,10 +95,6 @@ extern float BKE_screen_view3d_zoom_to_fac(float camzoom); #include "BKE_ipo.h" /***/ -#ifdef WITH_AUDASPACE -# include "AUD_C-API.h" -#endif - //XXX #include "BSE_headerbuttons.h" #include "BKE_context.h" #include "../../blender/windowmanager/WM_types.h" @@ -108,6 +104,11 @@ extern float BKE_screen_view3d_zoom_to_fac(float camzoom); } #endif +#ifdef WITH_AUDASPACE +# include "AUD_C-API.h" +# include "AUD_I3DDevice.h" +# include "AUD_IDevice.h" +#endif static BlendFileData *load_game_data(char *filename) { @@ -186,6 +187,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c #endif bool novertexarrays = (SYS_GetCommandLineInt(syshandle, "novertexarrays", 0) != 0); bool mouse_state = startscene->gm.flag & GAME_SHOW_MOUSE; + bool restrictAnimFPS = startscene->gm.flag & GAME_RESTRICT_ANIM_UPDATES; if(animation_record) usefixed= true; /* override since you's always want fixed time for sim recording */ @@ -235,6 +237,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c ketsjiengine->SetRasterizer(rasterizer); ketsjiengine->SetUseFixedTime(usefixed); ketsjiengine->SetTimingDisplay(frameRate, profile, properties); + ketsjiengine->SetRestrictAnimationFPS(restrictAnimFPS); #ifdef WITH_PYTHON CValue::SetDeprecationWarnings(nodepwarnings); @@ -393,9 +396,13 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c ketsjiengine->InitDome(scene->gm.dome.res, scene->gm.dome.mode, scene->gm.dome.angle, scene->gm.dome.resbuf, scene->gm.dome.tilt, scene->gm.dome.warptext); // initialize 3D Audio Settings - AUD_setSpeedOfSound(scene->audio.speed_of_sound); - AUD_setDopplerFactor(scene->audio.doppler_factor); - AUD_setDistanceModel(AUD_DistanceModel(scene->audio.distance_model)); + AUD_I3DDevice* dev = AUD_get3DDevice(); + if(dev) + { + dev->setSpeedOfSound(scene->audio.speed_of_sound); + dev->setDopplerFactor(scene->audio.doppler_factor); + dev->setDistanceModel(AUD_DistanceModel(scene->audio.distance_model)); + } // from see blender.c: // FIXME: this version patching should really be part of the file-reading code, @@ -580,7 +587,10 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c { delete canvas; canvas = NULL; - } + } + + // stop all remaining playing sounds + AUD_getDevice()->stopAll(); } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME); diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index 7e353d590bb..50afac6992e 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -36,6 +36,7 @@ #include "BL_ActionActuator.h" #include "BL_ArmatureObject.h" #include "BL_SkinDeformer.h" +#include "BL_Action.h" #include "KX_GameObject.h" #include "STR_HashedString.h" #include "MEM_guardedalloc.h" @@ -60,6 +61,49 @@ extern "C" { #include "RNA_define.h" } +BL_ActionActuator::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 layer, + float layer_weight, + short ipo_flags, + short end_reset, + float stride) + : SCA_IActuator(gameobj, KX_ACT_ACTION), + + 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_layer(layer), + m_layer_weight(layer_weight), + m_ipo_flags(ipo_flags), + m_pose(NULL), + m_blendpose(NULL), + m_userpose(NULL), + m_action(action), + m_propname(propname), + m_framepropname(framepropname) +{ + if (!end_reset) + m_flag |= ACT_FLAG_CONTINUE; +}; + BL_ActionActuator::~BL_ActionActuator() { if (m_pose) @@ -91,364 +135,153 @@ CValue* BL_ActionActuator::GetReplica() { return replica; } -bool BL_ActionActuator::ClampLocalTime() +bool BL_ActionActuator::Update(double curtime, bool frame) { - if (m_startframe < m_endframe) + bool bNegativeEvent = false; + bool bPositiveEvent = false; + bool bUseContinue = false; + KX_GameObject *obj = (KX_GameObject*)GetParent(); + short playtype = BL_Action::ACT_MODE_PLAY; + float start = m_startframe; + float end = m_endframe; + + // If we don't have an action, we can't do anything + if (!m_action) + return false; + + // Convert our playtype to one that BL_Action likes + switch(m_playtype) { - 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_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_KetsjiEngine::GetAnimFrameRate(); - else - m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate(); -} - -void BL_ActionActuator::SetLocalTime(float curtime) -{ - float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate(); - - if (m_endframe < m_startframe) - delta_time = -delta_time; + case ACT_ACTION_LOOP_END: + case ACT_ACTION_LOOP_STOP: + playtype = BL_Action::ACT_MODE_LOOP; + break; + + case ACT_ACTION_PINGPONG: + // We handle ping pong ourselves to increase compabitility + // with files made prior to animation changes from GSoC 2011. + playtype = BL_Action::ACT_MODE_PLAY; + + if (m_flag & ACT_FLAG_REVERSE) + { + m_localtime = start; + start = end; + end = m_localtime; + } - if (!(m_flag & ACT_FLAG_REVERSE)) - m_localtime = m_startframe + delta_time; - else - m_localtime = m_endframe - delta_time; -} + break; + case ACT_ACTION_FROM_PROP: + CValue* prop = GetParent()->GetProperty(m_propname); + playtype = BL_Action::ACT_MODE_PLAY; + start = end = prop->GetNumber(); -bool BL_ActionActuator::Update(double curtime, bool frame) -{ - bool bNegativeEvent = false; - bool bPositiveEvent = false; - bool keepgoing = true; - bool wrap = false; - bool apply=true; - int priority; - float newweight; + break; + } - curtime -= KX_KetsjiEngine::GetSuspendedDelta(); + // Continue only really makes sense for play stop and flipper. All other modes go until they are complete. + if (m_flag & ACT_FLAG_CONTINUE && + (m_playtype == ACT_ACTION_LOOP_STOP || + m_playtype == ACT_ACTION_FLIPPER)) + bUseContinue = true; - // result = true if animation has to be continued, false if animation stops - // maybe there are events for us in the queue ! + + // Handle events if (frame) { bNegativeEvent = m_negevent; bPositiveEvent = m_posevent; RemoveAllEvents(); - - if (bPositiveEvent) - m_flag |= ACT_FLAG_ACTIVE; - - 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; - } - } - - /* We know that action actuators have been discarded from all non armature objects: - if we're being called, we're attached to a BL_ArmatureObject */ - BL_ArmatureObject *obj = (BL_ArmatureObject*)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_PINGPONG: - if (bPositiveEvent){ - if (!(m_flag & ACT_FLAG_LOCKINPUT)){ - m_flag &= ~ACT_FLAG_KEYUP; - m_localtime = m_starttime; - m_starttime = curtime; - m_flag |= ACT_FLAG_LOCKINPUT; - } - } - 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); - } } + + if (bUseContinue && (m_flag & ACT_FLAG_ACTIVE)) + m_localtime = obj->GetActionFrame(m_layer); - /* Check if a wrapping response is needed */ - if (length){ - if (m_localtime < m_startframe || m_localtime > m_endframe) + if (bPositiveEvent) + { + if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, playtype, m_layer_weight, m_ipo_flags)) { - m_localtime = m_startframe + fmod(m_localtime, length); - wrap = true; + m_flag |= ACT_FLAG_ACTIVE; + if (bUseContinue) + obj->SetActionFrame(m_layer, m_localtime); + + if (m_playtype == ACT_ACTION_PLAY) + m_flag |= ACT_FLAG_PLAY_END; + else + m_flag &= ~ACT_FLAG_PLAY_END; } + else + return false; } - else - m_localtime = m_startframe; - - /* Perform post-increment tasks */ - switch (m_playtype){ - case ACT_ACTION_FROM_PROP: + else if ((m_flag & ACT_FLAG_ACTIVE) && bNegativeEvent) + { + bAction *curr_action = obj->GetCurrentAction(m_layer); + if (curr_action && curr_action != m_action) { - 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_PINGPONG: - if (wrap){ - if (!(m_flag & ACT_FLAG_REVERSE)) - m_localtime = m_endframe; - else - m_localtime = m_startframe; - - m_flag &= ~ACT_FLAG_LOCKINPUT; - m_flag ^= ACT_FLAG_REVERSE; //flip direction - keepgoing = false; - } - 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); + // Someone changed the action on us, so we wont mess with it + // Hopefully there wont be too many problems with two actuators using + // the same action... + m_flag &= ~ACT_FLAG_ACTIVE; + return false; } - break; - case ACT_ACTION_PLAY: - if (wrap){ - m_localtime = m_endframe; - keepgoing = false; - m_flag &= ~ACT_FLAG_LOCKINPUT; + + + m_localtime = obj->GetActionFrame(m_layer); + if (m_localtime < min(m_startframe, m_endframe) || m_localtime > max(m_startframe, m_endframe)) + m_localtime = m_startframe; + + switch(m_playtype) + { + case ACT_ACTION_LOOP_STOP: + obj->StopAction(m_layer); // Stop the action after getting the frame + + // We're done + m_flag &= ~ACT_FLAG_ACTIVE; + return false; + case ACT_ACTION_PINGPONG: + m_flag ^= ACT_FLAG_REVERSE; + // Now fallthrough to LOOP_END code + case ACT_ACTION_LOOP_END: + // Convert into a play and let it finish + obj->SetPlayMode(m_layer, BL_Action::ACT_MODE_PLAY); + + m_flag |= ACT_FLAG_PLAY_END; + break; + + case ACT_ACTION_FLIPPER: + // Convert into a play action and play back to the beginning + end = start; + start = obj->GetActionFrame(m_layer); + obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, 0, BL_Action::ACT_MODE_PLAY, m_layer_weight, m_ipo_flags); + + m_flag |= ACT_FLAG_PLAY_END; + break; } - 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) { + + // Handle a frame property if it's defined + if ((m_flag & ACT_FLAG_ACTIVE) && m_framepropname[0] != 0) + { + CValue* oldprop = obj->GetProperty(m_framepropname); + CValue* newval = new CFloatValue(obj->GetActionFrame(m_layer)); + if (oldprop) oldprop->SetValue(newval); - } else { - propowner->SetProperty(m_framepropname, newval); - } + else + obj->SetProperty(m_framepropname, newval); + newval->Release(); } - - if (bNegativeEvent) - m_blendframe=0.0; - - /* Apply the pose if necessary*/ - if (apply){ - - /* Priority test */ - if (obj->SetActiveAction(this, priority, curtime)){ - - /* Get the underlying pose from the armature */ - obj->GetPose(&m_pose); - -// 2.4x function, - /* Override the necessary channels with ones from the action */ - // XXX extract_pose_from_action(m_pose, m_action, m_localtime); - - -// 2.5x - replacement for extract_pose_from_action(...) above. - { - struct PointerRNA id_ptr; - Object *arm= obj->GetArmatureObject(); - bPose *pose_back= arm->pose; - - arm->pose= m_pose; - RNA_id_pointer_create((ID *)arm, &id_ptr); - animsys_evaluate_action(&id_ptr, m_action, NULL, m_localtime); - - arm->pose= pose_back; - -// 2.5x - could also do this but looks too high level, constraints use this, it works ok. -// Object workob; /* evaluate using workob */ -// what_does_obaction(obj->GetArmatureObject(), &workob, m_pose, m_action, NULL, m_localtime); - } - // done getting the pose from the action - - /* Perform the user override (if any) */ - if (m_userpose){ - extract_pose_from_pose(m_pose, m_userpose); - game_free_pose(m_userpose); //cant use MEM_freeN(m_userpose) because the channels need freeing too. - m_userpose = NULL; - } -#if 1 - /* Handle blending */ - if (m_blendin && (m_blendframe<m_blendin)){ - /* If this is the start of a blending sequence... */ - if ((m_blendframe==0.0) || (!m_blendpose)){ - obj->GetMRDPose(&m_blendpose); - m_blendstart = curtime; - } - - /* Find percentages */ - newweight = (m_blendframe/(float)m_blendin); - game_blend_poses(m_pose, m_blendpose, 1.0 - newweight); - - /* Increment current blending percentage */ - m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate(); - if (m_blendframe>m_blendin) - m_blendframe = m_blendin; - - } -#endif - m_lastUpdate = m_localtime; - obj->SetPose (m_pose); - } - else{ - m_blendframe = 0.0; - } - } - - if (!keepgoing){ - m_blendframe = 0.0; + // Handle a finished animation + if ((m_flag & ACT_FLAG_PLAY_END) && obj->IsActionDone(m_layer)) + { + m_flag &= ~ACT_FLAG_ACTIVE; + obj->StopAction(m_layer); + return false; } - return keepgoing; -}; + + return true; +} #ifdef WITH_PYTHON @@ -633,10 +466,10 @@ PyAttributeDef BL_ActionActuator::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ActionActuator, pyattr_get_action, pyattr_set_action), KX_PYATTRIBUTE_RO_FUNCTION("channelNames", BL_ActionActuator, pyattr_get_channel_names), KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ActionActuator, m_priority), - KX_PYATTRIBUTE_FLOAT_RW_CHECK("frame", 0, MAXFRAMEF, BL_ActionActuator, m_localtime, CheckFrame), + KX_PYATTRIBUTE_RW_FUNCTION("frame", BL_ActionActuator, pyattr_get_frame, pyattr_set_frame), KX_PYATTRIBUTE_STRING_RW("propName", 0, 31, false, BL_ActionActuator, m_propname), KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 31, false, BL_ActionActuator, m_framepropname), - KX_PYATTRIBUTE_BOOL_RW("useContinue", BL_ActionActuator, m_end_reset), + KX_PYATTRIBUTE_RW_FUNCTION("useContinue", BL_ActionActuator, pyattr_get_use_continue, pyattr_set_use_continue), KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ActionActuator, m_blendframe, CheckBlendTime), KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ActionActuator,m_playtype,CheckType), { NULL } //Sentinel @@ -696,4 +529,37 @@ PyObject* BL_ActionActuator::pyattr_get_channel_names(void *self_v, const KX_PYA return ret; } +PyObject* BL_ActionActuator::pyattr_get_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v); + return PyBool_FromLong(self->m_flag & ACT_FLAG_CONTINUE); +} + +int BL_ActionActuator::pyattr_set_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v); + + if (PyObject_IsTrue(value)) + self->m_flag |= ACT_FLAG_CONTINUE; + else + self->m_flag &= ~ACT_FLAG_CONTINUE; + + return PY_SET_ATTR_SUCCESS; +} + +PyObject* BL_ActionActuator::pyattr_get_frame(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v); + return PyFloat_FromDouble(((KX_GameObject*)self->m_gameobj)->GetActionFrame(self->m_layer)); +} + +int BL_ActionActuator::pyattr_set_frame(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v); + + ((KX_GameObject*)self->m_gameobj)->SetActionFrame(self->m_layer, PyFloat_AsDouble(value)); + + return PY_SET_ATTR_SUCCESS; +} + #endif // WITH_PYTHON diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h index ff4ca785a96..5324cb10885 100644 --- a/source/gameengine/Converter/BL_ActionActuator.h +++ b/source/gameengine/Converter/BL_ActionActuator.h @@ -52,32 +52,12 @@ public: short playtype, short blendin, short priority, + short layer, + float layer_weight, + short ipo_flags, short end_reset, - float stride) - : SCA_IActuator(gameobj, KX_ACT_ACTION), - - 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_end_reset(end_reset), - m_pose(NULL), - m_blendpose(NULL), - m_userpose(NULL), - m_action(action), - m_propname(propname), - m_framepropname(framepropname) - { - }; + float stride); + virtual ~BL_ActionActuator(); virtual bool Update(double curtime, bool frame); virtual CValue* GetReplica(); @@ -96,18 +76,10 @@ public: static PyObject* pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_channel_names(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - /* attribute check */ - static int CheckFrame(void *self, const PyAttributeDef*) - { - BL_ActionActuator* act = reinterpret_cast<BL_ActionActuator*>(self); - - if (act->m_localtime < act->m_startframe) - act->m_localtime = act->m_startframe; - else if (act->m_localtime > act->m_endframe) - act->m_localtime = act->m_endframe; - - return 0; - } + static PyObject* pyattr_get_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_frame(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_frame(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static int CheckBlendTime(void *self, const PyAttributeDef*) { @@ -139,11 +111,6 @@ public: #endif // WITH_PYTHON protected: - - void SetStartTime(float curtime); - void SetLocalTime(float curtime); - bool ClampLocalTime(); - MT_Point3 m_lastpos; float m_blendframe; int m_flag; @@ -160,9 +127,11 @@ protected: float m_blendin; float m_blendstart; float m_stridelength; + float m_layer_weight; short m_playtype; short m_priority; - bool m_end_reset; + short m_layer; + short m_ipo_flags; struct bPose* m_pose; struct bPose* m_blendpose; struct bPose* m_userpose; @@ -171,11 +140,17 @@ protected: STR_String m_framepropname; }; +// Not all of these values are used in BL_ActionActuator anymore, +// but BL_ShapeActionActuator still uses them, so we keep them around +// for now. enum { - ACT_FLAG_REVERSE = 0x00000001, - ACT_FLAG_LOCKINPUT = 0x00000002, - ACT_FLAG_KEYUP = 0x00000004, - ACT_FLAG_ACTIVE = 0x00000008 + ACT_FLAG_REVERSE = 1<<0, + ACT_FLAG_LOCKINPUT = 1<<1, + ACT_FLAG_KEYUP = 1<<2, + ACT_FLAG_ACTIVE = 1<<3, + ACT_FLAG_CONTINUE = 1<<4, + ACT_FLAG_PLAY_END = 1<<5, + }; #endif diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index c6c20a96482..395cae4ba87 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -218,7 +218,8 @@ BL_ArmatureObject::BL_ArmatureObject( void* sgReplicationInfo, SG_Callbacks callbacks, Object *armature, - Scene *scene) + Scene *scene, + int vert_deform_type) : KX_GameObject(sgReplicationInfo,callbacks), m_controlledConstraints(), @@ -232,7 +233,8 @@ BL_ArmatureObject::BL_ArmatureObject( m_activePriority(999), m_constraintNumber(0), m_channelNumber(0), - m_lastapplyframe(0.0) + m_lastapplyframe(0.0), + m_vert_deform_type(vert_deform_type) { m_armature = (bArmature *)armature->data; @@ -298,6 +300,7 @@ void BL_ArmatureObject::LoadConstraints(KX_BlenderSceneConverter* converter) case CONSTRAINT_TYPE_CLAMPTO: case CONSTRAINT_TYPE_TRANSFORM: case CONSTRAINT_TYPE_DISTLIMIT: + case CONSTRAINT_TYPE_TRANSLIKE: cti = constraint_get_typeinfo(pcon); gametarget = gamesubtarget = NULL; if (cti && cti->get_constraint_targets) { diff --git a/source/gameengine/Converter/BL_ArmatureObject.h b/source/gameengine/Converter/BL_ArmatureObject.h index 2c3ca7404b3..1467f05c1bd 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.h +++ b/source/gameengine/Converter/BL_ArmatureObject.h @@ -69,7 +69,8 @@ public: void* sgReplicationInfo, SG_Callbacks callbacks, Object *armature, - Scene *scene + Scene *scene, + int vert_deform_type ); virtual ~BL_ArmatureObject(); @@ -90,6 +91,8 @@ public: Object* GetArmatureObject() {return m_objArma;} + int GetVertDeformType() {return m_vert_deform_type;} + // for constraint python API void LoadConstraints(KX_BlenderSceneConverter* converter); size_t GetConstraintNumber() const { return m_constraintNumber; } @@ -136,6 +139,7 @@ protected: double m_timestep; // delta since last pose evaluation. class BL_ActionActuator *m_activeAct; short m_activePriority; + int m_vert_deform_type; size_t m_constraintNumber; size_t m_channelNumber; // store the original armature object matrix diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 35c319e263b..4daed538b39 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -1684,8 +1684,6 @@ static KX_LightObject *gamelight_from_blamp(Object *ob, Lamp *la, unsigned int l gamelight = new KX_LightObject(kxscene, KX_Scene::m_callbacks, rendertools, lightobj, glslmat); - - BL_ConvertLampIpos(la, gamelight, converter); return gamelight; } @@ -1698,8 +1696,6 @@ static KX_Camera *gamecamera_from_bcamera(Object *ob, KX_Scene *kxscene, KX_Blen gamecamera= new KX_Camera(kxscene, KX_Scene::m_callbacks, camdata); gamecamera->SetName(ca->id.name + 2); - BL_ConvertCameraIpos(ca, gamecamera, converter); - return gamecamera; } @@ -1809,11 +1805,13 @@ static KX_GameObject *gameobject_from_blenderobject( case OB_ARMATURE: { + bArmature *arm = (bArmature*)ob->data; gameobj = new BL_ArmatureObject( kxscene, KX_Scene::m_callbacks, ob, - kxscene->GetBlenderScene() // handle + kxscene->GetBlenderScene(), // handle + arm->gevertdeformer ); /* Get the current pose from the armature object and apply it as the rest pose */ break; @@ -2092,8 +2090,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz)); gameobj->NodeSetLocalScale(scale); gameobj->NodeUpdateGS(0); - - BL_ConvertIpos(blenderobject,gameobj,converter); + BL_ConvertMaterialIpos(blenderobject, gameobj, converter); sumolist->Add(gameobj->AddRef()); @@ -2282,8 +2279,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, gameobj->NodeSetLocalOrientation(MT_Matrix3x3(eulxyz)); gameobj->NodeSetLocalScale(scale); gameobj->NodeUpdateGS(0); - - BL_ConvertIpos(blenderobject,gameobj,converter); + BL_ConvertMaterialIpos(blenderobject,gameobj, converter); sumolist->Add(gameobj->AddRef()); diff --git a/source/gameengine/Converter/BL_DeformableGameObject.cpp b/source/gameengine/Converter/BL_DeformableGameObject.cpp index bfba054d0d4..48392ee8dda 100644 --- a/source/gameengine/Converter/BL_DeformableGameObject.cpp +++ b/source/gameengine/Converter/BL_DeformableGameObject.cpp @@ -87,15 +87,16 @@ bool BL_DeformableGameObject::SetActiveAction(BL_ShapeActionActuator *act, short bool BL_DeformableGameObject::GetShape(vector<float> &shape) { shape.clear(); - if (m_pDeformer) + BL_ShapeDeformer* shape_deformer = dynamic_cast<BL_ShapeDeformer*>(m_pDeformer); + if (shape_deformer) { - 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) + Key* key = shape_deformer->GetKey(); + if (key && key->type==KEY_RELATIVE) { KeyBlock *kb; - for (kb = (KeyBlock*)mesh->key->block.first; kb; kb = (KeyBlock*)kb->next) + for (kb = (KeyBlock*)key->block.first; kb; kb = (KeyBlock*)kb->next) { shape.push_back(kb->curval); } diff --git a/source/gameengine/Converter/BL_DeformableGameObject.h b/source/gameengine/Converter/BL_DeformableGameObject.h index 615bb84ac2b..3ba55664007 100644 --- a/source/gameengine/Converter/BL_DeformableGameObject.h +++ b/source/gameengine/Converter/BL_DeformableGameObject.h @@ -82,23 +82,6 @@ public: bool SetActiveAction(class BL_ShapeActionActuator *act, short priority, double curtime); bool GetShape(vector<float> &shape); - Key* GetKey() - { - if(m_pDeformer) { - BL_MeshDeformer *deformer= dynamic_cast<BL_MeshDeformer *>(m_pDeformer); // incase its not a MeshDeformer - if(deformer) { - return deformer->GetMesh()->key; - } - -#if 0 // TODO. shape keys for softbody, currently they dont store a mesh. - KX_SoftBodyDeformer *deformer_soft= dynamic_cast<KX_SoftBodyDeformer *>(m_pDeformer); - if(deformer) { - return deformer->GetMesh()->key; - } -#endif - } - return NULL; - } virtual void SetDeformer(class RAS_Deformer* deformer); virtual class RAS_Deformer* GetDeformer() diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.cpp b/source/gameengine/Converter/BL_ShapeActionActuator.cpp index bb53c2d6fe6..ac377cdb7ca 100644 --- a/source/gameengine/Converter/BL_ShapeActionActuator.cpp +++ b/source/gameengine/Converter/BL_ShapeActionActuator.cpp @@ -59,10 +59,49 @@ extern "C" { #include "BKE_animsys.h" + #include "BKE_key.h" + #include "RNA_access.h" } +BL_ShapeActionActuator::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) + : SCA_IActuator(gameobj, KX_ACT_SHAPEACTION), + + 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) +{ + m_idptr = new PointerRNA(); + BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent(); + BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer()); + RNA_id_pointer_create(&shape_deformer->GetKey()->id, m_idptr); +}; + BL_ShapeActionActuator::~BL_ShapeActionActuator() { + if (m_idptr) + delete m_idptr; } void BL_ShapeActionActuator::ProcessReplica() @@ -382,7 +421,11 @@ bool BL_ShapeActionActuator::Update(double curtime, bool frame) /* Priority test */ if (obj->SetActiveAction(this, priority, curtime)){ - Key *key = obj->GetKey(); + BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer()); + Key *key = NULL; + + if (shape_deformer) + key = shape_deformer->GetKey(); if (!key) { // this could happen if the mesh was changed in the middle of an action @@ -397,10 +440,14 @@ bool BL_ShapeActionActuator::Update(double curtime, bool frame) obj->GetShape(m_blendshape); m_blendstart = curtime; } - // only interested in shape channel - // in 2.4x was // extract_ipochannels_from_action(&tchanbase, &key->id, m_action, "Shape", m_localtime); - BKE_animsys_evaluate_animdata(&key->id, key->adt, m_localtime, ADT_RECALC_ANIM); + KeyBlock *kb; + // We go through and clear out the keyblocks so there isn't any interference + // from other shape actions + for (kb=(KeyBlock*)key->block.first; kb; kb=(KeyBlock*)kb->next) + kb->curval = 0.f; + + animsys_evaluate_action(m_idptr, m_action, NULL, m_localtime); // XXX - in 2.5 theres no way to do this. possibly not that important to support - Campbell if (0) { // XXX !execute_ipochannels(&tchanbase)) { diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.h b/source/gameengine/Converter/BL_ShapeActionActuator.h index 7a4523d4554..efd24fc305f 100644 --- a/source/gameengine/Converter/BL_ShapeActionActuator.h +++ b/source/gameengine/Converter/BL_ShapeActionActuator.h @@ -54,27 +54,7 @@ public: short playtype, short blendin, short priority, - float stride) - : SCA_IActuator(gameobj, KX_ACT_SHAPEACTION), - - 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) - { - }; + float stride); virtual ~BL_ShapeActionActuator(); virtual bool Update(double curtime, bool frame); virtual CValue* GetReplica(); @@ -160,6 +140,7 @@ protected: STR_String m_framepropname; STR_String m_propname; vector<float> m_blendshape; + struct PointerRNA *m_idptr; }; #endif diff --git a/source/gameengine/Converter/BL_ShapeDeformer.cpp b/source/gameengine/Converter/BL_ShapeDeformer.cpp index 8d8f149bb6c..befe0f6e784 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.cpp +++ b/source/gameengine/Converter/BL_ShapeDeformer.cpp @@ -44,13 +44,12 @@ #include "RAS_MeshObject.h" //#include "BL_ArmatureController.h" +#include "DNA_anim_types.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" @@ -59,6 +58,7 @@ extern "C"{ #include "BKE_lattice.h" + #include "BKE_animsys.h" } @@ -68,9 +68,42 @@ extern "C"{ #define __NLA_DEFNORMALS //#undef __NLA_DEFNORMALS +BL_ShapeDeformer::BL_ShapeDeformer(BL_DeformableGameObject *gameobj, + Object *bmeshobj, + RAS_MeshObject *mesh) + : + BL_SkinDeformer(gameobj,bmeshobj, mesh), + m_useShapeDrivers(false), + m_lastShapeUpdate(-1) +{ + m_key = m_bmesh->key; + m_bmesh->key = copy_key(m_key); +}; + +/* this second constructor is needed for making a mesh deformable on the fly. */ +BL_ShapeDeformer::BL_ShapeDeformer(BL_DeformableGameObject *gameobj, + Object *bmeshobj_old, + Object *bmeshobj_new, + RAS_MeshObject *mesh, + bool release_object, + bool recalc_normal, + BL_ArmatureObject* arma) + : + BL_SkinDeformer(gameobj, bmeshobj_old, bmeshobj_new, mesh, release_object, recalc_normal, arma), + m_useShapeDrivers(false), + m_lastShapeUpdate(-1) +{ + m_key = m_bmesh->key; + m_bmesh->key = copy_key(m_key); +}; BL_ShapeDeformer::~BL_ShapeDeformer() { + if (m_key && m_bmesh->key) + { + free_key(m_bmesh->key); + m_bmesh->key = m_key; + } }; RAS_Deformer *BL_ShapeDeformer::GetReplica() @@ -90,45 +123,23 @@ 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 && 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(); + // This used to check if we had drivers from this armature, + // now we just assume we want to use shape drivers + // and let the animsys handle things. + m_useShapeDrivers = true; + + return true; } bool BL_ShapeDeformer::ExecuteShapeDrivers(void) { - if (!m_shapeDrivers.empty() && PoseUpdated()) { - vector<IpoCurve*>::iterator it; -// void *poin; -// int type; - + if (m_useShapeDrivers && PoseUpdated()) { // 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 - // XXX 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); - } + // We don't need an actual time, just use 0 + BKE_animsys_evaluate_animdata(NULL, &GetKey()->id, GetKey()->adt, 0.f, ADT_RECALC_DRIVERS); ForceUpdate(); m_armobj->RestorePose(); @@ -190,3 +201,13 @@ bool BL_ShapeDeformer::Update(void) } return bSkinUpdate; } + +Key *BL_ShapeDeformer::GetKey() +{ + return m_bmesh->key; +} + +void BL_ShapeDeformer::SetKey(Key *key) +{ + m_bmesh->key = key; +} diff --git a/source/gameengine/Converter/BL_ShapeDeformer.h b/source/gameengine/Converter/BL_ShapeDeformer.h index 8115af59d27..655cc9d7aeb 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.h +++ b/source/gameengine/Converter/BL_ShapeDeformer.h @@ -42,19 +42,12 @@ #include "BL_DeformableGameObject.h" #include <vector> -struct IpoCurve; - class BL_ShapeDeformer : public BL_SkinDeformer { public: BL_ShapeDeformer(BL_DeformableGameObject *gameobj, Object *bmeshobj, - RAS_MeshObject *mesh) - : - BL_SkinDeformer(gameobj,bmeshobj, mesh), - m_lastShapeUpdate(-1) - { - }; + RAS_MeshObject *mesh); /* this second constructor is needed for making a mesh deformable on the fly. */ BL_ShapeDeformer(BL_DeformableGameObject *gameobj, @@ -63,12 +56,7 @@ public: class RAS_MeshObject *mesh, bool release_object, bool recalc_normal, - BL_ArmatureObject* arma = NULL) - : - BL_SkinDeformer(gameobj, bmeshobj_old, bmeshobj_new, mesh, release_object, recalc_normal, arma), - m_lastShapeUpdate(-1) - { - }; + BL_ArmatureObject* arma = NULL); virtual RAS_Deformer *GetReplica(); virtual void ProcessReplica(); @@ -78,14 +66,18 @@ public: bool LoadShapeDrivers(Object* arma); bool ExecuteShapeDrivers(void); + struct Key *GetKey(); + void SetKey(struct Key *key); + void ForceUpdate() { m_lastShapeUpdate = -1.0; }; protected: - vector<IpoCurve*> m_shapeDrivers; - double m_lastShapeUpdate; + bool m_useShapeDrivers; + double m_lastShapeUpdate; + struct Key* m_key; #ifdef WITH_CXX_GUARDEDALLOC diff --git a/source/gameengine/Converter/BL_SkinDeformer.cpp b/source/gameengine/Converter/BL_SkinDeformer.cpp index 34f9cb56c27..3a379e8b0ed 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.cpp +++ b/source/gameengine/Converter/BL_SkinDeformer.cpp @@ -36,6 +36,10 @@ #pragma warning (disable : 4786) #endif //WIN32 +// Eigen2 stuff used for BGEDeformVerts +#include <Eigen/Core> +#include <Eigen/LU> + #include "BL_SkinDeformer.h" #include "CTR_Map.h" #include "STR_HashedString.h" @@ -54,6 +58,7 @@ extern "C"{ #include "BKE_lattice.h" + #include "BKE_deform.h" } @@ -74,7 +79,9 @@ BL_SkinDeformer::BL_SkinDeformer(BL_DeformableGameObject *gameobj, //m_defbase(&bmeshobj->defbase), m_releaseobject(false), m_poseApplied(false), - m_recalcNormal(true) + m_recalcNormal(true), + m_copyNormals(false), + m_dfnrToPC(NULL) { copy_m4_m4(m_obmat, bmeshobj->obmat); }; @@ -92,7 +99,9 @@ BL_SkinDeformer::BL_SkinDeformer( m_lastArmaUpdate(-1), //m_defbase(&bmeshobj_old->defbase), m_releaseobject(release_object), - m_recalcNormal(recalc_normal) + m_recalcNormal(recalc_normal), + m_copyNormals(false), + m_dfnrToPC(NULL) { // this is needed to ensure correct deformation of mesh: // the deformation is done with Blender's armature_deform_verts() function @@ -106,6 +115,8 @@ BL_SkinDeformer::~BL_SkinDeformer() { if(m_releaseobject && m_armobj) m_armobj->Release(); + if(m_dfnrToPC) + delete [] m_dfnrToPC; } void BL_SkinDeformer::Relink(CTR_Map<class CTR_HashedPtr, void*>*map) @@ -152,9 +163,14 @@ bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat) for(i=it.startvertex; i<it.endvertex; i++) { RAS_TexVert& v = it.vertex[i]; v.SetXYZ(m_transverts[v.getOrigIndex()]); + if (m_copyNormals) + v.SetNormal(m_transnors[v.getOrigIndex()]); } } } + + if (m_copyNormals) + m_copyNormals = false; } return true; } @@ -174,19 +190,126 @@ void BL_SkinDeformer::ProcessReplica() BL_MeshDeformer::ProcessReplica(); m_lastArmaUpdate = -1; m_releaseobject = false; + m_dfnrToPC = NULL; +} + +void BL_SkinDeformer::BlenderDeformVerts() +{ + float obmat[4][4]; // the original object matrix + Object* par_arma = m_armobj->GetArmatureObject(); + + // save matrix first + copy_m4_m4(obmat, m_objMesh->obmat); + // set reference matrix + copy_m4_m4(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 + copy_m4_m4(m_objMesh->obmat, obmat); + +#ifdef __NLA_DEFNORMALS + if (m_recalcNormal) + RecalcNormals(); +#endif +} + +void BL_SkinDeformer::BGEDeformVerts() +{ + Object *par_arma = m_armobj->GetArmatureObject(); + MDeformVert *dverts = m_bmesh->dvert; + bDeformGroup *dg; + int numGroups = BLI_countlist(&m_objMesh->defbase); + + if (!dverts) + return; + + if (m_dfnrToPC == NULL) + { + m_dfnrToPC = new bPoseChannel*[numGroups]; + int i; + for (i=0, dg=(bDeformGroup*)m_objMesh->defbase.first; + dg; + ++i, dg=(bDeformGroup*)dg->next) + { + m_dfnrToPC[i] = get_pose_channel(par_arma->pose, dg->name); + + if (m_dfnrToPC[i] && m_dfnrToPC[i]->bone->flag & BONE_NO_DEFORM) + m_dfnrToPC[i] = NULL; + } + } + + + for (int i=0; i<m_bmesh->totvert; ++i) + { + float contrib = 0.f, weight, max_weight=0.f; + Bone *bone; + bPoseChannel *pchan=NULL; + MDeformVert *dvert; + Eigen::Map<Eigen::Vector3f> norm(m_transnors[i]); + Eigen::Vector4f vec(0, 0, 0, 1); + Eigen::Matrix4f norm_chan_mat; + Eigen::Vector4f co(m_transverts[i][0], + m_transverts[i][1], + m_transverts[i][2], + 1.f); + + dvert = dverts+i; + + if (!dvert->totweight) + continue; + + for (int j=0; j<dvert->totweight; ++j) + { + int index = dvert->dw[j].def_nr; + + if (index < numGroups && (pchan=m_dfnrToPC[index])) + { + weight = dvert->dw[j].weight; + bone = pchan->bone; + + if (weight) + { + Eigen::Vector4f cop(co); + Eigen::Matrix4f chan_mat = Eigen::Matrix4f::Map((float*)pchan->chan_mat); + + // Update Vertex Position + cop = chan_mat*cop; + vec += (cop - co)*weight; + + // Save the most influential channel so we can use it to update the vertex normal + if (weight > max_weight) + { + max_weight = weight; + norm_chan_mat = chan_mat; + } + + contrib += weight; + } + } + } + + + // Update Vertex Normal + norm = norm_chan_mat.corner<3, 3>(Eigen::TopLeft)*norm; + + if (contrib > 0.0001f) + { + vec *= 1.f/contrib; + co += vec; + } + + m_transverts[i][0] = co[0]; + m_transverts[i][1] = co[1]; + m_transverts[i][2] = co[2]; + } + m_copyNormals = true; } -//void where_is_pose (Object *ob); -//void armature_deform_verts(Object *armOb, Object *target, float (*vertexCos)[3], int numVerts, int deformflag); bool BL_SkinDeformer::UpdateInternal(bool shape_applied) { /* See if the armature has been updated for this frame */ 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(); if(!shape_applied) { /* store verts locally */ @@ -194,25 +317,23 @@ bool BL_SkinDeformer::UpdateInternal(bool shape_applied) /* duplicate */ for (int v =0; v<m_bmesh->totvert; v++) + { VECCOPY(m_transverts[v], m_bmesh->mvert[v].co); + VECCOPY(m_transnors[v], m_bmesh->mvert[v].no); + } } m_armobj->ApplyPose(); - // save matrix first - copy_m4_m4(obmat, m_objMesh->obmat); - // set reference matrix - copy_m4_m4(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 - copy_m4_m4(m_objMesh->obmat, obmat); - -#ifdef __NLA_DEFNORMALS - if (m_recalcNormal) - RecalcNormals(); -#endif + switch (m_armobj->GetVertDeformType()) + { + case ARM_VDEF_BGE_CPU: + BGEDeformVerts(); + break; + case ARM_VDEF_BLENDER: + default: + BlenderDeformVerts(); + } /* Update the current frame */ m_lastArmaUpdate=m_armobj->GetLastFrame(); diff --git a/source/gameengine/Converter/BL_SkinDeformer.h b/source/gameengine/Converter/BL_SkinDeformer.h index e53e21e946f..be974619281 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.h +++ b/source/gameengine/Converter/BL_SkinDeformer.h @@ -109,6 +109,11 @@ protected: bool m_releaseobject; bool m_poseApplied; bool m_recalcNormal; + bool m_copyNormals; // dirty flag so we know if Apply() needs to copy normal information (used for BGEDeformVerts()) + struct bPoseChannel** m_dfnrToPC; + + void BlenderDeformVerts(); + void BGEDeformVerts(); #ifdef WITH_CXX_GUARDEDALLOC diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt index 45a7701d404..3a217ce9d74 100644 --- a/source/gameengine/Converter/CMakeLists.txt +++ b/source/gameengine/Converter/CMakeLists.txt @@ -51,6 +51,7 @@ set(INC ../../blender/makesrna ../../blender/windowmanager ../../../extern/bullet2/src + ../../../extern/Eigen2 ../../../intern/container ../../../intern/guardedalloc ../../../intern/moto/include diff --git a/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp b/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp index a9a3e66f996..75c0e012226 100644 --- a/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp +++ b/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp @@ -47,11 +47,11 @@ float BL_ScalarInterpolator::GetValue(float currentTime) const { return evaluate_fcurve(m_fcu, currentTime); } -BL_InterpolatorList::BL_InterpolatorList(struct AnimData *adt) { - if(adt->action==NULL) +BL_InterpolatorList::BL_InterpolatorList(bAction *action) { + if(action==NULL) return; - for(FCurve *fcu= (FCurve *)adt->action->curves.first; fcu; fcu= (FCurve *)fcu->next) { + for(FCurve *fcu= (FCurve *)action->curves.first; fcu; fcu= (FCurve *)fcu->next) { if(fcu->rna_path) { BL_ScalarInterpolator *new_ipo = new BL_ScalarInterpolator(fcu); //assert(new_ipo); diff --git a/source/gameengine/Converter/KX_BlenderScalarInterpolator.h b/source/gameengine/Converter/KX_BlenderScalarInterpolator.h index bd786bae969..cca66b3771c 100644 --- a/source/gameengine/Converter/KX_BlenderScalarInterpolator.h +++ b/source/gameengine/Converter/KX_BlenderScalarInterpolator.h @@ -66,7 +66,7 @@ public: class BL_InterpolatorList : public std::vector<KX_IScalarInterpolator *> { public: - BL_InterpolatorList(struct AnimData *adt); + BL_InterpolatorList(struct bAction *action); ~BL_InterpolatorList(); KX_IScalarInterpolator *GetScalarInterpolator(const char *rna_path, int array_index); diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index dd21e7ef263..ffb9a8ce691 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -566,18 +566,18 @@ void KX_BlenderSceneConverter::RegisterPolyMaterial(RAS_IPolyMaterial *polymat) void KX_BlenderSceneConverter::RegisterInterpolatorList( - BL_InterpolatorList *adtList, - struct AnimData *for_adt) + BL_InterpolatorList *actList, + struct bAction *for_act) { - m_map_blender_to_gameAdtList.insert(CHashedPtr(for_adt), adtList); + m_map_blender_to_gameAdtList.insert(CHashedPtr(for_act), actList); } BL_InterpolatorList *KX_BlenderSceneConverter::FindInterpolatorList( - struct AnimData *for_adt) + struct bAction *for_act) { - BL_InterpolatorList **listp = m_map_blender_to_gameAdtList[CHashedPtr(for_adt)]; + BL_InterpolatorList **listp = m_map_blender_to_gameAdtList[CHashedPtr(for_act)]; return listp?*listp:NULL; } diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.h b/source/gameengine/Converter/KX_BlenderSceneConverter.h index 2340e44d288..ba919eb9592 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.h +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.h @@ -113,8 +113,8 @@ public: void RegisterBlenderMaterial(BL_Material *mat); - void RegisterInterpolatorList(BL_InterpolatorList *adtList, struct AnimData *for_adt); - BL_InterpolatorList *FindInterpolatorList(struct AnimData *for_adt); + void RegisterInterpolatorList(BL_InterpolatorList *actList, struct bAction *for_act); + BL_InterpolatorList *FindInterpolatorList(struct bAction *for_act); void RegisterGameActuator(SCA_IActuator *act, struct bActuator *for_actuator); SCA_IActuator *FindGameActuator(struct bActuator *for_actuator); diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 51e0449a32e..7b9cba7770b 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -99,6 +99,7 @@ #include "BL_ActionActuator.h" #include "BL_ShapeActionActuator.h" #include "BL_ArmatureActuator.h" +#include "BL_Action.h" /* end of blender include block */ #include "BL_BlenderDataConversion.h" @@ -196,30 +197,37 @@ void BL_ConvertActuators(char* maggiename, } case ACT_ACTION: { - if (blenderobject->type==OB_ARMATURE){ - bActionActuator* actact = (bActionActuator*) bact->data; - STR_String propname = (actact->name ? actact->name : ""); - STR_String propframe = (actact->frameProp ? actact->frameProp : ""); + bActionActuator* actact = (bActionActuator*) bact->data; + STR_String propname = (actact->name ? actact->name : ""); + STR_String propframe = (actact->frameProp ? actact->frameProp : ""); + + short ipo_flags = 0; + + // Convert flags + if (actact->flag & ACT_IPOFORCE) ipo_flags |= BL_Action::ACT_IPOFLAG_FORCE; + if (actact->flag & ACT_IPOLOCAL) ipo_flags |= BL_Action::ACT_IPOFLAG_LOCAL; + if (actact->flag & ACT_IPOADD) ipo_flags |= BL_Action::ACT_IPOFLAG_ADD; + if (actact->flag & ACT_IPOCHILD) ipo_flags |= BL_Action::ACT_IPOFLAG_CHILD; - 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" - ); - baseact= tmpbaseact; - break; - } - else - printf ("Discarded action actuator from non-armature object [%s]\n", blenderobject->id.name+2); + 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->layer, + actact->layer_weight, + ipo_flags, + actact->end_reset, + actact->stridelength + // Ketsji at 1, because zero is reserved for "NoDef" + ); + baseact= tmpbaseact; + break; } case ACT_SHAPEACTION: { @@ -380,7 +388,7 @@ void BL_ConvertActuators(char* maggiename, { bSound* sound = soundact->sound; bool is3d = soundact->flag & ACT_SND_3D_SOUND ? true : false; - AUD_Sound* snd_sound = NULL; + AUD_Reference<AUD_IFactory> snd_sound; KX_3DSoundSettings settings; settings.cone_inner_angle = soundact->sound3D.cone_inner_angle; settings.cone_outer_angle = soundact->sound3D.cone_outer_angle; @@ -398,7 +406,7 @@ void BL_ConvertActuators(char* maggiename, "\" has no sound datablock." << std::endl; } else - snd_sound = sound->playback_handle; + snd_sound = *reinterpret_cast<AUD_Reference<AUD_IFactory>*>(sound->playback_handle); KX_SoundActuator* tmpsoundact = new KX_SoundActuator(gameobj, snd_sound, diff --git a/source/gameengine/Converter/KX_IpoConvert.cpp b/source/gameengine/Converter/KX_IpoConvert.cpp index 2ad56717e26..0ee99f5335b 100644 --- a/source/gameengine/Converter/KX_IpoConvert.cpp +++ b/source/gameengine/Converter/KX_IpoConvert.cpp @@ -54,6 +54,7 @@ #include "DNA_object_types.h" #include "DNA_action_types.h" +#include "DNA_anim_types.h" #include "DNA_ipo_types.h" #include "DNA_lamp_types.h" #include "DNA_world_types.h" @@ -72,226 +73,226 @@ #include "STR_HashedString.h" -static BL_InterpolatorList *GetAdtList(struct AnimData *for_adt, KX_BlenderSceneConverter *converter) { - BL_InterpolatorList *adtList= converter->FindInterpolatorList(for_adt); +static BL_InterpolatorList *GetAdtList(struct bAction *for_act, KX_BlenderSceneConverter *converter) { + BL_InterpolatorList *adtList= converter->FindInterpolatorList(for_act); if (!adtList) { - adtList = new BL_InterpolatorList(for_adt); - converter->RegisterInterpolatorList(adtList, for_adt); + adtList = new BL_InterpolatorList(for_act); + converter->RegisterInterpolatorList(adtList, for_act); } return adtList; } -void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_BlenderSceneConverter *converter) +SG_Controller *BL_CreateIPO(struct bAction *action, KX_GameObject* gameobj, KX_BlenderSceneConverter *converter) { - if (blenderobject->adt) { - - KX_IpoSGController* ipocontr = new KX_IpoSGController(); - gameobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(gameobj->GetSGNode()); - - // For ipo_as_force, we need to know which SM object and Scene the - // object associated with this ipo is in. Is this already known here? - // I think not.... then it must be done later :( -// ipocontr->SetSumoReference(gameobj->GetSumoScene(), -// gameobj->GetSumoObject()); - - ipocontr->SetGameObject(gameobj); - - ipocontr->GetIPOTransform().SetPosition( - MT_Point3( - blenderobject->loc[0]/*+blenderobject->dloc[0]*/, - blenderobject->loc[1]/*+blenderobject->dloc[1]*/, - blenderobject->loc[2]/*+blenderobject->dloc[2]*/ - ) - ); - ipocontr->GetIPOTransform().SetEulerAngles( - MT_Vector3( - blenderobject->rot[0], - blenderobject->rot[1], - blenderobject->rot[2] - ) - ); - ipocontr->GetIPOTransform().SetScaling( - MT_Vector3( - blenderobject->size[0], - blenderobject->size[1], - blenderobject->size[2] - ) - ); - - const char *rotmode, *drotmode; - - switch(blenderobject->rotmode) - { - case ROT_MODE_AXISANGLE: - rotmode = "rotation_axis_angle"; - drotmode = "delta_rotation_axis_angle"; - case ROT_MODE_QUAT: - rotmode = "rotation_quaternion"; - drotmode = "delta_rotation_quaternion"; - default: - rotmode = "rotation_euler"; - drotmode = "delta_rotation_euler"; - } + KX_IpoSGController* ipocontr = new KX_IpoSGController(); + ipocontr->SetGameObject(gameobj); + + Object* blenderobject = gameobj->GetBlenderObject(); + + ipocontr->GetIPOTransform().SetPosition(MT_Point3(blenderobject->loc)); + ipocontr->GetIPOTransform().SetEulerAngles(MT_Vector3(blenderobject->rot)); + ipocontr->GetIPOTransform().SetScaling(MT_Vector3(blenderobject->size)); + + const char *rotmode, *drotmode; + + switch(blenderobject->rotmode) { + case ROT_MODE_AXISANGLE: + rotmode = "rotation_axis_angle"; + drotmode = "delta_rotation_axis_angle"; + break; + case ROT_MODE_QUAT: + rotmode = "rotation_quaternion"; + drotmode = "delta_rotation_quaternion"; + break; + default: + rotmode = "rotation_euler"; + drotmode = "delta_rotation_euler"; + break; + } - BL_InterpolatorList *adtList= GetAdtList(blenderobject->adt, converter); + BL_InterpolatorList *adtList= GetAdtList(action, converter); - // For each active channel in the adtList add an - // interpolator to the game object. + // For each active channel in the adtList add an + // interpolator to the game object. - KX_IInterpolator *interpolator; - KX_IScalarInterpolator *interp; + KX_IInterpolator *interpolator; + KX_IScalarInterpolator *interp; - for(int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator("location", i))) { - interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetPosition()[i]), interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_LOC_X+i, true); - } + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("location", i))) { + interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetPosition()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_LOC_X+i, true); } - for(int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator("delta_location", i))) { - interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaPosition()[i]), interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DLOC_X+i, true); - } + } + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("delta_location", i))) { + interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaPosition()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_DLOC_X+i, true); } - for(int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator(rotmode, i))) { - interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetEulerAngles()[i]), interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_ROT_X+i, true); - } + } + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator(rotmode, i))) { + interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetEulerAngles()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_ROT_X+i, true); } - for(int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator(drotmode, i))) { - interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[i]), interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DROT_X+i, true); - } + } + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator(drotmode, i))) { + interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_DROT_X+i, true); } - for(int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator("scale", i))) { - interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetScaling()[i]), interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_SIZE_X+i, true); - } + } + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("scale", i))) { + interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetScaling()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_SIZE_X+i, true); } - for(int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator("delta_scale", i))) { - interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaScaling()[i]), interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DSIZE_X+i, true); - } + } + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("delta_scale", i))) { + interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaScaling()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_DSIZE_X+i, true); } + } - { - KX_ObColorIpoSGController* ipocontr_obcol=NULL; + { + KX_ObColorIpoSGController* ipocontr_obcol=NULL; - for(int i=0; i<4; i++) { - if ((interp = adtList->GetScalarInterpolator("color", i))) { - if (!ipocontr_obcol) { - ipocontr_obcol = new KX_ObColorIpoSGController(); - gameobj->GetSGNode()->AddSGController(ipocontr_obcol); - ipocontr_obcol->SetObject(gameobj->GetSGNode()); - } - interpolator= new KX_ScalarInterpolator(&ipocontr_obcol->m_rgba[i], interp); - ipocontr_obcol->AddInterpolator(interpolator); + for(int i=0; i<4; i++) { + if ((interp = adtList->GetScalarInterpolator("color", i))) { + if (!ipocontr_obcol) { + ipocontr_obcol = new KX_ObColorIpoSGController(); + gameobj->GetSGNode()->AddSGController(ipocontr_obcol); + ipocontr_obcol->SetObject(gameobj->GetSGNode()); } + interpolator= new KX_ScalarInterpolator(&ipocontr_obcol->m_rgba[i], interp); + ipocontr_obcol->AddInterpolator(interpolator); } } } + + return ipocontr; } -void BL_ConvertLampIpos(struct Lamp* blenderlamp, KX_GameObject *lightobj,KX_BlenderSceneConverter *converter) +void BL_ConvertIpos(struct Object* blenderobject,KX_GameObject* gameobj,KX_BlenderSceneConverter *converter) { + if (blenderobject->adt) { + SG_Controller *ipocontr = BL_CreateIPO(blenderobject->adt->action, gameobj, converter); + gameobj->GetSGNode()->AddSGController(ipocontr); + ipocontr->SetObject(gameobj->GetSGNode()); + } +} - if (blenderlamp->adt) { +SG_Controller *BL_CreateLampIPO(struct bAction *action, KX_GameObject* lightobj, KX_BlenderSceneConverter *converter) +{ + KX_LightIpoSGController* ipocontr = new KX_LightIpoSGController(); - KX_LightIpoSGController* ipocontr = new KX_LightIpoSGController(); - lightobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(lightobj->GetSGNode()); - - ipocontr->m_energy = blenderlamp->energy; - ipocontr->m_col_rgb[0] = blenderlamp->r; - ipocontr->m_col_rgb[1] = blenderlamp->g; - ipocontr->m_col_rgb[2] = blenderlamp->b; - ipocontr->m_dist = blenderlamp->dist; + Lamp *blenderlamp = (Lamp*)lightobj->GetBlenderObject()->data; - BL_InterpolatorList *adtList= GetAdtList(blenderlamp->adt, converter); + ipocontr->m_energy = blenderlamp->energy; + ipocontr->m_col_rgb[0] = blenderlamp->r; + ipocontr->m_col_rgb[1] = blenderlamp->g; + ipocontr->m_col_rgb[2] = blenderlamp->b; + ipocontr->m_dist = blenderlamp->dist; - // For each active channel in the adtList add an - // interpolator to the game object. + BL_InterpolatorList *adtList= GetAdtList(action, converter); + + // For each active channel in the adtList add an + // interpolator to the game object. - KX_IInterpolator *interpolator; - KX_IScalarInterpolator *interp; + KX_IInterpolator *interpolator; + KX_IScalarInterpolator *interp; - if ((interp= adtList->GetScalarInterpolator("energy", 0))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_energy, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyEnergy(true); - } + if ((interp= adtList->GetScalarInterpolator("energy", 0))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_energy, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyEnergy(true); + } - if ((interp = adtList->GetScalarInterpolator("distance", 0))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_dist, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyDist(true); - } + if ((interp = adtList->GetScalarInterpolator("distance", 0))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_dist, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyDist(true); + } - for(int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator("color", i))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_col_rgb[i], interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyColor(true); - } + for(int i=0; i<3; i++) { + if ((interp = adtList->GetScalarInterpolator("color", i))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_col_rgb[i], interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyColor(true); } } + + return ipocontr; } +void BL_ConvertLampIpos(struct Lamp* blenderlamp, KX_GameObject *lightobj,KX_BlenderSceneConverter *converter) +{ + if (blenderlamp->adt) { + SG_Controller* ipocontr = BL_CreateLampIPO(blenderlamp->adt->action, lightobj, converter); + lightobj->GetSGNode()->AddSGController(ipocontr); + ipocontr->SetObject(lightobj->GetSGNode()); + + + } +} -void BL_ConvertCameraIpos(struct Camera* blendercamera, KX_GameObject *cameraobj,KX_BlenderSceneConverter *converter) +SG_Controller *BL_CreateCameraIPO(struct bAction *action, KX_GameObject* cameraobj, KX_BlenderSceneConverter *converter) { + KX_CameraIpoSGController* ipocontr = new KX_CameraIpoSGController(); - if (blendercamera->adt) { + Camera *blendercamera = (Camera*)cameraobj->GetBlenderObject()->data; - KX_CameraIpoSGController* ipocontr = new KX_CameraIpoSGController(); - cameraobj->GetSGNode()->AddSGController(ipocontr); - ipocontr->SetObject(cameraobj->GetSGNode()); - - ipocontr->m_lens = blendercamera->lens; - ipocontr->m_clipstart = blendercamera->clipsta; - ipocontr->m_clipend = blendercamera->clipend; + ipocontr->m_lens = blendercamera->lens; + ipocontr->m_clipstart = blendercamera->clipsta; + ipocontr->m_clipend = blendercamera->clipend; - BL_InterpolatorList *adtList= GetAdtList(blendercamera->adt, converter); + BL_InterpolatorList *adtList= GetAdtList(blendercamera->adt->action, converter); - // For each active channel in the adtList add an - // interpolator to the game object. + // For each active channel in the adtList add an + // interpolator to the game object. - KX_IInterpolator *interpolator; - KX_IScalarInterpolator *interp; + KX_IInterpolator *interpolator; + KX_IScalarInterpolator *interp; - if ((interp = adtList->GetScalarInterpolator("lens", 0))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_lens, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyLens(true); - } + if ((interp = adtList->GetScalarInterpolator("lens", 0))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_lens, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyLens(true); + } - if ((interp = adtList->GetScalarInterpolator("clip_start", 0))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_clipstart, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyClipStart(true); - } + if ((interp = adtList->GetScalarInterpolator("clip_start", 0))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_clipstart, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyClipStart(true); + } - if ((interp = adtList->GetScalarInterpolator("clip_end", 0))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_clipend, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyClipEnd(true); - } + if ((interp = adtList->GetScalarInterpolator("clip_end", 0))) { + interpolator= new KX_ScalarInterpolator(&ipocontr->m_clipend, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyClipEnd(true); + } + + return ipocontr; +} +void BL_ConvertCameraIpos(struct Camera* blendercamera, KX_GameObject *cameraobj,KX_BlenderSceneConverter *converter) +{ + + if (blendercamera->adt) { + SG_Controller* ipocontr = BL_CreateCameraIPO(blendercamera->adt->action, cameraobj, converter); + cameraobj->GetSGNode()->AddSGController(ipocontr); + ipocontr->SetObject(cameraobj->GetSGNode()); } } @@ -314,7 +315,7 @@ void BL_ConvertWorldIpos(struct World* blenderworld,KX_BlenderSceneConverter *co ipocontr->m_mist_rgb[1] = blenderworld->horg; ipocontr->m_mist_rgb[2] = blenderworld->horb; - BL_InterpolatorList *adtList= GetAdtList(blenderworld->adt, converter); + BL_InterpolatorList *adtList= GetAdtList(blenderworld->adt->action, converter); // For each active channel in the adtList add an // interpolator to the game object. @@ -356,7 +357,7 @@ static void ConvertMaterialIpos( gameobj->GetSGNode()->AddSGController(ipocontr); ipocontr->SetObject(gameobj->GetSGNode()); - BL_InterpolatorList *adtList= GetAdtList(blendermaterial->adt, converter); + BL_InterpolatorList *adtList= GetAdtList(blendermaterial->adt->action, converter); ipocontr->m_rgba[0] = blendermaterial->r; diff --git a/source/gameengine/Converter/KX_IpoConvert.h b/source/gameengine/Converter/KX_IpoConvert.h index d77a72a82e2..60e695c68a7 100644 --- a/source/gameengine/Converter/KX_IpoConvert.h +++ b/source/gameengine/Converter/KX_IpoConvert.h @@ -36,10 +36,18 @@ struct Object; +class SG_Controller *BL_CreateIPO(struct bAction *action, + class KX_GameObject* gameobj, + class KX_BlenderSceneConverter *converter); + void BL_ConvertIpos(struct Object* blenderobject, class KX_GameObject* gameobj, class KX_BlenderSceneConverter *converter); +class SG_Controller *BL_CreateLampIPO(struct bAction *action, + class KX_GameObject* lightobj, + class KX_BlenderSceneConverter *converter); + void BL_ConvertLampIpos(struct Lamp* blenderlight, class KX_GameObject* lightobj, class KX_BlenderSceneConverter *converter); @@ -47,6 +55,10 @@ void BL_ConvertLampIpos(struct Lamp* blenderlight, void BL_ConvertWorldIpos(struct World* blenderworld, class KX_BlenderSceneConverter *converter); +class SG_Controller *BL_CreateCameraIPO(struct bAction *action, + class KX_GameObject* cameraobj, + class KX_BlenderSceneConverter *converter); + void BL_ConvertCameraIpos(struct Camera* blendercamera, class KX_GameObject* cameraobj, class KX_BlenderSceneConverter *converter); diff --git a/source/gameengine/Converter/SConscript b/source/gameengine/Converter/SConscript index 9cfc3410748..0ae22d548c5 100644 --- a/source/gameengine/Converter/SConscript +++ b/source/gameengine/Converter/SConscript @@ -20,6 +20,7 @@ incs += ' #source/blender/misc #source/blender/blenloader #source/blender/gpu' incs += ' #source/blender/windowmanager' incs += ' #source/blender/makesrna' incs += ' #source/blender/ikplugin' +incs += ' #extern/Eigen2' incs += ' ' + env['BF_BULLET_INC'] diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index 51cfb5471c0..080e7196d5a 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -255,12 +255,15 @@ typedef struct PyObjectPlus_Proxy { #define KX_PYMETHODTABLE_NOARGS(class_name, method_name) \ {#method_name , (PyCFunction) class_name::sPy##method_name, METH_NOARGS, (const char *)class_name::method_name##_doc} +#define KX_PYMETHODTABLE_KEYWORDS(class_name, method_name) \ + {#method_name , (PyCFunction) class_name::sPy##method_name, METH_VARARGS|METH_KEYWORDS, (const char *)class_name::method_name##_doc} + /** * Function implementation macro */ #define KX_PYMETHODDEF_DOC(class_name, method_name, doc_string) \ const char class_name::method_name##_doc[] = doc_string; \ -PyObject* class_name::Py##method_name(PyObject* args, PyObject*) +PyObject* class_name::Py##method_name(PyObject* args, PyObject* kwds) #define KX_PYMETHODDEF_DOC_VARARGS(class_name, method_name, doc_string) \ const char class_name::method_name##_doc[] = doc_string; \ diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index a4824e0004d..546ec69bf29 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -545,6 +545,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0); bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", gm->flag & GAME_DISPLAY_LISTS) != 0); bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 1) != 0); + bool restrictAnimFPS = gm->flag & GAME_RESTRICT_ANIM_UPDATES; if(GLEW_ARB_multitexture && GLEW_VERSION_1_1) m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0); @@ -626,6 +627,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) m_ketsjiengine->SetUseFixedTime(fixed_framerate); m_ketsjiengine->SetTimingDisplay(frameRate, profile, properties); + m_ketsjiengine->SetRestrictAnimationFPS(restrictAnimFPS); m_engineInitialized = true; } diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp new file mode 100644 index 00000000000..08794042e37 --- /dev/null +++ b/source/gameengine/Ketsji/BL_Action.cpp @@ -0,0 +1,453 @@ +/** + * $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Mitchell Stokes. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BL_Action.cpp + * \ingroup ketsji + */ + +#include <cstdlib> + +#include "BL_Action.h" +#include "BL_ArmatureObject.h" +#include "BL_DeformableGameObject.h" +#include "BL_ShapeDeformer.h" +#include "KX_IpoConvert.h" +#include "KX_GameObject.h" + +// These three are for getting the action from the logic manager +#include "KX_Scene.h" +#include "KX_PythonInit.h" +#include "SCA_LogicManager.h" + +extern "C" { +#include "BKE_animsys.h" +#include "BKE_action.h" +#include "RNA_access.h" +#include "RNA_define.h" +} + +BL_Action::BL_Action(class KX_GameObject* gameobj) +: + m_action(NULL), + m_pose(NULL), + m_blendpose(NULL), + m_blendinpose(NULL), + m_ptrrna(NULL), + m_obj(gameobj), + m_startframe(0.f), + m_endframe(0.f), + m_endtime(0.f), + m_localtime(0.f), + m_blendin(0.f), + m_blendframe(0.f), + m_blendstart(0.f), + m_speed(0.f), + m_priority(0), + m_playmode(0), + m_ipo_flags(0), + m_done(true), + m_calc_localtime(true) +{ + if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) + { + BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj; + + m_ptrrna = new PointerRNA(); + RNA_id_pointer_create(&obj->GetArmatureObject()->id, m_ptrrna); + } + else + { + BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj; + BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer()); + + if (shape_deformer) + { + m_ptrrna = new PointerRNA(); + RNA_id_pointer_create(&shape_deformer->GetKey()->id, m_ptrrna); + } + } +} + +BL_Action::~BL_Action() +{ + if (m_pose) + game_free_pose(m_pose); + if (m_blendpose) + game_free_pose(m_blendpose); + if (m_blendinpose) + game_free_pose(m_blendinpose); + if (m_ptrrna) + delete m_ptrrna; + ClearControllerList(); +} + +void BL_Action::ClearControllerList() +{ + // Clear out the controller list + std::vector<SG_Controller*>::iterator it; + for (it = m_sg_contr_list.begin(); it != m_sg_contr_list.end(); it++) + { + m_obj->GetSGNode()->RemoveSGController((*it)); + delete *it; + } + + m_sg_contr_list.clear(); +} + +bool BL_Action::Play(const char* name, + float start, + float end, + short priority, + float blendin, + short play_mode, + float layer_weight, + short ipo_flags, + float playback_speed) +{ + + // Only start playing a new action if we're done, or if + // the new action has a higher priority + if (priority != 0 && !IsDone() && priority >= m_priority) + return false; + m_priority = priority; + bAction* prev_action = m_action; + + // First try to load the action + m_action = (bAction*)KX_GetActiveScene()->GetLogicManager()->GetActionByName(name); + if (!m_action) + { + printf("Failed to load action: %s\n", name); + m_done = true; + return false; + } + + if (prev_action != m_action) + { + // First get rid of any old controllers + ClearControllerList(); + + // Create an SG_Controller + SG_Controller *sg_contr = BL_CreateIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter()); + m_sg_contr_list.push_back(sg_contr); + m_obj->GetSGNode()->AddSGController(sg_contr); + sg_contr->SetObject(m_obj->GetSGNode()); + + // Extra controllers + if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_LIGHT) + { + sg_contr = BL_CreateLampIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter()); + m_sg_contr_list.push_back(sg_contr); + m_obj->GetSGNode()->AddSGController(sg_contr); + sg_contr->SetObject(m_obj->GetSGNode()); + } + else if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_CAMERA) + { + sg_contr = BL_CreateCameraIPO(m_action, m_obj, KX_GetActiveScene()->GetSceneConverter()); + m_sg_contr_list.push_back(sg_contr); + m_obj->GetSGNode()->AddSGController(sg_contr); + sg_contr->SetObject(m_obj->GetSGNode()); + } + } + + m_ipo_flags = ipo_flags; + InitIPO(); + + // Setup blendin shapes/poses + if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) + { + BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj; + obj->GetMRDPose(&m_blendinpose); + } + else + { + BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj; + BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer()); + + if (shape_deformer && shape_deformer->GetKey()) + { + obj->GetShape(m_blendinshape); + + // Now that we have the previous blend shape saved, we can clear out the key to avoid any + // further interference. + KeyBlock *kb; + for (kb=(KeyBlock*)shape_deformer->GetKey()->block.first; kb; kb=(KeyBlock*)kb->next) + kb->curval = 0.f; + } + } + + // Now that we have an action, we have something we can play + m_starttime = KX_GetActiveEngine()->GetFrameTime(); + m_startframe = m_localtime = start; + m_endframe = end; + m_blendin = blendin; + m_playmode = play_mode; + m_endtime = 0.f; + m_blendframe = 0.f; + m_blendstart = 0.f; + m_speed = playback_speed; + m_layer_weight = layer_weight; + + m_done = false; + + return true; +} + +void BL_Action::Stop() +{ + m_done = true; +} + +bool BL_Action::IsDone() +{ + return m_done; +} + +void BL_Action::InitIPO() +{ + // Initialize the IPOs + std::vector<SG_Controller*>::iterator it; + for (it = m_sg_contr_list.begin(); it != m_sg_contr_list.end(); it++) + { + (*it)->SetOption(SG_Controller::SG_CONTR_IPO_RESET, true); + (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, m_ipo_flags & ACT_IPOFLAG_FORCE); + (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_ADD, m_ipo_flags & ACT_IPOFLAG_ADD); + (*it)->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, m_ipo_flags & ACT_IPOFLAG_LOCAL); + } +} + +bAction *BL_Action::GetAction() +{ + return (IsDone()) ? NULL : m_action; +} + +float BL_Action::GetFrame() +{ + return m_localtime; +} + +void BL_Action::SetFrame(float frame) +{ + // Clamp the frame to the start and end frame + if (frame < min(m_startframe, m_endframe)) + frame = min(m_startframe, m_endframe); + else if (frame > max(m_startframe, m_endframe)) + frame = max(m_startframe, m_endframe); + + m_localtime = frame; + m_calc_localtime = false; +} + +void BL_Action::SetPlayMode(short play_mode) +{ + m_playmode = play_mode; +} + +void BL_Action::SetTimes(float start, float end) +{ + m_startframe = start; + m_endframe = end; +} + +void BL_Action::SetLocalTime(float curtime) +{ + float dt = (curtime-m_starttime)*KX_KetsjiEngine::GetAnimFrameRate()*m_speed; + + if (m_endframe < m_startframe) + dt = -dt; + + m_localtime = m_startframe + dt; +} + +void BL_Action::ResetStartTime(float curtime) +{ + float dt = m_localtime - m_startframe; + + m_starttime = curtime - dt / (KX_KetsjiEngine::GetAnimFrameRate()*m_speed); + SetLocalTime(curtime); +} + +void BL_Action::IncrementBlending(float curtime) +{ + // Setup m_blendstart if we need to + if (m_blendstart == 0.f) + m_blendstart = curtime; + + // Bump the blend frame + m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate(); + + // Clamp + if (m_blendframe>m_blendin) + m_blendframe = m_blendin; +} + + +void BL_Action::BlendShape(Key* key, float srcweight, std::vector<float>& blendshape) +{ + vector<float>::const_iterator it; + float dstweight; + KeyBlock *kb; + + dstweight = 1.0F - srcweight; + //printf("Dst: %f\tSrc: %f\n", srcweight, dstweight); + for (it=blendshape.begin(), kb = (KeyBlock*)key->block.first; + kb && it != blendshape.end(); + kb = (KeyBlock*)kb->next, it++) { + //printf("OirgKeys: %f\t%f\n", kb->curval, (*it)); + kb->curval = kb->curval * dstweight + (*it) * srcweight; + //printf("NewKey: %f\n", kb->curval); + } + //printf("\n"); +} + +void BL_Action::Update(float curtime) +{ + // Don't bother if we're done with the animation + if (m_done) + return; + + curtime -= KX_KetsjiEngine::GetSuspendedDelta(); + + if (m_calc_localtime) + SetLocalTime(curtime); + else + { + ResetStartTime(curtime); + m_calc_localtime = true; + } + + // Handle wrap around + if (m_localtime < min(m_startframe, m_endframe) || m_localtime > max(m_startframe, m_endframe)) + { + switch(m_playmode) + { + case ACT_MODE_PLAY: + // Clamp + m_localtime = m_endframe; + m_done = true; + break; + case ACT_MODE_LOOP: + // Put the time back to the beginning + m_localtime = m_startframe; + m_starttime = curtime; + break; + case ACT_MODE_PING_PONG: + // Swap the start and end frames + float temp = m_startframe; + m_startframe = m_endframe; + m_endframe = temp; + + m_starttime = curtime; + + break; + } + + if (!m_done) + InitIPO(); + } + + if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) + { + BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj; + obj->GetPose(&m_pose); + + // Extract the pose from the action + { + Object *arm = obj->GetArmatureObject(); + bPose *temp = arm->pose; + + arm->pose = m_pose; + animsys_evaluate_action(m_ptrrna, m_action, NULL, m_localtime); + + arm->pose = temp; + } + + // Handle blending between armature actions + if (m_blendin && m_blendframe<m_blendin) + { + IncrementBlending(curtime); + + // Calculate weight + float weight = 1.f - (m_blendframe/m_blendin); + + // Blend the poses + game_blend_poses(m_pose, m_blendinpose, weight); + } + + + // Handle layer blending + if (m_layer_weight >= 0) + { + obj->GetMRDPose(&m_blendpose); + game_blend_poses(m_pose, m_blendpose, m_layer_weight); + } + + obj->SetPose(m_pose); + + obj->SetActiveAction(NULL, 0, curtime); + } + else + { + BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj; + BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer()); + + // Handle shape actions if we have any + if (shape_deformer && shape_deformer->GetKey()) + { + Key *key = shape_deformer->GetKey(); + + + animsys_evaluate_action(m_ptrrna, m_action, NULL, m_localtime); + + // Handle blending between shape actions + if (m_blendin && m_blendframe < m_blendin) + { + IncrementBlending(curtime); + + float weight = 1.f - (m_blendframe/m_blendin); + + // We go through and clear out the keyblocks so there isn't any interference + // from other shape actions + KeyBlock *kb; + for (kb=(KeyBlock*)key->block.first; kb; kb=(KeyBlock*)kb->next) + kb->curval = 0.f; + + // Now blend the shape + BlendShape(key, weight, m_blendinshape); + } + + // Handle layer blending + if (m_layer_weight >= 0) + { + obj->GetShape(m_blendshape); + BlendShape(key, m_layer_weight, m_blendshape); + } + + obj->SetActiveAction(NULL, 0, curtime); + } + + + InitIPO(); + m_obj->UpdateIPO(m_localtime, m_ipo_flags & ACT_IPOFLAG_CHILD); + } +} diff --git a/source/gameengine/Ketsji/BL_Action.h b/source/gameengine/Ketsji/BL_Action.h new file mode 100644 index 00000000000..92fbe95fd54 --- /dev/null +++ b/source/gameengine/Ketsji/BL_Action.h @@ -0,0 +1,144 @@ +/** + * $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Mitchell Stokes. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BL_Action.h + * \ingroup ketsji + */ + +#ifndef __BL_ACTION +#define __BL_ACTION + + +#include <vector> + +#ifdef WITH_CXX_GUARDEDALLOC +#include "MEM_guardedalloc.h" +#endif + + +class BL_Action +{ +private: + struct bAction* m_action; + struct bPose* m_pose; + struct bPose* m_blendpose; + struct bPose* m_blendinpose; + struct PointerRNA *m_ptrrna; + std::vector<class SG_Controller*> m_sg_contr_list; + class KX_GameObject* m_obj; + std::vector<float> m_blendshape; + std::vector<float> m_blendinshape; + + float m_startframe; + float m_endframe; + float m_starttime; + float m_endtime; + float m_localtime; + + float m_blendin; + float m_blendframe; + float m_blendstart; + + float m_layer_weight; + + float m_speed; + + short m_priority; + + short m_playmode; + + short m_ipo_flags; + + bool m_done; + bool m_calc_localtime; + + void ClearControllerList(); + void InitIPO(); + void SetLocalTime(float curtime); + void ResetStartTime(float curtime); + void IncrementBlending(float curtime); + void BlendShape(struct Key* key, float srcweight, std::vector<float>& blendshape); +public: + BL_Action(class KX_GameObject* gameobj); + ~BL_Action(); + + /** + * Play an action + */ + bool Play(const char* name, + float start, + float end, + short priority, + float blendin, + short play_mode, + float layer_weight, + short ipo_flags, + float playback_speed); + /** + * Stop playing the action + */ + void Stop(); + /** + * Whether or not the action is still playing + */ + bool IsDone(); + /** + * Update the action's frame, etc. + */ + void Update(float curtime); + + // Accessors + float GetFrame(); + struct bAction *GetAction(); + + // Mutators + void SetFrame(float frame); + void SetPlayMode(short play_mode); + void SetTimes(float start, float end); + + enum + { + ACT_MODE_PLAY = 0, + ACT_MODE_LOOP, + ACT_MODE_PING_PONG, + ACT_MODE_MAX, + }; + + enum + { + ACT_IPOFLAG_FORCE = 1, + ACT_IPOFLAG_LOCAL = 2, + ACT_IPOFLAG_ADD = 4, + ACT_IPOFLAG_CHILD = 8, + }; + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_Action"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif //BL_ACTION + diff --git a/source/gameengine/Ketsji/BL_ActionManager.cpp b/source/gameengine/Ketsji/BL_ActionManager.cpp new file mode 100644 index 00000000000..4e4d3bc539e --- /dev/null +++ b/source/gameengine/Ketsji/BL_ActionManager.cpp @@ -0,0 +1,110 @@ +/** + * $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Mitchell Stokes. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BL_ActionManager.cpp + * \ingroup ketsji + */ + +#include "BL_ActionManager.h" + +BL_ActionManager::BL_ActionManager(class KX_GameObject *obj) +{ + for (int i=0; i<MAX_ACTION_LAYERS; ++i) + m_layers[i] = new BL_Action(obj); +} + +BL_ActionManager::~BL_ActionManager() +{ + for (int i=0; i<MAX_ACTION_LAYERS; ++i) + delete m_layers[i]; +} + +float BL_ActionManager::GetActionFrame(short layer) +{ + return m_layers[layer]->GetFrame(); + + return 0.f; +} + +void BL_ActionManager::SetActionFrame(short layer, float frame) +{ + m_layers[layer]->SetFrame(frame); +} + +struct bAction *BL_ActionManager::GetCurrentAction(short layer) +{ + return m_layers[layer]->GetAction(); + + return 0; +} + +void BL_ActionManager::SetPlayMode(short layer, short mode) +{ + m_layers[layer]->SetPlayMode(mode); +} + +void BL_ActionManager::SetTimes(short layer, float start, float end) +{ + m_layers[layer]->SetTimes(start, end); +} + +bool BL_ActionManager::PlayAction(const char* name, + float start, + float end, + short layer, + short priority, + float blendin, + short play_mode, + float layer_weight, + short ipo_flags, + float playback_speed) +{ + // Disable layer blending on the first layer + if (layer == 0) layer_weight = -1.f; + + return m_layers[layer]->Play(name, start, end, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed); +} + +void BL_ActionManager::StopAction(short layer) +{ + m_layers[layer]->Stop(); +} + +bool BL_ActionManager::IsActionDone(short layer) +{ + return m_layers[layer]->IsDone(); + + return true; +} + +void BL_ActionManager::Update(float curtime) +{ + for (int i=0; i<MAX_ACTION_LAYERS; ++i) + { + if (!m_layers[i]->IsDone()) + { + m_layers[i]->Update(curtime); + } + } +} diff --git a/source/gameengine/Ketsji/BL_ActionManager.h b/source/gameengine/Ketsji/BL_ActionManager.h new file mode 100644 index 00000000000..a3c8379981e --- /dev/null +++ b/source/gameengine/Ketsji/BL_ActionManager.h @@ -0,0 +1,106 @@ +/** + * $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Mitchell Stokes. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BL_ActionManager.cpp + * \ingroup ketsji + */ + +#ifndef __BL_ACTIONMANAGER +#define __BL_ACTIONMANAGER + +#include "BL_Action.h" + +#define MAX_ACTION_LAYERS 8 + +/** + * BL_ActionManager is responsible for handling a KX_GameObject's actions. + */ +class BL_ActionManager +{ +private: + BL_Action* m_layers[MAX_ACTION_LAYERS]; + +public: + BL_ActionManager(class KX_GameObject* obj); + ~BL_ActionManager(); + + bool PlayAction(const char* name, + float start, + float end, + short layer=0, + short priority=0, + float blendin=0.f, + short play_mode=0, + float layer_weight=0.f, + short ipo_flags=0, + float playback_speed=1.f); + /** + * Gets the current frame of an action + */ + float GetActionFrame(short layer); + + /** + * Sets the current frame of an action + */ + void SetActionFrame(short layer, float frame); + + /** + * Gets the currently running action on the given layer + */ + struct bAction *GetCurrentAction(short layer); + + /** + * Sets play mode of the action on the given layer + */ + void SetPlayMode(short layer, short mode); + + /** + * Sets the start and end times of the action on the given layer + */ + void SetTimes(short layer, float start, float end); + + /** + * Stop playing the action on the given layer + */ + void StopAction(short layer); + + /** + * Check if an action has finished playing + */ + bool IsActionDone(short layer); + + /** + * Update any running actions + */ + void Update(float); + +#ifdef WITH_CXX_GUARDEDALLOC +public: + void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_ActionManager"); } + void operator delete( void *mem ) { MEM_freeN(mem); } +#endif +}; + +#endif //BL_ACTIONMANAGER + diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index 8222bf4b65f..99c9fb25a65 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -45,6 +45,7 @@ set(INC ../../blender/gpu ../../blender/imbuf ../../blender/makesdna + ../../blender/makesrna ../../blender/python ../../blender/python/generic ../../blender/python/mathutils @@ -59,6 +60,8 @@ set(INC_SYS ) set(SRC + BL_Action.cpp + BL_ActionManager.cpp BL_BlenderShader.cpp BL_Material.cpp BL_Shader.cpp @@ -128,6 +131,8 @@ set(SRC KX_WorldInfo.cpp KX_WorldIpoController.cpp + BL_Action.h + BL_ActionManager.h BL_BlenderShader.h BL_Material.h BL_Shader.h @@ -223,6 +228,7 @@ endif() if(WITH_AUDASPACE) list(APPEND INC ../../../intern/audaspace/intern + ../../../intern/audaspace/FX ) add_definitions(-DWITH_AUDASPACE) endif() diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 74652877e48..d51e2aa5386 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -74,6 +74,8 @@ typedef unsigned long uint_ptr; #include "SCA_IController.h" #include "NG_NetworkScene.h" //Needed for sendMessage() +#include "BL_ActionManager.h" + #include "PyObjectPlus.h" /* python stuff */ // This file defines relationships between parents and children @@ -107,6 +109,7 @@ KX_GameObject::KX_GameObject( m_pGraphicController(NULL), m_xray(false), m_pHitObject(NULL), + m_actionManager(NULL), m_isDeformable(false) #ifdef WITH_PYTHON , m_attr_dict(NULL) @@ -154,6 +157,10 @@ KX_GameObject::~KX_GameObject() { delete m_pGraphicController; } + if (m_actionManager) + { + delete m_actionManager; + } #ifdef WITH_PYTHON if (m_attr_dict) { PyDict_Clear(m_attr_dict); /* incase of circular refs or other weird cases */ @@ -344,6 +351,69 @@ void KX_GameObject::RemoveParent(KX_Scene *scene) } } +BL_ActionManager* KX_GameObject::GetActionManager() +{ + // We only want to create an action manager if we need it + if (!m_actionManager) + m_actionManager = new BL_ActionManager(this); + + return m_actionManager; +} + +bool KX_GameObject::PlayAction(const char* name, + float start, + float end, + short layer, + short priority, + float blendin, + short play_mode, + float layer_weight, + short ipo_flags, + float playback_speed) +{ + return GetActionManager()->PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed); +} + +void KX_GameObject::StopAction(short layer) +{ + GetActionManager()->StopAction(layer); +} + +bool KX_GameObject::IsActionDone(short layer) +{ + return GetActionManager()->IsActionDone(layer); +} + +void KX_GameObject::UpdateActionManager(float curtime) +{ + GetActionManager()->Update(curtime); +} + +float KX_GameObject::GetActionFrame(short layer) +{ + return GetActionManager()->GetActionFrame(layer); +} + +void KX_GameObject::SetActionFrame(short layer, float frame) +{ + GetActionManager()->SetActionFrame(layer, frame); +} + +bAction *KX_GameObject::GetCurrentAction(short layer) +{ + return GetActionManager()->GetCurrentAction(layer); +} + +void KX_GameObject::SetPlayMode(short layer, short mode) +{ + GetActionManager()->SetPlayMode(layer, mode); +} + +void KX_GameObject::SetTimes(short layer, float start, float end) +{ + GetActionManager()->SetTimes(layer, start, end); +} + void KX_GameObject::ProcessReplica() { SCA_IObject::ProcessReplica(); @@ -353,6 +423,8 @@ void KX_GameObject::ProcessReplica() m_pSGNode = NULL; m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info); m_pClient_info->m_gameobject = this; + if (m_actionManager) + m_actionManager = new BL_ActionManager(this); m_state = 0; #ifdef WITH_PYTHON @@ -1497,6 +1569,12 @@ PyMethodDef KX_GameObject::Methods[] = { KX_PYMETHODTABLE_O(KX_GameObject, getDistanceTo), KX_PYMETHODTABLE_O(KX_GameObject, getVectTo), KX_PYMETHODTABLE(KX_GameObject, sendMessage), + + KX_PYMETHODTABLE_KEYWORDS(KX_GameObject, playAction), + KX_PYMETHODTABLE(KX_GameObject, stopAction), + KX_PYMETHODTABLE(KX_GameObject, getActionFrame), + KX_PYMETHODTABLE(KX_GameObject, setActionFrame), + KX_PYMETHODTABLE(KX_GameObject, isPlayingAction), // dict style access for props {"get",(PyCFunction) KX_GameObject::sPyget, METH_VARARGS}, @@ -2975,6 +3053,112 @@ KX_PYMETHODDEF_DOC_VARARGS(KX_GameObject, sendMessage, Py_RETURN_NONE; } +static void layer_check(short &layer, const char *method_name) +{ + if (layer < 0 || layer >= MAX_ACTION_LAYERS) + { + printf("KX_GameObject.%s(): given layer (%d) is out of range (0 - %d), setting to 0.\n", method_name, layer, MAX_ACTION_LAYERS-1); + layer = 0; + } +} + +KX_PYMETHODDEF_DOC(KX_GameObject, playAction, + "playAction(name, start_frame, end_frame, layer=0, priority=0 blendin=0, play_mode=ACT_MODE_PLAY, layer_weight=0.0, ipo_flags=0, speed=1.0)\n" + "Plays an action\n") +{ + const char* name; + float start, end, blendin=0.f, speed=1.f, layer_weight=0.f; + short layer=0, priority=0; + short ipo_flags=0; + short play_mode=0; + + static const char *kwlist[] = {"name", "start_frame", "end_frame", "layer", "priority", "blendin", "play_mode", "layer_weight", "ipo_flags", "speed", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "sff|hhfhfhf:playAction", const_cast<char**>(kwlist), + &name, &start, &end, &layer, &priority, &blendin, &play_mode, &layer_weight, &ipo_flags, &speed)) + return NULL; + + layer_check(layer, "playAction"); + + if (play_mode < 0 || play_mode > BL_Action::ACT_MODE_MAX) + { + printf("KX_GameObject.playAction(): given play_mode (%d) is out of range (0 - %d), setting to ACT_MODE_PLAY", play_mode, BL_Action::ACT_MODE_MAX-1); + play_mode = BL_Action::ACT_MODE_MAX; + } + + if (layer_weight < 0.f || layer_weight > 1.f) + { + printf("KX_GameObject.playAction(): given layer_weight (%f) is out of range (0.0 - 1.0), setting to 0.0", layer_weight); + layer_weight = 0.f; + } + + PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, speed); + + Py_RETURN_NONE; +} + +KX_PYMETHODDEF_DOC(KX_GameObject, stopAction, + "stopAction(layer=0)\n" + "Stop playing the action on the given layer\n") +{ + short layer=0; + + if (!PyArg_ParseTuple(args, "|h:stopAction", &layer)) + return NULL; + + layer_check(layer, "stopAction"); + + StopAction(layer); + + Py_RETURN_NONE; +} + +KX_PYMETHODDEF_DOC(KX_GameObject, getActionFrame, + "getActionFrame(layer=0)\n" + "Gets the current frame of the action playing in the supplied layer\n") +{ + short layer=0; + + if (!PyArg_ParseTuple(args, "|h:getActionFrame", &layer)) + return NULL; + + layer_check(layer, "getActionFrame"); + + return PyLong_FromLong(GetActionFrame(layer)); +} + +KX_PYMETHODDEF_DOC(KX_GameObject, setActionFrame, + "setActionFrame(frame, layer=0)\n" + "Set the current frame of the action playing in the supplied layer\n") +{ + short layer=0; + float frame; + + if (!PyArg_ParseTuple(args, "f|h:setActionFrame", &frame, &layer)) + return NULL; + + layer_check(layer, "setActionFrame"); + + SetActionFrame(layer, frame); + + Py_RETURN_NONE; +} + +KX_PYMETHODDEF_DOC(KX_GameObject, isPlayingAction, + "isPlayingAction(layer=0)\n" + "Checks to see if there is an action playing in the given layer\n") +{ + short layer=0; + + if (!PyArg_ParseTuple(args, "|h:isPlayingAction", &layer)) + return NULL; + + layer_check(layer, "isPlayingAction"); + + return PyBool_FromLong(!IsActionDone(layer)); +} + + /* dict style access */ diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 50fbebe1341..6e79914172b 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -63,7 +63,9 @@ class RAS_MeshObject; class KX_IPhysicsController; class PHY_IGraphicController; class PHY_IPhysicsEnvironment; +class BL_ActionManager; struct Object; +struct bAction; #ifdef WITH_PYTHON /* utility conversion function */ @@ -112,6 +114,11 @@ protected: SG_Node* m_pSGNode; MT_CmMatrix4x4 m_OpenGL_4x4Matrix; + + // The action manager is used to play/stop/update actions + BL_ActionManager* m_actionManager; + + BL_ActionManager* GetActionManager(); public: bool m_isDeformable; @@ -198,6 +205,68 @@ public: */ void RemoveParent(KX_Scene *scene); + /********************************* + * Animation API + *********************************/ + + /** + * Adds an action to the object's action manager + */ + bool PlayAction(const char* name, + float start, + float end, + short layer=0, + short priority=0, + float blendin=0.f, + short play_mode=0, + float layer_weight=0.f, + short ipo_flags=0, + float playback_speed=1.f); + + /** + * Gets the current frame of an action + */ + float GetActionFrame(short layer); + + /** + * Sets the current frame of an action + */ + void SetActionFrame(short layer, float frame); + + /** + * Gets the currently running action on the given layer + */ + bAction *GetCurrentAction(short layer); + + /** + * Sets play mode of the action on the given layer + */ + void SetPlayMode(short layer, short mode); + + /** + * Sets the start and end times of the action on the given layer + */ + void SetTimes(short layer, float start, float end); + + /** + * Stop playing the action on the given layer + */ + void StopAction(short layer); + + /** + * Check if an action has finished playing + */ + bool IsActionDone(short layer); + + /** + * Kick the object's action manager + */ + void UpdateActionManager(float curtime); + + /********************************* + * End Animation API + *********************************/ + /** * Construct a game object. This class also inherits the * default constructors - use those with care! @@ -853,6 +922,12 @@ public: KX_PYMETHOD_DOC_O(KX_GameObject,getVectTo); KX_PYMETHOD_DOC_VARARGS(KX_GameObject, sendMessage); KX_PYMETHOD_VARARGS(KX_GameObject, ReinstancePhysicsMesh); + + KX_PYMETHOD_DOC(KX_GameObject, playAction); + KX_PYMETHOD_DOC(KX_GameObject, stopAction); + KX_PYMETHOD_DOC(KX_GameObject, getActionFrame); + KX_PYMETHOD_DOC(KX_GameObject, setActionFrame); + KX_PYMETHOD_DOC(KX_GameObject, isPlayingAction); /* Dict access */ KX_PYMETHOD_VARARGS(KX_GameObject,get); diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index f41e0c16457..b1a214b7c1c 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -70,6 +70,7 @@ #ifdef WITH_AUDASPACE # include "AUD_C-API.h" +# include "AUD_I3DDevice.h" #endif #include "NG_NetworkScene.h" @@ -91,10 +92,10 @@ const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = { "Physics:", // tc_physics - "Logic", // tc_logic + "Logic:", // tc_logic + "Animations:", // tc_animations "Network:", // tc_network "Scenegraph:", // tc_scenegraph - "Sound:", // tc_sound "Rasterizer:", // tc_rasterizer "Services:", // tc_services "Overhead:", // tc_overhead @@ -108,6 +109,7 @@ double KX_KetsjiEngine::m_anim_framerate = 25.0; double KX_KetsjiEngine::m_suspendedtime = 0.0; double KX_KetsjiEngine::m_suspendeddelta = 0.0; double KX_KetsjiEngine::m_average_framerate = 0.0; +bool KX_KetsjiEngine::m_restrict_anim_fps = false; /** @@ -137,6 +139,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_frameTime(0.f), m_clockTime(0.f), m_previousClockTime(0.f), + m_previousAnimTime(0.f), m_exitcode(KX_EXIT_REQUEST_NO_REQUEST), @@ -578,7 +581,7 @@ else framestep = (frames*timestep)/m_maxLogicFrame; frames = m_maxLogicFrame; } - + while (frames) { @@ -657,7 +660,14 @@ else m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE); scene->UpdateParents(m_frameTime); - + + if (!GetRestrictAnimationFPS()) + { + m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); + scene->UpdateAnimations(m_frameTime); + } + m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_PHYSICS2); scene->GetPhysicsEnvironment()->beginFrame(); @@ -681,8 +691,6 @@ else else if(scene->getSuspendedTime()==0.0) scene->setSuspendedTime(m_clockTime); - - DoSound(scene); m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true); } @@ -758,14 +766,30 @@ else if(scene->getSuspendedTime()==0.0) scene->setSuspendedTime(m_clockTime); - DoSound(scene); - m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true); } } + + // Handle the animations independently of the logic time step + if (GetRestrictAnimationFPS()) + { + m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); - m_previousClockTime = m_clockTime; + double anim_timestep = 1.0/KX_GetActiveScene()->GetAnimationFPS(); + if (m_clockTime - m_previousAnimTime > anim_timestep) + { + // Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep) + // printf("Anim fps: %f\n", 1.0/(m_clockTime - m_previousAnimTime)); + m_previousAnimTime = m_clockTime; + for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit) + { + (*sceneit)->UpdateAnimations(m_frameTime); + } + } + m_previousClockTime = m_clockTime; + } // Start logging time spend outside main loop m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true); @@ -980,29 +1004,6 @@ const STR_String& KX_KetsjiEngine::GetExitString() } - -void KX_KetsjiEngine::DoSound(KX_Scene* scene) -{ - m_logger->StartLog(tc_sound, m_kxsystem->GetTimeInSeconds(), true); - - KX_Camera* cam = scene->GetActiveCamera(); - if (!cam) - return; - - float f[4]; - - cam->NodeGetWorldPosition().getValue(f); - AUD_setListenerLocation(f); - - cam->GetLinearVelocity().getValue(f); - AUD_setListenerVelocity(f); - - cam->NodeGetWorldOrientation().getRotation().getValue(f); - AUD_setListenerOrientation(f); -} - - - void KX_KetsjiEngine::SetBackGround(KX_WorldInfo* wi) { if (wi->hasWorld()) @@ -1806,6 +1807,16 @@ void KX_KetsjiEngine::SetMaxPhysicsFrame(int frame) m_maxPhysicsFrame = frame; } +bool KX_KetsjiEngine::GetRestrictAnimationFPS() +{ + return m_restrict_anim_fps; +} + +void KX_KetsjiEngine::SetRestrictAnimationFPS(bool bRestrictAnimFPS) +{ + m_restrict_anim_fps = bRestrictAnimFPS; +} + double KX_KetsjiEngine::GetAnimFrameRate() { return m_anim_framerate; diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index 8cd6fdb8f5f..b1009c7d8f0 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -108,6 +108,7 @@ private: double m_frameTime;//discrete timestamp of the 'game logic frame' double m_clockTime;//current time double m_previousClockTime;//previous clock time + double m_previousAnimTime; //the last time animations were updated double m_remainingTime; static int m_maxLogicFrame; /* maximum number of consecutive logic frame */ @@ -115,6 +116,8 @@ private: static double m_ticrate; static double m_anim_framerate; /* for animation playback only - ipo and action */ + static bool m_restrict_anim_fps; + static double m_suspendedtime; static double m_suspendeddelta; @@ -147,9 +150,9 @@ private: tc_first = 0, tc_physics = 0, tc_logic, + tc_animations, tc_network, tc_scenegraph, - tc_sound, tc_rasterizer, tc_services, // time spend in miscelaneous activities tc_overhead, // profile info drawing overhead @@ -195,7 +198,6 @@ private: void RenderDebugProperties(); void RenderShadowBuffers(KX_Scene *scene); void SetBackGround(KX_WorldInfo* worldinfo); - void DoSound(KX_Scene* scene); void RenderFonts(KX_Scene* scene); public: @@ -321,6 +323,16 @@ public: static void SetMaxPhysicsFrame(int frame); /** + * Gets whether or not to lock animation updates to the animframerate + */ + static bool GetRestrictAnimationFPS(); + + /** + * Sets whether or not to lock animation updates to the animframerate + */ + static void SetRestrictAnimationFPS(bool bRestrictAnimFPS); + + /** * Gets the framerate for playing animations. (actions and ipos) */ static double GetAnimFrameRate(); diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index f643030e3a2..06db84feb23 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -113,6 +113,7 @@ extern "C" { #include "NG_NetworkScene.h" //Needed for sendMessage() #include "BL_Shader.h" +#include "BL_Action.h" #include "KX_PyMath.h" @@ -1628,6 +1629,11 @@ PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack KX_MACRO_addTypesToDict(d, ROT_MODE_ZXY, ROT_MODE_ZXY); KX_MACRO_addTypesToDict(d, ROT_MODE_ZYX, ROT_MODE_ZYX); + /* BL_Action play modes */ + KX_MACRO_addTypesToDict(d, KX_ACTION_MODE_PLAY, BL_Action::ACT_MODE_PLAY); + KX_MACRO_addTypesToDict(d, KX_ACTION_MODE_LOOP, BL_Action::ACT_MODE_LOOP); + KX_MACRO_addTypesToDict(d, KX_ACTION_MODE_PING_PONG, BL_Action::ACT_MODE_PING_PONG); + // Check for errors if (PyErr_Occurred()) { diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 28dc660037c..a49c1bf4b4c 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -1502,7 +1502,12 @@ void KX_Scene::LogicBeginFrame(double curtime) m_logicmgr->BeginFrame(curtime, 1.0/KX_KetsjiEngine::GetTicRate()); } - +void KX_Scene::UpdateAnimations(double curtime) +{ + // Update any animations + for (int i=0; i<GetObjectList()->GetCount(); ++i) + ((KX_GameObject*)GetObjectList()->GetValue(i))->UpdateActionManager(curtime); +} void KX_Scene::LogicUpdateFrame(double curtime, bool frame) { @@ -1668,6 +1673,11 @@ double KX_Scene::getSuspendedDelta() return m_suspendeddelta; } +short KX_Scene::GetAnimationFPS() +{ + return m_blenderScene->r.frs_sec; +} + #ifdef USE_BULLET #include "KX_BulletPhysicsController.h" #endif diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index 367bf0b82da..da9cc12c76a 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -340,6 +340,7 @@ public: */ void LogicBeginFrame(double curtime); void LogicUpdateFrame(double curtime, bool frame); + void UpdateAnimations(double curtime); void LogicEndFrame( @@ -565,6 +566,8 @@ public: void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* physEnv); void SetGravity(const MT_Vector3& gravity); + + short GetAnimationFPS(); /** * Sets the node tree for this scene. diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index 75012181ac2..6c7b515c095 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -39,17 +39,22 @@ #ifdef WITH_AUDASPACE # include "AUD_C-API.h" +# include "AUD_PingPongFactory.h" +# include "AUD_IDevice.h" +# include "AUD_I3DHandle.h" #endif #include "KX_GameObject.h" #include "KX_PyMath.h" // needed for PyObjectFrom() +#include "KX_PythonInit.h" +#include "KX_Camera.h" #include <iostream> /* ------------------------------------------------------------------------- */ /* Native functions */ /* ------------------------------------------------------------------------- */ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, - AUD_Sound* sound, + AUD_Reference<AUD_IFactory> sound, float volume, float pitch, bool is3d, @@ -62,7 +67,6 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, m_pitch = pitch; m_is3d = is3d; m_3d = settings; - m_handle = NULL; m_type = type; m_isplaying = false; } @@ -71,22 +75,20 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, KX_SoundActuator::~KX_SoundActuator() { - if(m_handle) - AUD_stop(m_handle); + if(!m_handle.isNull()) + m_handle->stop(); } void KX_SoundActuator::play() { - if(m_handle) - AUD_stop(m_handle); + if(!m_handle.isNull()) + m_handle->stop(); - if(!m_sound) + if(m_sound.isNull()) return; // this is the sound that will be played and not deleted afterwards - AUD_Sound* sound = m_sound; - // this sound is for temporary stacked sounds, will be deleted if not NULL - AUD_Sound* sound2 = NULL; + AUD_Reference<AUD_IFactory> sound = m_sound; bool loop = false; @@ -94,7 +96,7 @@ void KX_SoundActuator::play() { case KX_SOUNDACT_LOOPBIDIRECTIONAL: case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: - sound = sound2 = AUD_pingpongSound(sound); + sound = new AUD_PingPongFactory(sound); // fall through case KX_SOUNDACT_LOOPEND: case KX_SOUNDACT_LOOPSTOP: @@ -106,32 +108,28 @@ void KX_SoundActuator::play() break; } - if(m_is3d) + m_handle = AUD_getDevice()->play(sound, 0); + + AUD_Reference<AUD_I3DHandle> handle3d = AUD_Reference<AUD_I3DHandle>(m_handle); + + if(m_is3d && !handle3d.isNull()) { - // sound shall be played 3D - m_handle = AUD_play(sound, 0); - - AUD_setRelative(m_handle, false); - AUD_setVolumeMaximum(m_handle, m_3d.max_gain); - AUD_setVolumeMinimum(m_handle, m_3d.min_gain); - AUD_setDistanceReference(m_handle, m_3d.reference_distance); - AUD_setDistanceMaximum(m_handle, m_3d.max_distance); - AUD_setAttenuation(m_handle, m_3d.rolloff_factor); - AUD_setConeAngleInner(m_handle, m_3d.cone_inner_angle); - AUD_setConeAngleOuter(m_handle, m_3d.cone_outer_angle); - AUD_setConeVolumeOuter(m_handle, m_3d.cone_outer_gain); + handle3d->setRelative(true); + handle3d->setVolumeMaximum(m_3d.max_gain); + handle3d->setVolumeMinimum(m_3d.min_gain); + handle3d->setDistanceReference(m_3d.reference_distance); + handle3d->setDistanceMaximum(m_3d.max_distance); + handle3d->setAttenuation(m_3d.rolloff_factor); + handle3d->setConeAngleInner(m_3d.cone_inner_angle); + handle3d->setConeAngleOuter(m_3d.cone_outer_angle); + handle3d->setConeVolumeOuter(m_3d.cone_outer_gain); } - else - m_handle = AUD_play(sound, 0); if(loop) - AUD_setLoop(m_handle, -1); - AUD_setSoundPitch(m_handle, m_pitch); - AUD_setSoundVolume(m_handle, m_volume); + m_handle->setLoopCount(-1); + m_handle->setPitch(m_pitch); + m_handle->setVolume(m_volume); m_isplaying = true; - - if(sound2) - AUD_unload(sound2); } CValue* KX_SoundActuator::GetReplica() @@ -144,7 +142,7 @@ CValue* KX_SoundActuator::GetReplica() void KX_SoundActuator::ProcessReplica() { SCA_IActuator::ProcessReplica(); - m_handle = 0; + m_handle = AUD_Reference<AUD_IHandle>(); } bool KX_SoundActuator::Update(double curtime, bool frame) @@ -159,11 +157,11 @@ bool KX_SoundActuator::Update(double curtime, bool frame) RemoveAllEvents(); - if(!m_sound) + if(m_sound.isNull()) return false; // actual audio device playing state - bool isplaying = AUD_getStatus(m_handle) == AUD_STATUS_PLAYING; + bool isplaying = m_handle.isNull() ? false : (m_handle->getStatus() == AUD_STATUS_PLAYING); if (bNegativeEvent) { @@ -177,7 +175,9 @@ bool KX_SoundActuator::Update(double curtime, bool frame) case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: { // stop immediately - AUD_stop(m_handle); + if(!m_handle.isNull()) + m_handle->stop(); + m_handle = AUD_Reference<AUD_IHandle>(); break; } case KX_SOUNDACT_PLAYEND: @@ -189,7 +189,8 @@ bool KX_SoundActuator::Update(double curtime, bool frame) case KX_SOUNDACT_LOOPBIDIRECTIONAL: { // stop the looping so that the sound stops when it finished - AUD_setLoop(m_handle, 0); + if(!m_handle.isNull()) + m_handle->setLoopCount(0); break; } default: @@ -215,21 +216,35 @@ bool KX_SoundActuator::Update(double curtime, bool frame) play(); } // verify that the sound is still playing - isplaying = AUD_getStatus(m_handle) == AUD_STATUS_PLAYING ? true : false; + isplaying = m_handle.isNull() ? false : (m_handle->getStatus() == AUD_STATUS_PLAYING); if (isplaying) { - if(m_is3d) + AUD_Reference<AUD_I3DHandle> handle3d = AUD_Reference<AUD_I3DHandle>(m_handle); + + if(m_is3d && !handle3d.isNull()) { - KX_GameObject* obj = (KX_GameObject*)this->GetParent(); - float f[4]; - - obj->NodeGetWorldPosition().getValue(f); - AUD_setSourceLocation(m_handle, f); - obj->GetLinearVelocity().getValue(f); - AUD_setSourceVelocity(m_handle, f); - obj->NodeGetWorldOrientation().getRotation().getValue(f); - AUD_setSourceOrientation(m_handle, f); + KX_Camera* cam = KX_GetActiveScene()->GetActiveCamera(); + if (cam) + { + KX_GameObject* obj = (KX_GameObject*)this->GetParent(); + MT_Point3 p; + MT_Matrix3x3 Mo; + AUD_Vector3 v; + float q[4]; + + Mo = cam->NodeGetWorldOrientation().inverse(); + p = (obj->NodeGetWorldPosition() - cam->NodeGetWorldPosition()); + p = Mo * p; + p.getValue(v.get()); + handle3d->setSourceLocation(v); + p = (obj->GetLinearVelocity() - cam->GetLinearVelocity()); + p = Mo * p; + p.getValue(v.get()); + handle3d->setSourceVelocity(v); + (Mo * obj->NodeGetWorldOrientation()).getRotation().getValue(q); + handle3d->setSourceOrientation(AUD_Quaternion(q[3], q[0], q[1], q[2])); + } } result = true; } @@ -241,7 +256,6 @@ bool KX_SoundActuator::Update(double curtime, bool frame) return result; } - #ifdef WITH_PYTHON /* ------------------------------------------------------------------------- */ @@ -290,6 +304,7 @@ PyAttributeDef KX_SoundActuator::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("cone_angle_inner", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), KX_PYATTRIBUTE_RW_FUNCTION("cone_angle_outer", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), KX_PYATTRIBUTE_RW_FUNCTION("cone_volume_outer", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), + KX_PYATTRIBUTE_RW_FUNCTION("sound", KX_SoundActuator, pyattr_get_sound, pyattr_set_sound), KX_PYATTRIBUTE_RW_FUNCTION("time", KX_SoundActuator, pyattr_get_audposition, pyattr_set_audposition), KX_PYATTRIBUTE_RW_FUNCTION("volume", KX_SoundActuator, pyattr_get_gain, pyattr_set_gain), @@ -303,15 +318,18 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, startSound, "startSound()\n" "\tStarts the sound.\n") { - switch(AUD_getStatus(m_handle)) + if(!m_handle.isNull()) { - case AUD_STATUS_PLAYING: - break; - case AUD_STATUS_PAUSED: - AUD_resume(m_handle); - break; - default: - play(); + switch(m_handle->getStatus()) + { + case AUD_STATUS_PLAYING: + break; + case AUD_STATUS_PAUSED: + m_handle->resume(); + break; + default: + play(); + } } Py_RETURN_NONE; } @@ -320,7 +338,8 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, pauseSound, "pauseSound()\n" "\tPauses the sound.\n") { - AUD_pause(m_handle); + if(!m_handle.isNull()) + m_handle->pause(); Py_RETURN_NONE; } @@ -328,7 +347,9 @@ KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, stopSound, "stopSound()\n" "\tStops the sound.\n") { - AUD_stop(m_handle); + if(!m_handle.isNull()) + m_handle->stop(); + m_handle = AUD_Reference<AUD_IHandle>(); Py_RETURN_NONE; } @@ -376,8 +397,8 @@ PyObject* KX_SoundActuator::pyattr_get_audposition(void *self, const struct KX_P KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); float position = 0.0; - if(actuator->m_handle) - position = AUD_getPosition(actuator->m_handle); + if(!actuator->m_handle.isNull()) + position = actuator->m_handle->getPosition(); PyObject* result = PyFloat_FromDouble(position); @@ -404,6 +425,15 @@ PyObject* KX_SoundActuator::pyattr_get_pitch(void *self, const struct KX_PYATTRI return result; } +PyObject* KX_SoundActuator::pyattr_get_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); + if(!actuator->m_sound.isNull()) + return AUD_getPythonFactory(&actuator->m_sound); + else + Py_RETURN_NONE; +} + int KX_SoundActuator::pyattr_set_3d_property(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); @@ -413,49 +443,50 @@ int KX_SoundActuator::pyattr_set_3d_property(void *self, const struct KX_PYATTRI if (!PyArg_Parse(value, "f", &prop_value)) return PY_SET_ATTR_FAIL; + AUD_Reference<AUD_I3DHandle> handle3d = AUD_Reference<AUD_I3DHandle>(actuator->m_handle); // if sound is working and 3D, set the new setting if(!actuator->m_is3d) return PY_SET_ATTR_FAIL; if(!strcmp(prop, "volume_maximum")) { actuator->m_3d.max_gain = prop_value; - if(actuator->m_handle) - AUD_setVolumeMaximum(actuator->m_handle, prop_value); + if(!handle3d.isNull()) + handle3d->setVolumeMaximum(prop_value); } else if (!strcmp(prop, "volume_minimum")) { actuator->m_3d.min_gain = prop_value; - if(actuator->m_handle) - AUD_setVolumeMinimum(actuator->m_handle, prop_value); + if(!handle3d.isNull()) + handle3d->setVolumeMinimum(prop_value); } else if (!strcmp(prop, "distance_reference")) { actuator->m_3d.reference_distance = prop_value; - if(actuator->m_handle) - AUD_setDistanceReference(actuator->m_handle, prop_value); + if(!handle3d.isNull()) + handle3d->setDistanceReference(prop_value); } else if (!strcmp(prop, "distance_maximum")) { actuator->m_3d.max_distance = prop_value; - if(actuator->m_handle) - AUD_setDistanceMaximum(actuator->m_handle, prop_value); + if(!handle3d.isNull()) + handle3d->setDistanceMaximum(prop_value); } else if (!strcmp(prop, "attenuation")) { actuator->m_3d.rolloff_factor = prop_value; - if(actuator->m_handle) - AUD_setAttenuation(actuator->m_handle, prop_value); + if(!handle3d.isNull()) + handle3d->setAttenuation(prop_value); } else if (!!strcmp(prop, "cone_angle_inner")) { actuator->m_3d.cone_inner_angle = prop_value; - if(actuator->m_handle) - AUD_setConeAngleInner(actuator->m_handle, prop_value); + if(!handle3d.isNull()) + handle3d->setConeAngleInner(prop_value); } else if (!strcmp(prop, "cone_angle_outer")) { actuator->m_3d.cone_outer_angle = prop_value; - if(actuator->m_handle) - AUD_setConeAngleOuter(actuator->m_handle, prop_value); + if(!handle3d.isNull()) + handle3d->setConeAngleOuter(prop_value); } else if (!strcmp(prop, "cone_volume_outer")) { actuator->m_3d.cone_outer_gain = prop_value; - if(actuator->m_handle) - AUD_setConeVolumeOuter(actuator->m_handle, prop_value); + if(!handle3d.isNull()) + handle3d->setConeVolumeOuter(prop_value); } else { return PY_SET_ATTR_FAIL; @@ -472,8 +503,8 @@ int KX_SoundActuator::pyattr_set_audposition(void *self, const struct KX_PYATTRI if (!PyArg_Parse(value, "f", &position)) return PY_SET_ATTR_FAIL; - if(actuator->m_handle) - AUD_seek(actuator->m_handle, position); + if(!actuator->m_handle.isNull()) + actuator->m_handle->seek(position); return PY_SET_ATTR_SUCCESS; } @@ -485,8 +516,8 @@ int KX_SoundActuator::pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DE return PY_SET_ATTR_FAIL; actuator->m_volume = gain; - if(actuator->m_handle) - AUD_setSoundVolume(actuator->m_handle, gain); + if(!actuator->m_handle.isNull()) + actuator->m_handle->setVolume(gain); return PY_SET_ATTR_SUCCESS; } @@ -499,10 +530,28 @@ int KX_SoundActuator::pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_D return PY_SET_ATTR_FAIL; actuator->m_pitch = pitch; - if(actuator->m_handle) - AUD_setSoundPitch(actuator->m_handle, pitch); + if(!actuator->m_handle.isNull()) + actuator->m_handle->setPitch(pitch); return PY_SET_ATTR_SUCCESS; } +int KX_SoundActuator::pyattr_set_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + PyObject* sound = NULL; + KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self); + if (!PyArg_Parse(value, "O", &sound)) + return PY_SET_ATTR_FAIL; + + AUD_Reference<AUD_IFactory>* snd = reinterpret_cast<AUD_Reference<AUD_IFactory>*>(AUD_getPythonSound(sound)); + if(snd) + { + actuator->m_sound = *snd; + delete snd; + return PY_SET_ATTR_SUCCESS; + } + + return PY_SET_ATTR_FAIL; +} + #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_SoundActuator.h b/source/gameengine/Ketsji/KX_SoundActuator.h index eb6717f78f0..b1161e0cad2 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.h +++ b/source/gameengine/Ketsji/KX_SoundActuator.h @@ -38,6 +38,9 @@ #ifdef WITH_AUDASPACE # include "AUD_C-API.h" +# include "AUD_Reference.h" +# include "AUD_IFactory.h" +# include "AUD_IHandle.h" #endif #include "BKE_sound.h" @@ -56,14 +59,14 @@ typedef struct KX_3DSoundSettings class KX_SoundActuator : public SCA_IActuator { - Py_Header; - bool m_isplaying; - AUD_Sound* m_sound; + Py_Header; + bool m_isplaying; + AUD_Reference<AUD_IFactory> m_sound; float m_volume; float m_pitch; bool m_is3d; KX_3DSoundSettings m_3d; - AUD_Channel* m_handle; + AUD_Reference<AUD_IHandle> m_handle; void play(); @@ -84,7 +87,7 @@ public: KX_SOUNDACT_TYPE m_type; KX_SoundActuator(SCA_IObject* gameobj, - AUD_Sound* sound, + AUD_Reference<AUD_IFactory> sound, float volume, float pitch, bool is3d, @@ -113,12 +116,14 @@ public: static int pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static int pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static int pyattr_set_type(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_3d_property(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_audposition(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_type(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript index 62caa602c23..c5509dd7de8 100644 --- a/source/gameengine/Ketsji/SConscript +++ b/source/gameengine/Ketsji/SConscript @@ -11,11 +11,11 @@ incs += ' #source/blender/python/mathutils' # Only for mathutils, be very carefu incs += ' #intern/string #intern/guardedalloc #intern/container' incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer' -incs += ' #intern/audaspace/intern #source/gameengine/Converter' +incs += ' #intern/audaspace/intern #intern/audaspace/FX #source/gameengine/Converter' incs += ' #source/gameengine/BlenderRoutines #source/blender/imbuf #intern/moto/include' incs += ' #source/gameengine/Ketsji #source/gameengine/Ketsji/KXNetwork #source/blender/blenlib #source/blender/blenfont' incs += ' #source/blender/blenkernel #source/blender #source/blender/editors/include' -incs += ' #source/blender/makesdna #source/blender/python #source/gameengine/Rasterizer' +incs += ' #source/blender/makesdna #source/blender/makesrna #source/blender/python #source/gameengine/Rasterizer' incs += ' #source/gameengine/GameLogic #source/gameengine/Expressions #source/gameengine/Network' incs += ' #source/gameengine/SceneGraph #source/gameengine/Physics/common' incs += ' #source/gameengine/Physics/Dummy' @@ -35,7 +35,7 @@ if env['WITH_BF_PYTHON']: if env['WITH_BF_FFMPEG']: defs.append('WITH_FFMPEG') - + if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'): if env['BF_DEBUG']: defs.append('_DEBUG') # for Python diff --git a/source/gameengine/SceneGraph/SG_IObject.cpp b/source/gameengine/SceneGraph/SG_IObject.cpp index 3064e6662b9..b22d210984d 100644 --- a/source/gameengine/SceneGraph/SG_IObject.cpp +++ b/source/gameengine/SceneGraph/SG_IObject.cpp @@ -34,6 +34,8 @@ #include "SG_IObject.h" #include "SG_Controller.h" +#include <algorithm> + SG_Stage gSG_Stage = SG_STAGE_UNKNOWN; SG_IObject:: @@ -71,6 +73,16 @@ AddSGController( void SG_IObject:: +RemoveSGController( + SG_Controller* cont +) { + SGControllerList::iterator contit; + + m_SGcontrollers.erase(std::remove(m_SGcontrollers.begin(), m_SGcontrollers.end(), cont)); +} + + void +SG_IObject:: RemoveAllControllers( ) { m_SGcontrollers.clear(); diff --git a/source/gameengine/SceneGraph/SG_IObject.h b/source/gameengine/SceneGraph/SG_IObject.h index 26e317bdcd9..c42935bc487 100644 --- a/source/gameengine/SceneGraph/SG_IObject.h +++ b/source/gameengine/SceneGraph/SG_IObject.h @@ -49,6 +49,7 @@ enum SG_Stage SG_STAGE_CONTROLLER_UPDATE, SG_STAGE_ACTUATOR, SG_STAGE_ACTUATOR_UPDATE, + SG_STAGE_ANIMATION_UPDATE, SG_STAGE_PHYSICS2, SG_STAGE_PHYSICS2_UPDATE, SG_STAGE_SCENE, @@ -180,6 +181,16 @@ public: SG_Controller* cont ); + /** + * Remove a pointer to a controller from this node. + * This does not delete the controller itself! Be careful to + * avoid memory leaks. + */ + void + RemoveSGController( + SG_Controller* cont + ); + /** * Clear the array of pointers to controllers associated with * this node. This does not delete the controllers themselves! |