cloning
link-mesh-array.py
link-mesh.py

mesh fabrication
staircase.py
triangle-donut.py
vertexAccumulator.py
randomSquareArray.py
meshFromBathymetry.py
cylinders-from-list-of-radii.py
binary-image-to-mesh.py
sphere-minecraft-schematic.py
spikify.py
add-to-mesh.py
mobius-strip.py
split-copy-mesh.py

fabricating other objects
create-text.py
text-from-file.py
create-camera.py
create-bezier.py
helix-bezier.py

material slots
cube-copy-blue.py
cube-turns-red.py
red-blue-per-object.py

animation and fcurves
csv-to-fcurve-loc-rot.py
csv-to-fcurve.py
pop-in-material.py
spike-wiggle-2.py
spike-wiggle.py
sweep-animate-size.py
animate-cycles-lamp-strength.py

incorporating python libraries
exec-text-library.py
exec-external-python.py
import-python.py

constraints
camera-track-object.py
text-track-camera.py

shape keys
explore-shape-keys.py
shape-key-fin.py
docking-tube.py

animating curve bevel
data-graph.py

drivers
scan-drivers.py
copy-drivers.py
driver-fin.py
driver-multi-chain.py

UV layers
barber-pole.py
expand-uv-to-fit.py
uv-from-geometry-cubic.py
flip-texture-v-coordinate.py

modifiers
hook-modifier-curve.py
rounded-prisms.py
make-tile.py
remove-action-modifiers.py

NLAs
explore-NLAs.py
spinning-frogs.py

video sequence editor (VSE)
create-vse-image-strips.py
slide-show.py
vse-strip-gap.py

images and textures
image-on-mesh.py
image-to-material-node.py
load-image-texture.py
texture-one-cube-face.py
condense-duplicate-images.py

analytic geometry
animate-random-spin.py
camera-cone-exp-2.py
camera-cone-exp.py
compute-circle-center.py
dihedral-angle-from-xy.py
extrude-edge-along-custom-axis.py
orientation-matrix.py
two-spheres.py
bezier-interpolate.py
rotate-to-match.py

node trees
change-diffuse-to-emission-node.py

etc
add-plane-from-selected-vertices.py
adjust-all-materials.py
all-nodes-cycles-materials.py
bit_shift.py
bone-orientation-demo.py
cannonball-packing.py
comb.py
convert-quaternion-keyframes-to-euler.py
copy-location-from-vertex-group.py
create-cycles-material.py
demonstrate-decomposition-instability.py
dump-point-cache.py
dump-screen-layout-info.py
expand-nla-strips.py
explore-edge-bevel-weight.py
find-action-users.py
find-green-rectangle.py
find-new-objects.py
fix-scene-layers.py
generate-makefile.py
link-external-data-blocks.py
list-referenced-files.py
material-readout.py
movie-card-stack.py
movies-on-faces.py
next-file-name.py
object-font-from-regular-font.py
operator-mesh-gridify.py
particle-animator.py
particle_loop.py
pose-match.py
pose-sequence-to-fbx.py
prepare-texture-bake.py
raining-physics.py
random-pebble-material.py
reverse-keyframes.py
scale-parallelogram.py
screenshot-sequence.py
select-objects-in-modifiers.py
select-vertices.py
shift-layers.py
snapshot-keyframes-as-mesh.py
sphere-project-texture.py
squish-mesh-axis.py
subdivide-fcurve.py
thicken-texture.py
transform-selected.py
voronoi-madness.py

__author__ = 'thoth'

import bpy
from mathutils import *

movies = {
    "bbb1080.mp4": {
        "img": "bbb1080.mp4",
        "base_frame":1000
    },
    "redline.mp4": {
        "img": "redline.mp4",
        "base_frame": 2593
    },
    "redline A": {
        "img": "redline.mp4",
        "base_frame": 2593
    },
    "redline B": {
        "img": "redline.mp4",
        "base_frame": 5838
    }
}

def material_for(image_movie, offset):
    name = "%s o=%d" % (image_movie.name, offset)

    mat = bpy.data.materials.get(name)
    if mat is None:
        mat = bpy.data.materials.new(name)
        mat.texture_slots.add()
        ts0 = mat.texture_slots[0]

        ts0.texture_coords = 'UV'
        ts0.uv_layer = 'UVMap'
        ts0.texture = bpy.data.textures.new(name, 'IMAGE')
    else:
        ts0 = mat.texture_slots[0]

    mat.specular_intensity = 0
    t1 = ts0.texture
    t1.image = image_movie
    t1.image_user.frame_duration = 1
    t1.image_user.frame_offset = offset

    return mat


def action_card_start():
    return bpy.data.actions.get("card start")


def action_card_pick_up():
    return bpy.data.actions.get("card parenting")


def action_card_release():
    return bpy.data.actions.get("card release")


def rig_child_animation(obj, pick_up, release):
    if obj.animation_data is None:
        obj.animation_data_create()
    track = obj.animation_data.nla_tracks.new()
    track.new("pick up", pick_up, action_card_pick_up())
    track.new("release", release, action_card_release())


def cardbot_for(num, loc=None):
    """ get or create the cardbot object and armature with the requested number.  Then set the location
    """
    rval = None

    scn = bpy.context.scene

    for obj in scn.objects:
        if obj.get("bot.number") == num and obj.data.name == "cardbot":
#            print(obj)
            if not hasattr(obj.data, "bones"):
                rval = obj
                ao = rval.parent

    if rval is None:
        # hmm, doesn't exist yet
        mesh = bpy.data.meshes["cardbot"]
        rval = bpy.data.objects.new("cardbot", mesh)
        rval["bot.number"] = num

        arm = bpy.data.armatures["cardbot"]
        ao = bpy.data.objects.new("cardbot armature", arm)
        ao["bot.number"] = num

        mod = rval.modifiers.new("armature", "ARMATURE")
        mod.object = ao
        clone_vertex_groups(bpy.data.objects["transmit bot"], rval)

        rval.parent = ao

    try:
        scn.objects.link(rval)
    except:
        pass
    try:
        scn.objects.link(ao)
    except:
        pass

    if loc is not None:
        ao.location = loc

    # and now comes the part I hate:
    bpy.context.scene.objects.active = ao
    bpy.ops.object.mode_set(mode='POSE')
    for bone in ao.pose.bones:
        bone.rotation_mode = 'XYZ'
    bpy.ops.object.mode_set(mode='OBJECT')

    return [rval, ao]


def add_child_constraint(obj, name, target, bone_name=None, use_location=True, use_rotation=True):
    cns = obj.constraints.new('CHILD_OF')
    cns.name = name
    cns.target = target
    cns.use_location_x = use_location
    cns.use_location_y = use_location
    cns.use_location_z = use_location
    cns.use_rotation_x = use_rotation
    cns.use_rotation_y = use_rotation
    cns.use_rotation_z = use_rotation
    if bone_name is not None:
        cns.subtarget = bone_name


def make_card_animated(armature, movie_id, pickup, release, num):

    name = "movie card"
    mesh = bpy.data.meshes["movie card"]

    obj = bpy.data.objects.new(name, mesh)
    ms0 = obj.material_slots[0]
    ms0.link = 'OBJECT'
    image_movie = bpy.data.images[movies[movie_id]["img"]]
    movie_base = movies[movie_id]["base_frame"]
    ms0.material = material_for(image_movie, pickup+movie_base)

    obj["card.number"] = num
    obj["bot.number"] = armature["bot.number"]

    scn = bpy.context.scene
    scn.objects.link(obj)

    obj.animation_data_create()
    track = obj.animation_data.nla_tracks.new()
    track.strips.new("pick up", pickup-49, action_card_pick_up())
    track.strips.new("release", release, action_card_release())
    try:
        track.strips.new("start", min(1, pickup-51), action_card_start())
    except:
        # the pickup happened so early we don't even need a start strip
        pass

    add_child_constraint(obj, "prelude rotation", armature, "card pre", False, True)
    add_child_constraint(obj, "prelude", armature, "card pre", True, False)
    add_child_constraint(obj, "ready", armature, "card lift", True, False)
    add_child_constraint(obj, "on arm", armature, "card anchor")
    add_child_constraint(obj, "sky", get_card_destination())
    add_child_constraint(obj, "up", armature, "card release")

    obj.layers = [i==1 or i==5 for i in range(20)]

    return obj


def get_card_destination():
    return bpy.data.objects.get("card destination")


def make_phantom_animated(armature, pickup, release, num):
    name = "phantom"
    mesh = bpy.data.meshes["phantom"]

    obj = bpy.data.objects.new(name, mesh)
    obj.scale = [0.25, 0.25, 0.25]

    obj["card.number"] = num
    obj["bot.number"] = armature["bot.number"]

    scn = bpy.context.scene
    scn.objects.link(obj)

    obj.animation_data_create()
    track = obj.animation_data.nla_tracks.new()
    track.strips.new("pick up", pickup-49, action_card_pick_up())
    track.strips.new("release", release, action_card_release())
    try:
        track.strips.new("start", min(1, pickup-51), action_card_start())
    except:
        # the pickup happened so early we don't even need a start strip
        pass

    obj.animation_data.action = action = bpy.data.actions.new("phantom action")

    fc = find_or_create_fcurve(action, "hide_render")
    for kp in add_keyframe_points(fc, [ [1, True],
                              [pickup+19, False]]):
        kp.interpolation = 'CONSTANT'

    add_child_constraint(obj, "prelude", armature, "card pre", True, False)
    add_child_constraint(obj, "ready", armature, "card lift", True, False)
    add_child_constraint(obj, "on arm", armature, "card anchor", True, False)
    add_child_constraint(obj, "sky", get_card_destination(), None, True, False)
    add_child_constraint(obj, "up", armature, "card release", True, False)

    obj.layers = [i==15 for i in range(20)]

    return obj


def clone_vertex_groups(src, dst):
    """ this is NOT general purpose.  It doesn't copy weights. """

    for vg1 in src.vertex_groups:
        vg = dst.vertex_groups.new(vg1.name)
        print(vg)


def find_or_create_track(animation_data, name):
    for track in animation_data.nla_tracks:
        print (track)
        if track.name == name:
            return track

    track = animation_data.nla_tracks.new()
    print(track)
    track.name = name
    return track


def destroy_all_nla_strips(strips):
    """ remove all the strips from an NLA track
    :param strips: something like data_block.animation_data.nla_tracks[i].strips
    """
    while len(strips) >0:
        strips.remove(strips[-1])

def wipe_fcurves(action):
    print("wipe fcurves %s"%action.name)
    while len(action.fcurves)>0:
        action.fcurves.remove(action.fcurves[-1])


def find_constraint_track_to(obj, armature, subtarget=None):
    cns_name = "look at %s" % armature.name
    for cns in obj.constraints:
        if cns.type == 'TRACK_TO' and cns.target == armature and cns.subtarget == subtarget:
            return cns

    cns = obj.constraints.new('TRACK_TO')
    cns.name = cns_name
    cns.target = armature
    cns.subtarget = subtarget
    cns.track_axis = 'TRACK_Z'
    cns.up_axis = 'UP_X'

    return cns


def find_or_create_fcurve(action, data_path, array_index= -1):
    for fc in action.fcurves:
        if fc.data_path == data_path and ( array_index<0 or fc.array_index==array_index):
            return fc
    fc = action.fcurves.new(data_path, array_index)
    return fc


def get_object(prefix, scene=bpy.context.scene):
    for obj in scene.objects:
        if obj.name[:len(prefix)] == prefix:
            return obj
    return None


def get_eyeball():
    prefix = "eyeball"
    return get_object("eyeball")


def get_laser_end():
    return get_object("laser end")


def get_laser():
    return get_object("laser beam")


def make_eyeball_look_at(armature, frame):

    eyeball = get_eyeball()

    cns = find_constraint_track_to(eyeball, armature, "card release")
    data_path = 'constraints["%s"].influence' % cns.name
    fc = find_or_create_fcurve(eyeball.animation_data.action, data_path)

    i0 = len(fc.keyframe_points)
    fc.keyframe_points.add(4)
    kp0 = fc.keyframe_points[i0]
    kp1 = fc.keyframe_points[i0 + 1]
    kp2 = fc.keyframe_points[i0 + 2]
    kp3 = fc.keyframe_points[i0 + 3]

    kp0.handle_left = [frame - 7, 0]
    kp0.co = [frame - 6, 0]
    kp0.handle_right = [frame - 5, 0]

    kp1.handle_left = [frame - 4, 1]
    kp1.co = [frame - 3, 1]
    kp1.handle_right = [frame - 2, 1]

    kp2.handle_left = [frame + 2, 1]
    kp2.co = [frame + 3, 1]
    kp2.handle_right = [frame + 4, 1]

    kp3.handle_left = [frame + 5, 0]
    kp3.co = [frame + 6, 0]
    kp3.handle_right = [frame + 7, 0]


def add_keyframe_points(fcurve, kps):
    idx0 = len(fcurve.keyframe_points)
    fcurve.keyframe_points.add(len(kps))
    rval = []
    for i in range(len(kps)):
        kp = fcurve.keyframe_points[idx0 + i]
        kp.co = kps[i]
        rval.append(kp)
    return rval


def find_or_create_child_constraint(obj, cns_name, target, subtarget=None):
    for cns in obj.constraints:
        if cns.type == 'CHILD_OF' and cns.target==target and (subtarget is None or cns.subtarget==subtarget):
            return cns
    cns = obj.constraints.new('CHILD_OF')
    cns.name =cns_name
    cns.target = target
    if subtarget is not None:
        cns.subtarget = subtarget
    return cns


def make_laser_blast(frame, armature):
    laser = get_laser()
    fc = find_or_create_fcurve(laser.animation_data.action, "hide_render")
    if len(fc.keyframe_points) < 1:
        # start off hidden
        fc.keyframe_points.add(1)
        fc.keyframe_points[0].co = [1, 1]
        fc.keyframe_points[0].interpolation = 'CONSTANT'

    idx0 = len(fc.keyframe_points)
    fc.keyframe_points.add(2)
    kp0 = fc.keyframe_points[idx0]
    kp1 = fc.keyframe_points[idx0 + 1]

    kp0.co = [frame - 2, 0]
    kp0.interpolation = 'CONSTANT'
    kp1.co = [frame + 3, 1]
    kp1.interpolation = 'CONSTANT'

    #

    laser_end = get_laser_end()

    cns = find_or_create_child_constraint(laser_end, "be at %s"%armature.name, armature, "card release")

    fc = find_or_create_fcurve(laser_end.animation_data.action, 'constraints["%s"].influence'%cns.name)

    if len(fc.keyframe_points) < 1:
        # start off hidden
        fc.keyframe_points.add(1)
        fc.keyframe_points[0].co = [1, 0]
        fc.keyframe_points[0].interpolation = 'CONSTANT'

    kps = [ [frame-4,1],
      [frame+5,0]]
    for kp in add_keyframe_points(fc, kps):
        kp.interpolation = 'CONSTANT'

def card_approval_event(armature, movie_id, old, frame, num):
    """
    :param armature: the armature handling the card
    :param movie_image: the movie that our cards come from
    :param old: the frame number of the previous card approval on this specific robot
    :param frame: the frame number of this specific card approval event
    :param num: card number
    :return:
    """
    make_card_animated(armature, movie_id, old, frame, num)

    track = find_or_create_track(armature.animation_data, "robot grabbing")
    track.strips.new("catch and release", frame, bpy.data.actions["robot grabbing"])

    make_eyeball_look_at(armature, frame)

    make_laser_blast(frame, armature)


def phantom_event(armature, movie_id, old, frame, num):

    make_phantom_animated(armature, old, frame, num)

    track = find_or_create_track(armature.animation_data, "robot grabbing")
    track.strips.new("catch and release", frame, bpy.data.actions["robot grabbing"])

    make_eyeball_look_at(armature, frame)

    make_laser_blast(frame, armature)


def set_empty_action(laser, action_name):
    if laser.animation_data is None:
        laser.animation_data_create()
    if laser.animation_data.action is None:
        laser.animation_data.action = bpy.data.actions.new(action_name)
    else:
        wipe_fcurves(laser.animation_data.action)


def blast_old_cards():
    scn = bpy.context.scene

    for obj in scn.objects:
        if obj.name[:10] == "movie card" and obj.layers[5] or obj.name[:7]=="phantom" and obj.layers[15]:
            scn.objects.unlink(obj)



def reinitialize_actors(robots):
    eyeball = get_eyeball()
    set_empty_action(eyeball, "eyeball look at")

    #
    #

    laser = get_laser()
    print ("laser is %s"% laser.name)
    set_empty_action(laser, "laser flash")

    #
    #

    set_empty_action(get_laser_end(), "laser end")

    #
    #
    for robot in robots:

        (bot, arm) = cardbot_for(robot[0], robot[1])

        bot["movie"] = robot[2]
        if arm.animation_data is None:
            arm.animation_data_create()
        track = find_or_create_track(arm.animation_data, "robot grabbing")

        destroy_all_nla_strips(track.strips)

    #
    #
    blast_old_cards()


def go():
    reinitialize_actors([
        [7, [0, 2, 0], 'bbb1080.mp4'],
        [3, [0, -2, 0], 'redline.mp4']
    ])

    #
    #

    (b1, a1) = cardbot_for(7, [0, 2, 0])



    num = 1
    events = [ [7,15], [3,45], [7,75, phantom_event], [7,100], [3,130], [7,165] ]

    animate_for_events(events, 1)


def events_1_1_2():
    frame = 15
    events = []
    for i in range(7):
        for suffix in [ "a", "b", "a", "c"]:
            bot = "112 "+suffix
            evt = [ bot, frame]
            events.append(evt)

            frame = frame + 30
    return events


def animate_for_events(events, num):
    old_per_bot = {}
    for event in events:
        bot_num = event[0]
        frame = event[1]

        event_actor = None
        if len(event) > 2:
            event_actor = event[2]
        if event_actor is None:
            event_actor = card_approval_event

        old = old_per_bot.get(bot_num) or -15

        (b1, a1) = cardbot_for(bot_num)

        event_actor(a1, b1["movie"], old, frame, num)

        num += 1
        old_per_bot[bot_num] = frame
    bpy.context.scene.objects.active = a1
#    print(a1)


def scene_1_1_2():
    reinitialize_actors([
        ["112 a", [0, 2, 0], 'bbb1080.mp4'],
        ["112 b", [0, 0, 0], 'redline A'],
        ["112 c", [0, -2, 0], 'redline B']
    ])

    #
    #

    num = 1

    events = events_1_1_2()

    animate_for_events(events, num)


#
#
#

scn = bpy.context.scene

if scn.name == "weight 1 1 2":
    scene_1_1_2()
else:
    go()

Blender python API quick-start

Syntax highlighting by Pygments.