def preview_nla(self, context): scn = context.scene start = end = None # Set preview range using snapping (from frame_step operator) prefs = scn.step_frames stepped = prefs.on_steps frame_step = prefs.frame_step strips_nla = Get.strips_nla(context) for (obj, strips) in strips_nla: for item in strips: strip = item.strip # Scale update start value frame_start = int(strip.frame_start) if stepped: while (frame_start % frame_step): frame_start -= 1 if (start is None) or (frame_start < start): start = frame_start # Get used frame range from repeat # if (strip.repeat != 1.0): # fs = strip.frame_start # fe = strip.frame_end # fe2 = scale_range(fe, fs, fe, 0, abs(fs - fe)) # frame_end = int((1 / strip.repeat) * fe2 + fs) # else: # frame_end = int(strip.frame_end) if self.repeat: afe = strip.action_frame_end frame_end = Get.frame_from_strip(context, strip, afe) else: frame_end = strip.frame_end frame_end = round(frame_end, 4) # Update end value if stepped: while (frame_end % frame_step): frame_end += 1 if (strip.repeat > 1.0) and self.repeat: # Don't let loops end on the first frame frame_end -= 1 if (end is None) or (end < frame_end): end = frame_end if (None not in {start, end}): scn.use_preview_range = True scn.frame_preview_end = end scn.frame_preview_start = start return {'FINISHED'} else: if strips_nla: self.report({'WARNING'}, "Couldn't set preview; using default") return bpy.ops.nla.previewrange_set()
def scan_strips(context, sub, selected): frames = list() for obj in Get.objects_nla(context): data = getattr(obj, 'data', None) shapes = getattr(data, 'shape_keys', None) # Poll object if pose(context): if not pose(obj): continue elif selected: if not Get.selected_pose_bones(context, src=obj): continue else: if (selected and obj not in selected): continue for src in (obj, data, shapes): frames_fcurve = list() frames_strip = list() for item in Get.strip_tracks(src, selected=False): strip = item.strip if strip.mute and not strip.select: continue for fc in strip.fcurves: if fc.hide: continue scan_fcurve(context, sub, fc, frames_fcurve) if frames_fcurve: # Don't scan strip boxes if have animation keyframes continue (fs, fe) = (strip.frame_start, strip.frame_end) if not sub: (fs, fe) = (smooth(fs), smooth(fe)) frames_strip.append(fs) frames_strip.append(fe) # Get loop ends if (strip.action) and (strip.repeat != 1.0): afe = strip.action_frame_end fel = fer = Get.frame_from_strip(context, strip, afe) while fel < strip.frame_end: frames_strip.append([smooth(fel), fel][sub]) fel += (fer - strip.frame_start) if frames_fcurve: frames.extend(frames_fcurve) else: frames.extend(frames_strip) return sorted(set(frames))
def scan_fcurve(context, sub, fcurve, frames=list(), strip=None): scn = context.scene fc = (int(scn.frame_current_final), scn.frame_current_final)[sub] if not fcurve.keyframe_points: return frames types = scn.keyframe_navigation_types (first_key, last_key) = (fcurve.keyframe_points[0], fcurve.keyframe_points[-1]) if ('HIDDEN' not in types) and fcurve.hide: return frames keyframes = list() for key in fcurve.keyframe_points: if (key.type not in types): # and key not in (first_key, last_key): continue co = key.co[0] # cycos = list() if strip: co = Get.frame_from_strip(context, strip, frame=co) # for (x, loco) in enumerate(cycle): # cyco = co + x * loco # cycos.append(cyco) # if cycle and (strip.repeat % 1): # has decimal # cycos.append(cyco + loco) keyframes.append(co) # for cyco in cycos: # if not sub: cyco = smooth(cyco) # frames.append(cyco) for co in keyframes: if not sub: co = smooth(co) frames.append(co) use_cycles = scn.tool_settings.use_keyframe_cycle_aware for mod in fcurve.modifiers: if (mod.type == 'CYCLES') and use_cycles: (fs, fe) = (keyframes[0], keyframes[-1]) if abs(fs - fe) < 1: continue cycos = list() offset = (fe - fs) loops = list() if fe <= fc: fel = fe while fel <= fc: loops.append(1) fel += offset elif fc <= fs: fsl = fs while fc <= fsl: loops.append(-1) fsl -= offset for (x, fl) in enumerate(loops): for co in keyframes: co += ((x + 1) * (offset * fl)) if not sub: co = smooth(co) frames.append(co) return frames
def scan_actions(context, sub, selected): scn = context.scene fc = (int(scn.frame_current_final), scn.frame_current_final)[sub] frames = list() for obj in selected: if Is.gpencil(obj): for layer in obj.data.layers: for frame in layer.frames: frames.append(frame.frame_number) for obj in Get.objects_nla(context): # Poll object if pose(context): if not pose(obj): continue elif selected: bones = [ f'pose.bones[\"{b.name}\"]' for b in Get.selected_pose_bones(context, src=obj) ] if not bones: continue else: bones = list() else: if (selected and obj not in selected): continue else: bones = list() for anim in Get.animation_datas(obj): if (not anim.action): continue if anim.use_tweak_mode: for s in Get.strips(anim.id_data): if s.action == anim.action: strip = s if s.active: break # Get loop ends cycle = list() afe = strip.action_frame_end fel = fer = Get.frame_from_strip(context, strip, afe) while fel < strip.frame_end: offset = (fer - strip.frame_start) cycle.append(offset) fel += abs(offset) # If offset becomes negative, it "should" create an infinite loop # abs() forces positive, which "should" prevent loop else: strip = None for fcurve in anim.action.fcurves: path = fcurve.data_path if bones: # Bones are selected, so verify this fcurve if for one of them for bpath in bones: if path.startswith(bpath): break else: continue elif path.startswith('pose.bones[\"'): try: eval(repr(obj) + '.' + path) # Validate path bpath = path.split('\"]', 1)[0] + '\"]' bone = eval(repr(obj) + '.' + bpath) if not Is.visible(context, bone): continue except: # curve points to a removed bone or something continue scan_fcurve(context, sub, fcurve, frames, strip=strip) return sorted(set(frames))