/* drivers support/hacks * - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render * - these are always run since the depsgraph can't handle non-object data * - these happen after objects are all done so that we can read in their final transform values, * though this means that objects can't refer to scene info for guidance... */ static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene) { float ctime = BKE_scene_frame_get(scene); /* scene itself */ if (scene->adt && scene->adt->drivers.first) { BKE_animsys_evaluate_animdata(scene, &scene->id, scene->adt, ctime, ADT_RECALC_DRIVERS); } /* world */ /* TODO: what about world textures? but then those have nodes too... */ if (scene->world) { ID *wid = (ID *)scene->world; AnimData *adt = BKE_animdata_from_id(wid); if (adt && adt->drivers.first) BKE_animsys_evaluate_animdata(scene, wid, adt, ctime, ADT_RECALC_DRIVERS); } /* nodes */ if (scene->nodetree) { ID *nid = (ID *)scene->nodetree; AnimData *adt = BKE_animdata_from_id(nid); if (adt && adt->drivers.first) BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS); } }
/* drivers support/hacks * - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render * - these are always run since the depsgraph can't handle non-object data * - these happen after objects are all done so that we can read in their final transform values, * though this means that objects can't refer to scene info for guidance... */ static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene) { SceneRenderLayer *srl; float ctime = BKE_scene_frame_get(scene); /* scene itself */ if (scene->adt && scene->adt->drivers.first) { BKE_animsys_evaluate_animdata(scene, &scene->id, scene->adt, ctime, ADT_RECALC_DRIVERS); } /* world */ /* TODO: what about world textures? but then those have nodes too... */ if (scene->world) { ID *wid = (ID *)scene->world; AnimData *adt = BKE_animdata_from_id(wid); if (adt && adt->drivers.first) BKE_animsys_evaluate_animdata(scene, wid, adt, ctime, ADT_RECALC_DRIVERS); } /* nodes */ if (scene->nodetree) { ID *nid = (ID *)scene->nodetree; AnimData *adt = BKE_animdata_from_id(nid); if (adt && adt->drivers.first) BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS); } /* world nodes */ if (scene->world && scene->world->nodetree) { ID *nid = (ID *)scene->world->nodetree; AnimData *adt = BKE_animdata_from_id(nid); if (adt && adt->drivers.first) BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS); } /* freestyle */ for (srl = scene->r.layers.first; srl; srl = srl->next) { FreestyleConfig *config = &srl->freestyleConfig; FreestyleLineSet *lineset; for (lineset = config->linesets.first; lineset; lineset = lineset->next) { if (lineset->linestyle) { ID *lid = &lineset->linestyle->id; AnimData *adt = BKE_animdata_from_id(lid); if (adt && adt->drivers.first) BKE_animsys_evaluate_animdata(scene, lid, adt, ctime, ADT_RECALC_DRIVERS); } } } }
void AnimationExporter::calc_ob_mat_at_time(Object *ob, float ctime , float mat[][4]) { ListBase *conlist = get_active_constraints(ob); bConstraint *con; for (con = (bConstraint *)conlist->first; con; con = con->next) { ListBase targets = {NULL, NULL}; bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); if (cti && cti->get_constraint_targets) { bConstraintTarget *ct; Object *obtar; cti->get_constraint_targets(con, &targets); for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) { obtar = ct->tar; if (obtar) { BKE_animsys_evaluate_animdata(scene, &obtar->id, obtar->adt, ctime, ADT_RECALC_ANIM); BKE_object_where_is_calc_time(scene, obtar, ctime); } } if (cti->flush_constraint_targets) cti->flush_constraint_targets(con, &targets, 1); } } BKE_object_where_is_calc_time(scene, ob, ctime); copy_m4_m4(mat, ob->obmat); }
/* For the calculation of the effects of an Action at the given frame on an object * This is currently only used for the Action Constraint */ void what_does_obaction (Object *ob, Object *workob, bPose *pose, bAction *act, char groupname[], float cframe) { bActionGroup *agrp= action_groups_find_named(act, groupname); /* clear workob */ clear_workob(workob); /* init workob */ copy_m4_m4(workob->obmat, ob->obmat); copy_m4_m4(workob->parentinv, ob->parentinv); copy_m4_m4(workob->constinv, ob->constinv); workob->parent= ob->parent; workob->rotmode= ob->rotmode; workob->trackflag= ob->trackflag; workob->upflag= ob->upflag; workob->partype= ob->partype; workob->par1= ob->par1; workob->par2= ob->par2; workob->par3= ob->par3; workob->constraints.first = ob->constraints.first; workob->constraints.last = ob->constraints.last; workob->pose= pose; /* need to set pose too, since this is used for both types of Action Constraint */ BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr)); BLI_strncpy(workob->id.name, "OB<ConstrWorkOb>", sizeof(workob->id.name)); /* we don't use real object name, otherwise RNA screws with the real thing */ /* if we're given a group to use, it's likely to be more efficient (though a bit more dangerous) */ if (agrp) { /* specifically evaluate this group only */ PointerRNA id_ptr; /* get RNA-pointer for the workob's ID */ RNA_id_pointer_create(&workob->id, &id_ptr); /* execute action for this group only */ animsys_evaluate_action_group(&id_ptr, act, agrp, NULL, cframe); } else { AnimData adt= {NULL}; /* init animdata, and attach to workob */ workob->adt= &adt; adt.recalc= ADT_RECALC_ANIM; adt.action= act; /* execute effects of Action on to workob (or it's PoseChannels) */ BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM); } }
static void lamp_node_drivers_update(Scene *scene, bNodeTree *ntree, float ctime) { bNode *node; /* nodetree itself */ if (ntree->adt && ntree->adt->drivers.first) BKE_animsys_evaluate_animdata(scene, &ntree->id, ntree->adt, ctime, ADT_RECALC_DRIVERS); /* nodes */ for (node = ntree->nodes.first; node; node = node->next) if (node->id && node->type == NODE_GROUP) lamp_node_drivers_update(scene, (bNodeTree *)node->id, ctime); }
void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pchan) { bPoseChannel *parchan = NULL; bPose *pose = ob_arm->pose; pchan = BKE_pose_channel_find_name(pose, bone->name); if (!pchan) return; parchan = pchan->parent; enable_fcurves(ob_arm->adt->action, bone->name); std::vector<float>::iterator it; for (it = frames.begin(); it != frames.end(); it++) { float mat[4][4], ipar[4][4]; float ctime = BKE_scene_frame_get_from_ctime(scene, *it); BKE_animsys_evaluate_animdata(scene, &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM); BKE_pose_where_is_bone(scene, ob_arm, pchan, ctime, 1); // compute bone local mat if (bone->parent) { invert_m4_m4(ipar, parchan->pose_mat); mult_m4_m4m4(mat, ipar, pchan->pose_mat); } else copy_m4_m4(mat, pchan->pose_mat); switch (type) { case 0: mat4_to_eul(v, mat); break; case 1: mat4_to_size(v, mat); break; case 2: copy_v3_v3(v, mat[3]); break; } v += 3; } enable_fcurves(ob_arm->adt->action, NULL); }
bool BL_ShapeDeformer::ExecuteShapeDrivers(void) { if (m_useShapeDrivers && PoseUpdated()) { // the shape drivers use the bone matrix as input. Must // update the matrix now m_armobj->ApplyPose(); // 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(); m_bDynamic = true; return true; } return false; }
/* this is called in main loop, doing tagged updates before redraw */ void BKE_scene_update_tagged(Main *bmain, Scene *scene) { Scene *sce_iter; /* keep this first */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE); /* (re-)build dependency graph if needed */ for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) DAG_scene_relations_update(bmain, sce_iter); /* flush recalc flags to dependencies */ DAG_ids_flush_tagged(bmain); /* removed calls to quick_cache, see pointcache.c */ /* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later * when trying to find materials with drivers that need evaluating [#32017] */ tag_main_idcode(bmain, ID_MA, FALSE); tag_main_idcode(bmain, ID_LA, FALSE); /* update all objects: drivers, matrices, displists, etc. flags set * by depgraph or manual, no layer check here, gets correct flushed * * in the future this should handle updates for all datablocks, not * only objects and scenes. - brecht */ scene_update_tagged_recursive(bmain, scene, scene); /* extra call here to recalc scene animation (for sequencer) */ { AnimData *adt = BKE_animdata_from_id(&scene->id); float ctime = BKE_scene_frame_get(scene); if (adt && (adt->recalc & ADT_RECALC_ANIM)) BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, 0); } /* notify editors and python about recalc */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST); DAG_ids_check_recalc(bmain, scene, FALSE); /* clear recalc flags */ DAG_ids_clear_recalc(bmain); }
void lamp_drivers_update(Scene *scene, Lamp *la, float ctime) { /* Prevent infinite recursion by checking (and tagging the lamp) as having been visited already * (see BKE_scene_update_tagged()). This assumes la->id.flag & LIB_DOIT isn't set by anything else * in the meantime... [#32017] */ if (la->id.flag & LIB_DOIT) return; else la->id.flag |= LIB_DOIT; /* lamp itself */ if (la->adt && la->adt->drivers.first) BKE_animsys_evaluate_animdata(scene, &la->id, la->adt, ctime, ADT_RECALC_DRIVERS); /* nodes */ if (la->nodetree) lamp_node_drivers_update(scene, la->nodetree, ctime); }
/* this is called in main loop, doing tagged updates before redraw */ void BKE_scene_update_tagged(Main *bmain, Scene *scene) { /* keep this first */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE); /* flush recalc flags to dependencies */ DAG_ids_flush_tagged(bmain); scene->physics_settings.quick_cache_step = 0; /* update all objects: drivers, matrices, displists, etc. flags set * by depgraph or manual, no layer check here, gets correct flushed * * in the future this should handle updates for all datablocks, not * only objects and scenes. - brecht */ scene_update_tagged_recursive(bmain, scene, scene); /* extra call here to recalc scene animation (for sequencer) */ { AnimData *adt = BKE_animdata_from_id(&scene->id); float ctime = BKE_scene_frame_get(scene); if (adt && (adt->recalc & ADT_RECALC_ANIM)) BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, 0); } /* quick point cache updates */ if (scene->physics_settings.quick_cache_step) BKE_ptcache_quick_cache_all(bmain, scene); /* notify editors and python about recalc */ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST); DAG_ids_check_recalc(bmain, scene, FALSE); /* clear recalc flags */ DAG_ids_clear_recalc(bmain); }
void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, const float fps) { CacheFile *cache_file; char filename[FILE_MAX]; for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) { /* Execute drivers only, as animation has already been done. */ BKE_animsys_evaluate_animdata(scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS); if (!cache_file->is_sequence) { continue; } const float time = BKE_cachefile_time_offset(cache_file, ctime, fps); if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) { BKE_cachefile_clean(scene, cache_file); #ifdef WITH_ALEMBIC ABC_free_handle(cache_file->handle); cache_file->handle = ABC_create_handle(filename, NULL); #endif } } }
static int ocean_bake_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_active_context(C); OceanModifierData *omd = (OceanModifierData *)edit_modifier_property_get(op, ob, eModifierType_Ocean); Scene *scene = CTX_data_scene(C); OceanCache *och; struct Ocean *ocean; int f, cfra, i=0; int free= RNA_boolean_get(op->ptr, "free"); wmJob *steve; OceanBakeJob *oj; if (!omd) return OPERATOR_CANCELLED; if (free) { omd->refresh |= MOD_OCEAN_REFRESH_CLEAR_CACHE; DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); return OPERATOR_FINISHED; } och = BKE_init_ocean_cache(omd->cachepath, modifier_path_relbase(ob), omd->bakestart, omd->bakeend, omd->wave_scale, omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution); och->time = MEM_mallocN(och->duration*sizeof(float), "foam bake time"); cfra = scene->r.cfra; /* precalculate time variable before baking */ for (f=omd->bakestart; f<=omd->bakeend; f++) { /* from physics_fluid.c: * XXX: This can't be used due to an anim sys optimisation that ignores recalc object animation, * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ ) * --> BKE_animsys_evaluate_all_animation(G.main, eval_time); * This doesn't work with drivers: * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL); */ /* Modifying the global scene isn't nice, but we can do it in * this part of the process before a threaded job is created */ //scene->r.cfra = f; //ED_update_for_newframe(CTX_data_main(C), scene, CTX_wm_screen(C), 1); /* ok, this doesn't work with drivers, but is way faster. * let's use this for now and hope nobody wants to drive the time value... */ BKE_animsys_evaluate_animdata(scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM); och->time[i] = omd->time; i++; } /* make a copy of ocean to use for baking - threadsafety */ ocean = BKE_add_ocean(); init_ocean_modifier_bake(ocean, omd); /* BKE_bake_ocean(ocean, och); omd->oceancache = och; omd->cached = TRUE; scene->r.cfra = cfra; DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); */ /* job stuff */ scene->r.cfra = cfra; /* setup job */ steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Ocean Simulation", WM_JOB_PROGRESS); oj= MEM_callocN(sizeof(OceanBakeJob), "ocean bake job"); oj->ocean = ocean; oj->och = och; oj->omd = omd; WM_jobs_customdata(steve, oj, oceanbake_free); WM_jobs_timer(steve, 0.1, NC_OBJECT|ND_MODIFIER, NC_OBJECT|ND_MODIFIER); WM_jobs_callbacks(steve, oceanbake_startjob, NULL, NULL, oceanbake_endjob); WM_jobs_start(CTX_wm_manager(C), steve); return OPERATOR_FINISHED; }
void BKE_object_handle_data_update(EvaluationContext *eval_ctx, Scene *scene, Object *ob) { ID *data_id = (ID *)ob->data; AnimData *adt = BKE_animdata_from_id(data_id); Key *key; float ctime = BKE_scene_frame_get(scene); if (G.debug & G_DEBUG_DEPSGRAPH) printf("recalcdata %s\n", ob->id.name + 2); /* TODO(sergey): Only used by legacy depsgraph. */ if (adt) { /* evaluate drivers - datalevel */ /* XXX: for mesh types, should we push this to derivedmesh instead? */ BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS); } /* TODO(sergey): Only used by legacy depsgraph. */ key = BKE_key_from_object(ob); if (key && key->block.first) { if (!(ob->shapeflag & OB_SHAPE_LOCK)) BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS); } /* includes all keys and modifiers */ switch (ob->type) { case OB_MESH: { BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL; uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH; #ifdef WITH_FREESTYLE /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */ if (eval_ctx->mode != DAG_EVAL_VIEWPORT) { data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; } #endif if (em) { makeDerivedMesh(scene, ob, em, data_mask, false); /* was CD_MASK_BAREMESH */ } else { makeDerivedMesh(scene, ob, NULL, data_mask, false); } break; } case OB_ARMATURE: if (ob->id.lib && ob->proxy_from) { if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { printf("Proxy copy error, lib Object: %s proxy Object: %s\n", ob->id.name + 2, ob->proxy_from->id.name + 2); } } else { BKE_pose_where_is(scene, ob); } break; case OB_MBALL: BKE_displist_make_mball(eval_ctx, scene, ob); break; case OB_CURVE: case OB_SURF: case OB_FONT: BKE_displist_make_curveTypes(scene, ob, 0); break; case OB_LATTICE: BKE_lattice_modifiers_calc(scene, ob); break; case OB_EMPTY: if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) if (BKE_image_is_animated(ob->data)) BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0); break; } /* related materials */ /* XXX: without depsgraph tagging, this will always need to be run, which will be slow! * However, not doing anything (or trying to hack around this lack) is not an option * anymore, especially due to Cycles [#31834] */ if (ob->totcol) { int a; if (ob->totcol != 0) { BLI_mutex_lock(&material_lock); for (a = 1; a <= ob->totcol; a++) { Material *ma = give_current_material(ob, a); if (ma) { /* recursively update drivers for this material */ material_drivers_update(scene, ma, ctime); } } BLI_mutex_unlock(&material_lock); } } else if (ob->type == OB_LAMP) lamp_drivers_update(scene, ob->data, ctime); /* particles */ if (ob != scene->obedit && ob->particlesystem.first) { ParticleSystem *tpsys, *psys; DerivedMesh *dm; ob->transflag &= ~OB_DUPLIPARTS; psys = ob->particlesystem.first; while (psys) { /* ensure this update always happens even if psys is disabled */ if (psys->recalc & PSYS_RECALC_TYPE) { psys_changed_type(ob, psys); } if (psys_check_enabled(ob, psys)) { /* check use of dupli objects here */ if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) && ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) || (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group))) { ob->transflag |= OB_DUPLIPARTS; } particle_system_update(scene, ob, psys); psys = psys->next; } else if (psys->flag & PSYS_DELETE) { tpsys = psys->next; BLI_remlink(&ob->particlesystem, psys); psys_free(ob, psys); psys = tpsys; } else psys = psys->next; } if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) { /* this is to make sure we get render level duplis in groups: * the derivedmesh must be created before init_render_mesh, * since object_duplilist does dupliparticles before that */ CustomDataMask data_mask = CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL; dm = mesh_create_derived_render(scene, ob, data_mask); dm->release(dm); for (psys = ob->particlesystem.first; psys; psys = psys->next) psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated; } } /* quick cache removed */ }
static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated) { extern int enable_cu_speed; /* object.c */ Object copyob; int cfrao = scene->r.cfra; int dupend = ob->dupend; /* simple prevention of too deep nested groups */ if (level > MAX_DUPLI_RECUR) return; /* if we don't have any data/settings which will lead to object movement, * don't waste time trying, as it will all look the same... */ if (ob->parent==NULL && ob->constraints.first==NULL && ob->adt==NULL) return; /* make a copy of the object's original data (before any dupli-data overwrites it) * as we'll need this to keep track of unkeyed data * - this doesn't take into account other data that can be reached from the object, * for example it's shapekeys or bones, hence the need for an update flush at the end */ copyob = *ob; /* duplicate over the required range */ if (ob->transflag & OB_DUPLINOSPEED) enable_cu_speed= 0; for (scene->r.cfra= ob->dupsta; scene->r.cfra<=dupend; scene->r.cfra++) { short ok= 1; /* - dupoff = how often a frames within the range shouldn't be made into duplis * - dupon = the length of each "skipping" block in frames */ if (ob->dupoff) { ok= scene->r.cfra - ob->dupsta; ok= ok % (ob->dupon+ob->dupoff); ok= (ok < ob->dupon); } if (ok) { DupliObject *dob; /* WARNING: doing animation updates in this way is not terribly accurate, as the dependencies * and/or other objects which may affect this object's transforms are not updated either. * However, this has always been the way that this worked (i.e. pre 2.5), so I guess that it'll be fine! */ BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ where_is_object_time(scene, ob, (float)scene->r.cfra); dob= new_dupli_object(lb, ob, ob->obmat, ob->lay, scene->r.cfra, OB_DUPLIFRAMES, animated); copy_m4_m4(dob->omat, copyob.obmat); } } enable_cu_speed= 1; /* reset frame to original frame, then re-evaluate animation as above * as 2.5 animation data may have far-reaching consequences */ scene->r.cfra= cfrao; BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ where_is_object_time(scene, ob, (float)scene->r.cfra); /* but, to make sure unkeyed object transforms are still sane, * let's copy object's original data back over */ *ob = copyob; }
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_FLIPPER: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_flag |= ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } } else if (bNegativeEvent){ m_flag |= ACT_FLAG_REVERSE; m_flag &= ~ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } break; case ACT_ACTION_PLAY: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_localtime = m_starttime; m_starttime = curtime; m_flag |= ACT_FLAG_LOCKINPUT; } } break; default: break; } /* Perform increment */ if (keepgoing){ if (m_playtype == ACT_ACTION_MOTION){ MT_Point3 newpos; MT_Point3 deltapos; newpos = obj->NodeGetWorldPosition(); /* Find displacement */ deltapos = newpos-m_lastpos; m_localtime += (length/m_stridelength) * deltapos.length(); m_lastpos = newpos; } else{ SetLocalTime(curtime); } } /* Check if a wrapping response is needed */ if (length){ if (m_localtime < m_startframe || m_localtime > m_endframe) { m_localtime = m_startframe + fmod(m_localtime, length); wrap = true; } } else m_localtime = m_startframe; /* Perform post-increment tasks */ switch (m_playtype){ case ACT_ACTION_FROM_PROP: { CValue* propval = GetParent()->GetProperty(m_propname); if (propval) m_localtime = propval->GetNumber(); if (bNegativeEvent){ keepgoing=false; } } break; case ACT_ACTION_MOTION: break; case ACT_ACTION_LOOP_STOP: break; case ACT_ACTION_FLIPPER: if (wrap){ if (!(m_flag & ACT_FLAG_REVERSE)){ m_localtime=m_endframe; //keepgoing = false; } else { m_localtime=m_startframe; keepgoing = false; } } break; case ACT_ACTION_LOOP_END: if (wrap){ if (m_flag & ACT_FLAG_KEYUP){ keepgoing = false; m_localtime = m_endframe; m_flag &= ~ACT_FLAG_LOCKINPUT; } SetStartTime(curtime); } break; case ACT_ACTION_PLAY: if (wrap){ m_localtime = m_endframe; keepgoing = false; m_flag &= ~ACT_FLAG_LOCKINPUT; } break; default: keepgoing = false; break; } /* Set the property if its defined */ if (m_framepropname[0] != '\0') { CValue* propowner = GetParent(); CValue* oldprop = propowner->GetProperty(m_framepropname); CValue* newval = new CFloatValue(m_localtime); if (oldprop) { oldprop->SetValue(newval); } else { propowner->SetProperty(m_framepropname, newval); } newval->Release(); } if (bNegativeEvent) m_blendframe=0.0f; /* Apply the pose if necessary*/ if (apply) { /* Priority test */ if (obj->SetActiveAction(this, priority, curtime)){ Key *key = obj->GetKey(); if (!key) { // this could happen if the mesh was changed in the middle of an action // and the new mesh has no key, stop the action keepgoing = false; } else { ListBase tchanbase= {NULL, NULL}; if (m_blendin && m_blendframe==0.0f){ // this is the start of the blending, remember the startup shape obj->GetShape(m_blendshape); m_blendstart = curtime; } // only interested in shape channel // 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); // 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; };
/* For the calculation of the effects of an Action at the given frame on an object * This is currently only used for the Action Constraint */ void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, char groupname[], float cframe) { bActionGroup *agrp = BKE_action_group_find_name(act, groupname); /* clear workob */ BKE_object_workob_clear(workob); /* init workob */ copy_m4_m4(workob->obmat, ob->obmat); copy_m4_m4(workob->parentinv, ob->parentinv); copy_m4_m4(workob->constinv, ob->constinv); workob->parent = ob->parent; workob->rotmode = ob->rotmode; workob->trackflag = ob->trackflag; workob->upflag = ob->upflag; workob->partype = ob->partype; workob->par1 = ob->par1; workob->par2 = ob->par2; workob->par3 = ob->par3; workob->constraints.first = ob->constraints.first; workob->constraints.last = ob->constraints.last; workob->pose = pose; /* need to set pose too, since this is used for both types of Action Constraint */ if (pose) { /* This function is most likely to be used with a temporary pose with a single bone in there. * For such cases it makes no sense to create hash since it'll only waste CPU ticks on memory * allocation and also will make lookup slower. */ if (pose->chanbase.first != pose->chanbase.last) { BKE_pose_channels_hash_make(pose); } if (pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { BKE_pose_update_constraint_flags(pose); } } BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr)); BLI_strncpy(workob->id.name, "OB<ConstrWorkOb>", sizeof(workob->id.name)); /* we don't use real object name, otherwise RNA screws with the real thing */ /* if we're given a group to use, it's likely to be more efficient (though a bit more dangerous) */ if (agrp) { /* specifically evaluate this group only */ PointerRNA id_ptr; /* get RNA-pointer for the workob's ID */ RNA_id_pointer_create(&workob->id, &id_ptr); /* execute action for this group only */ animsys_evaluate_action_group(&id_ptr, act, agrp, NULL, cframe); } else { AnimData adt = {NULL}; /* init animdata, and attach to workob */ workob->adt = &adt; adt.recalc = ADT_RECALC_ANIM; adt.action = act; /* execute effects of Action on to workob (or it's PoseChannels) */ BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM); } }
std::string AnimationExporter::create_4x4_source(std::vector<float> &frames , Object * ob_arm, Bone *bone , const std::string& anim_id) { COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; std::string source_id = anim_id + get_semantic_suffix(semantic); COLLADASW::Float4x4Source source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(frames.size()); source.setAccessorStride(16); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); add_source_parameters(param, semantic, false, NULL, true); source.prepareToAppendValues(); bPoseChannel *parchan = NULL; bPoseChannel *pchan = NULL; bPose *pose = ob_arm->pose; pchan = get_pose_channel(pose, bone->name); if (!pchan) return ""; parchan = pchan->parent; enable_fcurves(ob_arm->adt->action, bone->name); std::vector<float>::iterator it; int j = 0; for (it = frames.begin(); it != frames.end(); it++) { float mat[4][4], ipar[4][4]; float ctime = BKE_frame_to_ctime(scene, *it); BKE_animsys_evaluate_animdata(scene , &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM); where_is_pose_bone(scene, ob_arm, pchan, ctime, 1); // compute bone local mat if (bone->parent) { invert_m4_m4(ipar, parchan->pose_mat); mult_m4_m4m4(mat, ipar, pchan->pose_mat); } else copy_m4_m4(mat, pchan->pose_mat); UnitConverter converter; float outmat[4][4]; converter.mat4_to_dae(outmat,mat); source.appendValues(outmat); j++; } enable_fcurves(ob_arm->adt->action, NULL); source.finish(); return source_id; }
/* OB_DUPLIFRAMES */ static void make_duplis_frames(const DupliContext *ctx) { Scene *scene = ctx->scene; Object *ob = ctx->object; extern int enable_cu_speed; /* object.c */ Object copyob; int cfrao = scene->r.cfra; int dupend = ob->dupend; /* dupliframes not supported inside groups */ if (ctx->group) return; /* if we don't have any data/settings which will lead to object movement, * don't waste time trying, as it will all look the same... */ if (ob->parent == NULL && BLI_listbase_is_empty(&ob->constraints) && ob->adt == NULL) return; /* make a copy of the object's original data (before any dupli-data overwrites it) * as we'll need this to keep track of unkeyed data * - this doesn't take into account other data that can be reached from the object, * for example it's shapekeys or bones, hence the need for an update flush at the end */ copyob = *ob; /* duplicate over the required range */ if (ob->transflag & OB_DUPLINOSPEED) enable_cu_speed = 0; /* special flag to avoid setting recalc flags to notify the depsgraph of * updates, as this is not a permanent change to the object */ ob->id.tag |= LIB_TAG_ANIM_NO_RECALC; for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) { int ok = 1; /* - dupoff = how often a frames within the range shouldn't be made into duplis * - dupon = the length of each "skipping" block in frames */ if (ob->dupoff) { ok = scene->r.cfra - ob->dupsta; ok = ok % (ob->dupon + ob->dupoff); ok = (ok < ob->dupon); } if (ok) { /* WARNING: doing animation updates in this way is not terribly accurate, as the dependencies * and/or other objects which may affect this object's transforms are not updated either. * However, this has always been the way that this worked (i.e. pre 2.5), so I guess that it'll be fine! */ BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra); make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false); } } enable_cu_speed = 1; /* reset frame to original frame, then re-evaluate animation as above * as 2.5 animation data may have far-reaching consequences */ scene->r.cfra = cfrao; BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra); /* but, to make sure unkeyed object transforms are still sane, * let's copy object's original data back over */ *ob = copyob; }
std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Object *ob_arm, Bone *bone, const std::string& anim_id) { COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT; std::string source_id = anim_id + get_semantic_suffix(semantic); COLLADASW::Float4x4Source source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); source.setAccessorCount(frames.size()); source.setAccessorStride(16); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); add_source_parameters(param, semantic, false, NULL, true); source.prepareToAppendValues(); bPoseChannel *parchan = NULL; bPoseChannel *pchan = NULL; bPose *pose = ob_arm->pose; pchan = BKE_pose_channel_find_name(pose, bone->name); if (!pchan) return ""; parchan = pchan->parent; enable_fcurves(ob_arm->adt->action, bone->name); std::vector<float>::iterator it; int j = 0; for (it = frames.begin(); it != frames.end(); it++) { float mat[4][4], ipar[4][4]; float ctime = BKE_scene_frame_get_from_ctime(scene, *it); BKE_animsys_evaluate_animdata(scene, &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM); BKE_pose_where_is_bone(scene, ob_arm, pchan, ctime, 1); // compute bone local mat if (bone->parent) { invert_m4_m4(ipar, parchan->pose_mat); mult_m4_m4m4(mat, ipar, pchan->pose_mat); } else copy_m4_m4(mat, pchan->pose_mat); UnitConverter converter; // SECOND_LIFE_COMPATIBILITY // AFAIK animation to second life is via BVH, but no // reason to not have the collada-animation be correct if (export_settings->second_life) { float temp[4][4]; copy_m4_m4(temp, bone->arm_mat); temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; invert_m4(temp); mult_m4_m4m4(mat, mat, temp); if (bone->parent) { copy_m4_m4(temp, bone->parent->arm_mat); temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; mult_m4_m4m4(mat, temp, mat); } } float outmat[4][4]; converter.mat4_to_dae(outmat, mat); source.appendValues(outmat); j++; } enable_fcurves(ob_arm->adt->action, NULL); source.finish(); return source_id; }