exports.update_scene_nla = function(scene, is_cyclic) { var nla = { frame_start: scene["frame_start"], frame_end: scene["frame_end"], last_frame: -1, cyclic: is_cyclic, objects: [] } var sobjs = m_scenes.get_scene_objs(scene, "ALL"); for (var i = 0; i < sobjs.length; i++) { var sobj = sobjs[i]; var adata = sobj["animation_data"]; if (adata && adata["nla_tracks"].length) { var nla_tracks = adata["nla_tracks"]; if (m_util.is_armature(sobj) || m_cam.is_camera(sobj) || m_util.is_mesh(sobj)) { var nla_events = get_nla_events(nla_tracks); sobj._nla_events = nla_events; nla.objects.push(sobj); } if (m_sfx.is_speaker(sobj)) { var nla_events = get_nla_events(nla_tracks); sobj._nla_events = nla_events; nla.objects.push(sobj); } } } for (var i = 0; i < sobjs.length; i++) { var sobj = sobjs[i]; for (var j = 0; j < nla.objects.length; j++) if (m_anim.get_first_armature_object(sobj) == nla.objects[j]) { sobj._nla_events = m_util.clone_object_json(nla.objects[j]._nla_events); nla.objects.push(sobj); } if (m_particles.has_particles(sobj) && m_particles.has_anim_particles(sobj)) { var ev = { frame_start: nla.frame_start, frame_end: nla.frame_end+1, frame_offset: 0, scheduled: false, action: null } sobj._nla_events = [ev]; nla.objects.push(sobj); } } enforce_nla_consistency(nla); _nla_arr.push(nla); }
function has_spk_param_nla(obj) { if (m_sfx.is_speaker(obj) && obj["data"]["animation_data"] && obj["data"]["animation_data"]["nla_tracks"].length) return true; else return false; }
function process_event_start(obj, ev, frame, elapsed) { if (m_particles.has_particles(obj) && m_particles.has_anim_particles(obj)) { m_anim.apply_def(obj); m_anim.set_behavior(obj, m_anim.AB_FINISH_STOP, m_anim.SLOT_0); } else if (m_util.is_armature(obj) || m_util.is_mesh(obj) || m_cam.is_camera(obj)) { m_anim.apply(obj, ev.action, m_anim.SLOT_0); // NOTE: should not be required m_anim.set_behavior(obj, m_anim.AB_FINISH_STOP, m_anim.SLOT_0); } else if (m_sfx.is_speaker(obj)) { // TODO: speakers are special var when = (ev.frame_start - frame) / cfg_ani.framerate; var duration = (ev.frame_end - ev.frame_start) / cfg_ani.framerate; m_sfx.play(obj, when, duration); } }
exports.update = function(timeline, elapsed) { // NOTE: need explicit start if (_start_time == -1) _start_time = timeline; for (var i = 0; i < _nla_arr.length; i++) { var nla = _nla_arr[i]; process_nla_script(nla, timeline, elapsed, _start_time); var cf = calc_curr_frame(nla, timeline, _start_time); for (var j = 0; j < nla.objects.length; j++) { var obj = nla.objects[j]; var nla_events = obj._nla_events; // NOTE: allow single-strip speakers to play again for (var k = 0; k < nla_events.length; k++) { var ev = nla_events[k]; if (cf < nla.last_frame && m_sfx.is_speaker(obj)) ev.scheduled = false; } for (var k = 0; k < nla_events.length; k++) { var ev = nla_events[k]; if (ev.ext_frame_start <= cf && cf < ev.ext_frame_end) if (!ev.scheduled) { process_event_start(obj, ev, cf, elapsed); for (var l = 0; l < nla_events.length; l++) if (nla_events[l] != ev) nla_events[l].scheduled = false; ev.scheduled = true; } if (ev.scheduled) process_event(obj, ev, cf, elapsed); } } nla.last_frame = cf; } }
function process_event_start(obj, ev, frame, elapsed) { // subtract elapsed because play() occures before animation calcuations var init_anim_frame = ev.frame_offset - elapsed * cfg_ani.framerate; if (m_particles.has_particles(obj) && m_particles.has_anim_particles(obj)) { m_anim.apply_def(obj); m_anim.set_current_frame_float(obj, init_anim_frame); m_anim.play(obj); } else if (m_util.is_armature(obj) || m_util.is_mesh(obj) || m_cam.is_camera(obj)) { m_anim.apply(obj, ev.action); m_anim.set_current_frame_float(obj, init_anim_frame); m_anim.play(obj); } else if (m_sfx.is_speaker(obj)) { // TODO: speakers are special var when = 0; var duration = (ev.frame_end - frame) / cfg_ani.framerate; m_sfx.play(obj, when, duration); } }
/** * Try to get action from the following places: * obj.modifiers -> armature obj * obj.animation_data.action * spkobj.data.animation_data * @param {Object} obj Object ID * @returns Default action or null */ function get_default_action(obj) { // armature from obj.modifieres var armobj = get_first_armature_object(obj); if (armobj) { var anim_data = armobj["animation_data"]; if (anim_data && anim_data["action"]) return anim_data["action"]; } // animation_data var anim_data = obj["animation_data"]; if (anim_data && anim_data["action"]) return anim_data["action"]; if (m_sfx.is_speaker(obj) && obj["data"]["animation_data"] && obj["data"]["animation_data"]["action"]) return obj["data"]["animation_data"]["action"]; // not found return null; }
/** * Calculate object animation data: * quats, trans for each bone (group) index and pierced point * save them to obj._anim */ function apply_action(obj, action) { if (!m_util.get_dict_length(action["fcurves"])) throw new Error("No fcurves in action \"" + action["name"] + "\""); var frame_range = action["frame_range"]; var act_render = action._render; obj._anim.action_name = action["name"]; obj._anim.action_frame_range = frame_range; obj._anim.action_step = act_render.pierce_step; obj._anim.action_bflags = act_render.bflags; obj._anim.start = frame_range[0]; obj._anim.current_frame_float = frame_range[0]; obj._anim.length = frame_range[1] - frame_range[0]; // TODO: clarify length/frame_range/num_pierced var num_pierced = act_render.num_pierced; var armobj = get_first_armature_object(obj); // armature itself if (m_util.is_armature(obj)) { obj._anim.type = OBJ_ANIM_TYPE_ARMATURE; var pose_data_frames = get_cached_pose_data(obj, action); if (!pose_data_frames) { var bone_pointers = calc_armature_bone_pointers(obj); var pose_data_frames = calc_pose_data_frames(obj, action, bone_pointers); cache_pose_data(obj, action, pose_data_frames); } obj._anim.trans = pose_data_frames.trans; obj._anim.quats = pose_data_frames.quats; // skeletal mesh animation } else if (armobj) { obj._anim.type = OBJ_ANIM_TYPE_SKELETAL; var pose_data_frames = get_cached_pose_data(obj, action); if (!pose_data_frames) { var bone_pointers = obj._render.bone_pointers; // calc anim data by posing armature object in every pierced point var pose_data_frames = calc_pose_data_frames(armobj, action, bone_pointers); cache_pose_data(obj, action, pose_data_frames); } obj._anim.trans = pose_data_frames.trans; obj._anim.quats = pose_data_frames.quats; } else if (m_sfx.is_speaker(obj) && (act_render.params["volume"] || act_render.params["pitch"])) { obj._anim.volume = act_render.params["volume"] || null; obj._anim.pitch = act_render.params["pitch"] || null; obj._anim.type = OBJ_ANIM_TYPE_SOUND; } else { var tsr = act_render.params["tsr"]; if (tsr) { obj._anim.trans = []; obj._anim.quats = []; for (var i = 0; i < num_pierced; i++) { obj._anim.trans.push(tsr.subarray(i*8, i*8 + 4)); obj._anim.quats.push(tsr.subarray(i*8 + 4, i*8 + 8)); } obj._anim.type = OBJ_ANIM_TYPE_OBJECT; } else { m_print.warn("B4W Warning: Incompatible action \"" + action["name"] + "\" has been applied to object \"" + obj["name"] + "\""); obj._anim.type = OBJ_ANIM_TYPE_STATIC; } } }
exports.update_scene_nla = function(scene, is_cyclic) { var nla = { frame_start: scene["frame_start"], frame_end: scene["frame_end"], frame_offset: 0, last_frame: -1, cyclic: is_cyclic, objects: [], script: [], curr_script_slot: 0 } prepare_nla_script(scene, nla); var sobjs = m_scs.get_scene_objs(scene, "ALL", m_scs.DATA_ID_ALL); for (var i = 0; i < sobjs.length; i++) { var sobj = sobjs[i]; var adata = sobj["animation_data"]; if (adata && adata["nla_tracks"].length) { var nla_tracks = adata["nla_tracks"]; if (m_util.is_armature(sobj) || m_cam.is_camera(sobj) || m_util.is_mesh(sobj)) { var nla_events = get_nla_events(nla_tracks); sobj._nla_events = nla_events; } if (m_sfx.is_speaker(sobj)) { var nla_events = get_nla_events(nla_tracks); sobj._nla_events = nla_events; } } if (m_anim.has_animated_nodemats(sobj)) { var materials = sobj["data"]["materials"]; for (var j = 0; j < materials.length; j++) { var mat = materials[j]; var node_tree = mat["node_tree"]; var adata = node_tree["animation_data"]; if (node_tree && adata) { var nla_tracks = adata["nla_tracks"]; var nla_events = get_nla_events(nla_tracks); if (sobj._nla_events) sobj._nla_events = sobj._nla_events.concat(nla_events); else sobj._nla_events = nla_events; } } } if (sobj._nla_events) nla.objects.push(sobj); } for (var i = 0; i < sobjs.length; i++) { var sobj = sobjs[i]; if (m_particles.has_particles(sobj) && m_particles.has_anim_particles(sobj)) { var ev = { frame_start: nla.frame_start, frame_end: nla.frame_end+1, scheduled: false, paused: false, action: null, action_frame_start: 0, action_frame_end: 0, ext_frame_start: 0, ext_frame_end: 0 } sobj._nla_events = [ev]; nla.objects.push(sobj); } } enforce_nla_consistency(nla); calc_nla_extents(nla); _nla_arr.push(nla); }
exports.update_scene_nla = function(scene, is_cyclic) { var nla = { frame_start: scene["frame_start"], frame_end: scene["frame_end"], frame_offset: 0, last_frame: -1, cyclic: is_cyclic, objects: [], textures: [], script: [], curr_script_slot: 0, registers: { "R1" : 0, "R2" : 0, "R3" : 0, "R4" : 0, "R5" : 0, "R6" : 0, "R7" : 0, "R8" : 0 } } prepare_nla_script(scene, nla); var sobjs = m_scs.get_scene_objs(scene, "ALL", m_scs.DATA_ID_ALL); for (var i = 0; i < sobjs.length; i++) { var sobj = sobjs[i]; var slot_num = 0; var obj_nla_events = []; var adata = sobj["animation_data"]; if (adata && adata["nla_tracks"].length) { var nla_tracks = adata["nla_tracks"]; if (m_util.is_armature(sobj) || m_cam.is_camera(sobj) || m_util.is_mesh(sobj) || m_util.is_empty(sobj) || // no need for separate slot in case of sound m_sfx.is_speaker(sobj)) { var nla_events = get_nla_events(nla_tracks, slot_num); if (nla_events.length) { obj_nla_events = obj_nla_events.concat(nla_events); slot_num++; } } } if (has_spk_param_nla(sobj)) { var nla_tracks = sobj["data"]["animation_data"]["nla_tracks"]; var nla_events = get_nla_events(nla_tracks, slot_num); if (nla_events.length) { obj_nla_events = obj_nla_events.concat(nla_events); slot_num++; } } if (m_anim.has_animated_nodemats(sobj)) { var materials = sobj["data"]["materials"]; for (var j = 0; j < materials.length; j++) { var mat = materials[j]; var node_tree = mat["node_tree"]; var adata = node_tree["animation_data"]; if (node_tree && adata) { var nla_tracks = adata["nla_tracks"]; var nla_events = get_nla_events(nla_tracks, -1); var mat_anim_names = []; for (var k = 0; k < nla_events.length; k++) { var ev = nla_events[k]; if (mat_anim_names.indexOf(ev.anim_name) == -1) mat_anim_names.push(ev.anim_name); ev.anim_slot = slot_num + mat_anim_names.indexOf(ev.anim_name); obj_nla_events.push(ev); } slot_num += mat_anim_names.length; } } } for (var j = 0; j < sobj["particle_systems"].length; j++) { var psys = sobj["particle_systems"][j]; var pset = psys["settings"]; if (pset["type"] == "EMITTER" && pset["b4w_allow_nla"]) { var ev = init_event(); ev.type = "CLIP"; ev.frame_start = nla.frame_start; ev.frame_end = nla.frame_end+1; ev.anim_name = psys["name"]; ev.anim_slot = slot_num; obj_nla_events.push(ev); slot_num++; } } var slot_num_va = slot_num+1; // NOTE: the data is missing in the meta objects if (m_util.is_mesh(sobj) && sobj["data"]) { for (var j = 0; j < sobj["data"]["b4w_vertex_anim"].length; j++) { var va = sobj["data"]["b4w_vertex_anim"][j]; if (va["allow_nla"]) { slot_num = slot_num_va; var ev = init_event(); ev.type = "CLIP"; ev.frame_start = nla.frame_start; ev.frame_end = nla.frame_end+1; ev.anim_name = va["name"]; ev.anim_slot = slot_num; obj_nla_events.push(ev); } } } if (obj_nla_events.length) { sobj._nla_events = obj_nla_events; nla.objects.push(sobj); } } var textures = scene._render.video_textures; for (var j = 0; j < textures.length; j++) { var ev = init_event(); var texture = textures[j]._render; ev.type = "VIDEO"; ev.frame_start = Math.min(texture.frame_start, nla.frame_end); if (texture.use_cyclic) ev.frame_end = nla.frame_end; else ev.frame_end = Math.min(texture.frame_duration + texture.frame_start + texture.frame_offset, nla.frame_end); ev.anim_name = textures[j].name; texture._nla_tex_event = ev; nla.textures.push(texture); } enforce_nla_consistency(nla); calc_nla_extents(nla); _nla_arr.push(nla); }