void SCA_ExpressionController::Trigger(SCA_LogicManager* logicmgr) { bool expressionresult = false; if (!m_exprCache) { CParser parser; parser.SetContext(this->AddRef()); m_exprCache = parser.ProcessText(m_exprText); } if (m_exprCache) { CValue* value = m_exprCache->Calculate(); if (value) { if (value->IsError()) { printf("%s\n", value->GetText().ReadPtr()); } else { float num = (float)value->GetNumber(); expressionresult = !MT_fuzzyZero(num); } value->Release(); } } for (vector<SCA_IActuator*>::const_iterator i=m_linkedactuators.begin(); !(i==m_linkedactuators.end());i++) { SCA_IActuator* actua = *i; logicmgr->AddActiveActuator(actua,expressionresult); } }
float CValue::GetPropertyNumber(const STR_String& inName,float defnumber) { CValue *property = GetProperty(inName); if (property) return property->GetNumber(); else return defnumber; }
bool SCA_PropertyActuator::Update() { bool result = false; bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); if (bNegativeEvent) return false; // do nothing on negative events CValue* propowner = GetParent(); CParser parser; parser.SetContext( propowner->AddRef()); CExpression* userexpr= NULL; if (m_type==KX_ACT_PROP_TOGGLE) { /* dont use */ CValue* newval; CValue* oldprop = propowner->GetProperty(m_propname); if (oldprop) { newval = new CBoolValue((oldprop->GetNumber()==0.0) ? true:false); oldprop->SetValue(newval); } else { /* as not been assigned, evaluate as false, so assign true */ newval = new CBoolValue(true); propowner->SetProperty(m_propname,newval); } newval->Release(); } else if ((userexpr = parser.ProcessText(m_exprtxt))) { switch (m_type) { case KX_ACT_PROP_ASSIGN: { CValue* newval = userexpr->Calculate(); CValue* oldprop = propowner->GetProperty(m_propname); if (oldprop) { oldprop->SetValue(newval); } else { propowner->SetProperty(m_propname,newval); } newval->Release(); break; } case KX_ACT_PROP_ADD: { CValue* oldprop = propowner->GetProperty(m_propname); if (oldprop) { // int waarde = (int)oldprop->GetNumber(); /*unused*/ CExpression* expr = new COperator2Expr(VALUE_ADD_OPERATOR,new CConstExpr(oldprop->AddRef()), userexpr->AddRef()); CValue* newprop = expr->Calculate(); oldprop->SetValue(newprop); newprop->Release(); expr->Release(); } break; } case KX_ACT_PROP_COPY: { if (m_sourceObj) { CValue* copyprop = m_sourceObj->GetProperty(m_exprtxt); if (copyprop) { CValue *val = copyprop->GetReplica(); GetParent()->SetProperty( m_propname, val); val->Release(); } } break; } /* case KX_ACT_PROP_TOGGLE: */ /* accounted for above, no need for userexpr */ default: { } } userexpr->Release(); } return result; }
bool BL_ActionActuator::Update(double curtime, bool frame) { 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) { 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) { start = m_endframe; end = m_startframe; } break; case ACT_ACTION_FROM_PROP: CValue* prop = GetParent()->GetProperty(m_propname); // If we don't have a property, we can't do anything, so just bail if (!prop) return false; playtype = BL_Action::ACT_MODE_PLAY; start = end = prop->GetNumber(); break; } if (m_flag & ACT_FLAG_CONTINUE) bUseContinue = true; // Handle events if (frame) { bNegativeEvent = m_negevent; bPositiveEvent = m_posevent; RemoveAllEvents(); } // "Active" actions need to keep updating their current frame if (bUseContinue && (m_flag & ACT_FLAG_ACTIVE)) m_localtime = obj->GetActionFrame(m_layer); if (m_flag & ACT_FLAG_ATTEMPT_PLAY) SetLocalTime(curtime); else ResetStartTime(curtime); // 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 obj->SetProperty(m_framepropname, newval); newval->Release(); } // Handle a finished animation if ((m_flag & ACT_FLAG_PLAY_END) && (m_flag & ACT_FLAG_ACTIVE) && obj->IsActionDone(m_layer)) { m_flag &= ~ACT_FLAG_ACTIVE; m_flag &= ~ACT_FLAG_ATTEMPT_PLAY; if (m_playtype == ACT_ACTION_PINGPONG) m_flag ^= ACT_FLAG_REVERSE; return false; } // If a different action is playing, we've been overruled and are no longer active if (obj->GetCurrentAction(m_layer) != m_action && !obj->IsActionDone(m_layer)) m_flag &= ~ACT_FLAG_ACTIVE; if (bPositiveEvent || (m_flag & ACT_FLAG_ATTEMPT_PLAY && !(m_flag & ACT_FLAG_ACTIVE))) { if (bPositiveEvent && m_playtype == ACT_ACTION_PLAY) { if (obj->IsActionDone(m_layer)) m_localtime = start; ResetStartTime(curtime); } if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, playtype, m_layer_weight, m_ipo_flags)) { m_flag |= ACT_FLAG_ACTIVE; if (bUseContinue) obj->SetActionFrame(m_layer, m_localtime); if (m_playtype == ACT_ACTION_PLAY || m_playtype == ACT_ACTION_PINGPONG) m_flag |= ACT_FLAG_PLAY_END; else m_flag &= ~ACT_FLAG_PLAY_END; } m_flag |= ACT_FLAG_ATTEMPT_PLAY; } else if ((m_flag & ACT_FLAG_ACTIVE) && bNegativeEvent) { m_flag &= ~ACT_FLAG_ATTEMPT_PLAY; m_localtime = obj->GetActionFrame(m_layer); bAction *curr_action = obj->GetCurrentAction(m_layer); if (curr_action && curr_action != m_action) { // 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; } 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_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; } } return m_flag & ACT_FLAG_ACTIVE; }
bool SCA_PropertySensor::CheckPropertyCondition() { m_recentresult=false; bool result=false; bool reverse = false; switch (m_checktype) { case KX_PROPSENSOR_NOTEQUAL: reverse = true; /* fall-through */ case KX_PROPSENSOR_EQUAL: { CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { const std::string& testprop = orgprop->GetText(); // Force strings to upper case, to avoid confusion in // bool tests. It's stupid the prop's identity is lost // on the way here... if ((testprop == CBoolValue::sTrueString) || (testprop == CBoolValue::sFalseString)) { boost::to_upper(m_checkpropval); } result = (testprop == m_checkpropval); /* Patch: floating point values cant use strings usefully since you can have "0.0" == "0.0000" * this could be made into a generic Value class function for comparing values with a string. */ if (result==false && (orgprop->GetValueType() == VALUE_FLOAT_TYPE)) { float f = std::stof(m_checkpropval); result = (f == ((CFloatValue *)orgprop)->GetFloat()); } /* end patch */ } orgprop->Release(); if (reverse) result = !result; break; } case KX_PROPSENSOR_EXPRESSION: { break; } case KX_PROPSENSOR_INTERVAL: { CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { const float min = std::stof(m_checkpropval); const float max = std::stof(m_checkpropmaxval); float val; if (orgprop->GetValueType() == VALUE_STRING_TYPE) { val = std::stof(orgprop->GetText()); } else { val = orgprop->GetNumber(); } result = (min <= val) && (val <= max); } orgprop->Release(); break; } case KX_PROPSENSOR_CHANGED: { CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { if (m_previoustext != orgprop->GetText()) { m_previoustext = orgprop->GetText(); result = true; } } orgprop->Release(); break; } case KX_PROPSENSOR_LESSTHAN: reverse = true; /* fall-through */ case KX_PROPSENSOR_GREATERTHAN: { CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { const float ref = std::stof(m_checkpropval); float val; if (orgprop->GetValueType() == VALUE_STRING_TYPE) { val = std::stof(orgprop->GetText()); } else { val = orgprop->GetNumber(); } if (reverse) { result = val < ref; } else { result = val > ref; } } orgprop->Release(); break; } default: ; /* error */ } //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED //see Game Engine bugtracker [ #3809 ] m_recentresult = result; return result; }
bool BL_ShapeActionActuator::Update(double curtime, bool frame) { bool bNegativeEvent = false; bool bPositiveEvent = false; bool keepgoing = true; bool wrap = false; bool apply=true; int priority; float newweight; curtime -= KX_KetsjiEngine::GetSuspendedDelta(); // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! if (frame) { bNegativeEvent = m_negevent; bPositiveEvent = m_posevent; RemoveAllEvents(); if (bPositiveEvent) m_flag |= ACT_FLAG_ACTIVE; if (bNegativeEvent) { if (!(m_flag & ACT_FLAG_ACTIVE)) return false; m_flag &= ~ACT_FLAG_ACTIVE; } } /* This action can only be attached to a deform object */ BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent(); float length = m_endframe - m_startframe; priority = m_priority; /* Determine pre-incrementation behaviour and set appropriate flags */ switch (m_playtype){ case ACT_ACTION_MOTION: if (bNegativeEvent){ keepgoing=false; apply=false; }; break; case ACT_ACTION_FROM_PROP: if (bNegativeEvent){ apply=false; keepgoing=false; } break; case ACT_ACTION_LOOP_END: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_KEYUP; m_flag &= ~ACT_FLAG_REVERSE; m_flag |= ACT_FLAG_LOCKINPUT; m_localtime = m_startframe; m_starttime = curtime; } } if (bNegativeEvent){ m_flag |= ACT_FLAG_KEYUP; } break; case ACT_ACTION_LOOP_STOP: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_flag &= ~ACT_FLAG_KEYUP; m_flag |= ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } } if (bNegativeEvent){ m_flag |= ACT_FLAG_KEYUP; m_flag &= ~ACT_FLAG_LOCKINPUT; keepgoing=false; apply=false; } break; case ACT_ACTION_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); } } /* Check if a wrapping response is needed */ if (length){ if (m_localtime < m_startframe || m_localtime > m_endframe) { m_localtime = m_startframe + fmod(m_localtime, length); wrap = true; } } else m_localtime = m_startframe; /* Perform post-increment tasks */ switch (m_playtype){ case ACT_ACTION_FROM_PROP: { CValue* propval = GetParent()->GetProperty(m_propname); if (propval) m_localtime = propval->GetNumber(); if (bNegativeEvent){ keepgoing=false; } } break; case ACT_ACTION_MOTION: break; case ACT_ACTION_LOOP_STOP: break; case ACT_ACTION_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); } break; case ACT_ACTION_PLAY: if (wrap){ m_localtime = m_endframe; keepgoing = false; m_flag &= ~ACT_FLAG_LOCKINPUT; } break; default: keepgoing = false; break; } /* Set the property if its defined */ if (m_framepropname[0] != '\0') { CValue* propowner = GetParent(); CValue* oldprop = propowner->GetProperty(m_framepropname); CValue* newval = new CFloatValue(m_localtime); if (oldprop) { oldprop->SetValue(newval); } else { propowner->SetProperty(m_framepropname, newval); } newval->Release(); } if (bNegativeEvent) m_blendframe=0.0f; /* Apply the pose if necessary*/ if (apply) { /* Priority test */ if (obj->SetActiveAction(this, priority, curtime)){ 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 // and the new mesh has no key, stop the action keepgoing = false; } else { ListBase tchanbase= {NULL, NULL}; if (m_blendin && m_blendframe==0.0f){ // this is the start of the blending, remember the startup shape obj->GetShape(m_blendshape); m_blendstart = curtime; } 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)) { // no update, this is possible if action does not match the keys, stop the action keepgoing = false; } else { // the key have changed, apply blending if needed if (m_blendin && (m_blendframe<m_blendin)){ newweight = (m_blendframe/(float)m_blendin); BlendShape(key, 1.0f - newweight); /* Increment current blending percentage */ m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate(); if (m_blendframe>m_blendin) m_blendframe = m_blendin; } m_lastUpdate = m_localtime; } BLI_freelistN(&tchanbase); } } else{ m_blendframe = 0.0f; } } if (!keepgoing){ m_blendframe = 0.0f; } return keepgoing; };
bool SCA_KeyboardSensor::Evaluate() { bool result = false; bool reset = m_reset && m_level; bool qual = true; bool qual_change = false; short int m_val_orig = m_val; SCA_IInputDevice* inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); // cerr << "SCA_KeyboardSensor::Eval event, sensing for "<< m_hotkey << " at device " << inputdev << "\n"; /* See if we need to do logging: togPropState exists and is * different from 0 */ CValue* myparent = GetParent(); CValue* togPropState = myparent->GetProperty(m_toggleprop); if (togPropState && (((int)togPropState->GetNumber()) != 0) ) { LogKeystrokes(); } m_reset = false; /* Now see whether events must be bounced. */ if (m_bAllKeys) { bool justactivated = false; bool justreleased = false; bool active = false; for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++) { const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); switch (inevent.m_status) { case SCA_InputEvent::KX_JUSTACTIVATED: justactivated = true; break; case SCA_InputEvent::KX_JUSTRELEASED: justreleased = true; break; case SCA_InputEvent::KX_ACTIVE: active = true; break; case SCA_InputEvent::KX_NO_INPUTSTATUS: /* do nothing */ break; } } if (justactivated) { m_val=1; result = true; } else { if (justreleased) { m_val=(active)?1:0; result = true; } else { if (active) { if (m_val == 0) { m_val = 1; if (m_level) { result = true; } } } else { if (m_val == 1) { m_val = 0; result = true; } } } if (m_tap) // special case for tap mode: only generate event for new activation result = false; } } else { // cerr << "======= SCA_KeyboardSensor::Evaluate:: peeking at key status" << endl; const SCA_InputEvent & inevent = inputdev->GetEventValue( (SCA_IInputDevice::KX_EnumInputs) m_hotkey); // cerr << "======= SCA_KeyboardSensor::Evaluate:: status: " << inevent.m_status << endl; /* Check qualifier keys * - see if the qualifiers we request are pressed - 'qual' true/false * - see if the qualifiers we request changed their state - 'qual_change' true/false */ if (m_qual > 0) { const SCA_InputEvent & qualevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) m_qual); switch (qualevent.m_status) { case SCA_InputEvent::KX_NO_INPUTSTATUS: qual = false; break; case SCA_InputEvent::KX_JUSTRELEASED: qual_change = true; qual = false; break; case SCA_InputEvent::KX_JUSTACTIVATED: qual_change = true; case SCA_InputEvent::KX_ACTIVE: /* do nothing */ break; } } if (m_qual2 > 0 && qual==true) { const SCA_InputEvent & qualevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) m_qual2); /* copy of above */ switch (qualevent.m_status) { case SCA_InputEvent::KX_NO_INPUTSTATUS: qual = false; break; case SCA_InputEvent::KX_JUSTRELEASED: qual_change = true; qual = false; break; case SCA_InputEvent::KX_JUSTACTIVATED: qual_change = true; case SCA_InputEvent::KX_ACTIVE: /* do nothing */ break; } } /* done reading qualifiers */ if (inevent.m_status == SCA_InputEvent::KX_NO_INPUTSTATUS) { if (m_val == 1) { // this situation may occur after a scene suspend: the keyboard release // event was not captured, produce now the event off m_val = 0; result = true; } } else { if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED) { m_val=1; result = true; } else { if (inevent.m_status == SCA_InputEvent::KX_JUSTRELEASED) { m_val = 0; result = true; } else { if (inevent.m_status == SCA_InputEvent::KX_ACTIVE) { if (m_val == 0) { m_val = 1; if (m_level) { result = true; } } } } } } /* Modify the key state based on qual(s) * Tested carefully. don't touch unless your really sure. * note, this will only change the results if key modifiers are set. * * When all modifiers and keys are positive * - pulse true * * When ANY of the modifiers or main key become inactive, * - pulse false */ if (qual==false) { /* one of the qualifiers are not pressed */ if (m_val_orig && qual_change) { /* we were originally enabled, but a qualifier changed */ result = true; } else { result = false; } m_val = 0; /* since one of the qualifiers is not on, set the state to false */ } else { /* we done have any qualifiers or they are all pressed */ if (m_val && qual_change) { /* the main key state is true and our qualifier just changed */ result = true; } } /* done with key quals */ } if (reset) // force an event result = true; return result; }
bool KX_IpoActuator::Update(double curtime, bool frame) { // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! bool bNegativeEvent = false; bool numevents = false; bool bIpoStart = false; curtime -= KX_KetsjiEngine::GetSuspendedDelta(); if (frame) { numevents = m_posevent || m_negevent; bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); } float start_smaller_then_end = ( m_startframe < m_endframe ? 1.0f : -1.0f); bool result=true; if (!bNegativeEvent) { if (m_starttime < -2.0f*fabs(m_endframe - m_startframe)) { // start for all Ipo, initial start for LOOP_STOP m_starttime = curtime; m_bIpoPlaying = true; bIpoStart = true; } } switch ((IpoActType)m_type) { case KX_ACT_IPO_PLAY: { // Check if playing forwards. result = ! finished if (start_smaller_then_end > 0.f) result = (m_localtime < m_endframe && m_bIpoPlaying); else result = (m_localtime > m_endframe && m_bIpoPlaying); if (result) { SetLocalTime(curtime); /* Perform clamping */ ClampLocalTime(); if (bIpoStart) ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); } else { m_localtime=m_startframe; m_direction=1; } break; } case KX_ACT_IPO_PINGPONG: { result = true; if (bNegativeEvent && !m_bIpoPlaying) result = false; else SetLocalTime(curtime); if (ClampLocalTime()) { result = false; m_direction = -m_direction; } if (bIpoStart && m_direction > 0) ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); break; } case KX_ACT_IPO_FLIPPER: { if (bNegativeEvent && !m_bIpoPlaying) result = false; if (numevents) { float oldDirection = m_direction; if (bNegativeEvent) m_direction = -1; else m_direction = 1; if (m_direction != oldDirection) // changing direction, reset start time SetStartTime(curtime); } SetLocalTime(curtime); if (ClampLocalTime() && m_localtime == m_startframe) result = false; if (bIpoStart) ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); break; } case KX_ACT_IPO_LOOPSTOP: { if (numevents) { if (bNegativeEvent) { result = false; m_bNegativeEvent = false; numevents = false; } if (!m_bIpoPlaying) { // Ipo was stopped, make sure we will restart from where it stopped SetStartTime(curtime); if (!bNegativeEvent) // positive signal will restart the Ipo m_bIpoPlaying = true; } } // fall through to loopend, and quit the ipo animation immediatly } case KX_ACT_IPO_LOOPEND: { if (numevents) { if (bNegativeEvent && m_bIpoPlaying) { m_bNegativeEvent = true; } } if (bNegativeEvent && !m_bIpoPlaying) { result = false; } else { if (m_localtime*start_smaller_then_end < m_endframe*start_smaller_then_end) { SetLocalTime(curtime); } else { if (!m_bNegativeEvent) { /* Perform wraparound */ SetLocalTime(curtime); if (start_smaller_then_end > 0.f) m_localtime = m_startframe + fmod(m_localtime - m_startframe, m_endframe - m_startframe); else m_localtime = m_startframe - fmod(m_startframe - m_localtime, m_startframe - m_endframe); SetStartTime(curtime); bIpoStart = true; } else { /* Perform clamping */ m_localtime=m_endframe; result = false; m_bNegativeEvent = false; } } } if (m_bIpoPlaying && bIpoStart) ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); break; } case KX_ACT_IPO_KEY2KEY: { // not implemented yet result = false; break; } case KX_ACT_IPO_FROM_PROP: { result = !bNegativeEvent; CValue* propval = GetParent()->GetProperty(m_propname); if (propval) { m_localtime = propval->GetNumber(); if (bIpoStart) ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local); ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse); } else { result = false; } break; } default: result = false; } /* Set the property if its defined */ if (m_framepropname[0] != '\0') { CValue* propowner = GetParent(); CValue* oldprop = propowner->GetProperty(m_framepropname); CValue* newval = new CFloatValue(m_localtime); if (oldprop) { oldprop->SetValue(newval); } else { propowner->SetProperty(m_framepropname, newval); } newval->Release(); } if (!result) { if (m_type != KX_ACT_IPO_LOOPSTOP) this->ResetStartTime(); m_bIpoPlaying = false; } return result; }
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; curtime -= KX_KetsjiEngine::GetSuspendedDelta(); // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! if (frame) { 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_FLIPPER: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_flag |= ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } } else if (bNegativeEvent){ m_flag |= ACT_FLAG_REVERSE; m_flag &= ~ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } break; case ACT_ACTION_PLAY: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_localtime = m_starttime; m_starttime = curtime; m_flag |= ACT_FLAG_LOCKINPUT; } } break; default: break; } /* Perform increment */ if (keepgoing){ if (m_playtype == ACT_ACTION_MOTION){ MT_Point3 newpos; MT_Point3 deltapos; newpos = obj->NodeGetWorldPosition(); /* Find displacement */ deltapos = newpos-m_lastpos; m_localtime += (length/m_stridelength) * deltapos.length(); m_lastpos = newpos; } else{ SetLocalTime(curtime); } } /* Check if a wrapping response is needed */ if (length){ if (m_localtime < m_startframe || m_localtime > m_endframe) { m_localtime = m_startframe + fmod(m_localtime, length); wrap = true; } } else m_localtime = m_startframe; /* Perform post-increment tasks */ switch (m_playtype){ case ACT_ACTION_FROM_PROP: { CValue* propval = GetParent()->GetProperty(m_propname); if (propval) m_localtime = propval->GetNumber(); if (bNegativeEvent){ keepgoing=false; } } break; case ACT_ACTION_MOTION: break; case ACT_ACTION_LOOP_STOP: break; case ACT_ACTION_FLIPPER: if (wrap){ if (!(m_flag & ACT_FLAG_REVERSE)){ m_localtime=m_endframe; //keepgoing = false; } else { m_localtime=m_startframe; keepgoing = false; } } break; case ACT_ACTION_LOOP_END: if (wrap){ if (m_flag & ACT_FLAG_KEYUP){ keepgoing = false; m_localtime = m_endframe; m_flag &= ~ACT_FLAG_LOCKINPUT; } SetStartTime(curtime); } break; case ACT_ACTION_PLAY: if (wrap){ m_localtime = m_endframe; keepgoing = false; m_flag &= ~ACT_FLAG_LOCKINPUT; } break; default: keepgoing = false; break; } /* Set the property if its defined */ if (m_framepropname[0] != '\0') { CValue* propowner = GetParent(); CValue* oldprop = propowner->GetProperty(m_framepropname); CValue* newval = new CFloatValue(m_localtime); if (oldprop) { oldprop->SetValue(newval); } else { propowner->SetProperty(m_framepropname, newval); } newval->Release(); } if (bNegativeEvent) m_blendframe=0.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((Scene *)obj->GetScene(), 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; } return keepgoing; };
bool SCA_KeyboardSensor::Evaluate() { bool result = false; bool reset = m_reset && m_level; SCA_IInputDevice* inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); // cerr << "SCA_KeyboardSensor::Eval event, sensing for "<< m_hotkey << " at device " << inputdev << "\n"; /* See if we need to do logging: togPropState exists and is * different from 0 */ CValue* myparent = GetParent(); CValue* togPropState = myparent->GetProperty(m_toggleprop); if (togPropState && (((int)togPropState->GetNumber()) != 0) ) { LogKeystrokes(); } m_reset = false; /* Now see whether events must be bounced. */ if (m_bAllKeys) { bool status = false; bool events = false; for (int i = SCA_IInputDevice::BEGINKEY; i <= SCA_IInputDevice::ENDKEY; ++i) { const SCA_InputEvent& input = inputdev->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); if (input.End(SCA_InputEvent::ACTIVE)) { status = true; break; } } for (int i = SCA_IInputDevice::BEGINKEY; i <= SCA_IInputDevice::ENDKEY; ++i) { const SCA_InputEvent& input = inputdev->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); if (input.m_queue.size() > 0) { events = true; break; } } m_val = status; result = events; } else { bool status[3] = {false, false, false}; bool events[3] = {false, false, false}; const SCA_InputEvent & input = inputdev->GetInput((SCA_IInputDevice::SCA_EnumInputs) m_hotkey); /* Check qualifier keys * - see if the qualifiers we request are pressed - 'qual' true/false * - see if the qualifiers we request changed their state - 'qual_change' true/false */ if (m_qual > 0) { const SCA_InputEvent & qualevent = inputdev->GetInput((SCA_IInputDevice::SCA_EnumInputs) m_qual); status[1] = qualevent.End(SCA_InputEvent::ACTIVE); events[1] = (qualevent.m_queue.size() > 0); } if (m_qual2 > 0) { const SCA_InputEvent & qualevent = inputdev->GetInput((SCA_IInputDevice::SCA_EnumInputs) m_qual2); /* copy of above */ status[2] = qualevent.End(SCA_InputEvent::ACTIVE); events[2] = (qualevent.m_queue.size() > 0); } /* done reading qualifiers */ status[0] = input.End(SCA_InputEvent::ACTIVE); events[0] = (input.m_queue.size() > 0); /* Modify the key state based on qual(s) * Tested carefully. don't touch unless your really sure. * note, this will only change the results if key modifiers are set. * * When all modifiers and keys are positive * - pulse true * * When ANY of the modifiers or main key become inactive, * - pulse false */ // One of the third keys value from last logic frame changed. if (events[0] || events[1] || events[2]) { result = true; } if (!status[0] || (m_qual > 0 && !status[0]) || (m_qual2 > 0 && !status[1])) { /* one of the used qualifiers are not pressed */ m_val = false; /* since one of the qualifiers is not on, set the state to false */ } else { m_val = true; } /* done with key quals */ } if (reset) // force an event result = true; return result; }