Example #1
0
    def create_eyes(self, data):
        self.eye_left = Ball((-10, 3, -5), data.eye_size, (255, 255, 255))
        self.eye_left.set_gap(5, self.head)
        self.eye_right = Ball((-10, 3, 5), data.eye_size, (255, 255, 255))
        self.eye_right.set_gap(5, self.head)

        self.iris_left = Ball(self.eye_left - (4, 0, 0), data.iris_size, data.iris_col(80))
        self.iris_right = Ball(self.eye_right - (4, 0, 0), data.iris_size, data.iris_col(80))

        self.pupil_left = Ball(self.iris_left - (10, 0, 0), data.pupil_size, (0, 0, 0))
        self.pupil_left.move_to_sphere(self.iris_left)
        self.pupil_right = Ball(self.iris_right - (10, 0, 0), data.pupil_size, (0, 0, 0))
        self.pupil_right.move_to_sphere(self.iris_right)

        mood_delta = data.brow_mood * 3
        
        self.brow_left_inner = Ball(self.eye_left - (0, 10, -data.brow_length), data.brow_size, data.hair_col(50))
        self.brow_left_inner.set_gap(5 + mood_delta, self.eye_left)
        self.brow_left_middle = Ball(self.eye_left - (0, 10, 0), data.brow_size, data.hair_col(70))
        self.brow_left_middle.set_gap(5 + data.brow_length, self.eye_left)
        self.brow_left_outer = Ball(self.eye_left - (0, 10, data.brow_length), data.brow_size, data.hair_col(60))
        self.brow_left_outer.set_gap(5 - mood_delta, self.eye_left)
        self.brow_right_inner = Ball(self.eye_right - (0, 10, data.brow_length), data.brow_size, data.hair_col(60))
        self.brow_right_inner.set_gap(5 + mood_delta, self.eye_right)
        self.brow_right_middle = Ball(self.eye_right - (0, 10, 0), data.brow_size, data.hair_col(70))
        self.brow_right_middle.set_gap(5 + data.brow_length, self.eye_right)
        self.brow_right_outer = Ball(self.eye_right - (0, 10, -data.brow_length), data.brow_size, data.hair_col(50))
        self.brow_right_outer.set_gap(5 - mood_delta, self.eye_right)
Example #2
0
    def create_mane(self, data):
        self.hairs = Figure()

        hair_top = Ball(self.head - (-10, 5, 0), 8, None)
        hair_top.move_to_sphere(self.head)
        hair_bottom = Ball(self.shoulder - (-10, 15, 0), 8, None)
        hair_bottom.move_to_sphere(self.shoulder)        
        for start, gamma, length, angle, lightness, straightness in zip(
                        data.hair_starts, data.hair_gammas, data.hair_lengths,
                        data.hair_angles, data.hair_tip_lightnesses,
                        data.hair_straightnesses):
            x, y, z = (c[0] + start / 100.0 * (c[1] - c[0]) for c in zip(hair_top.center, hair_bottom.center))
            hair_start = Ball((x, y, z), 8, data.hair_col(60))
            hair_end = Ball((x + length, y, z + straightness), 4, data.hair_col(lightness))
            hair_end.rotate(-angle, hair_start)
            hair = NonLinBone(hair_start, hair_end, yfunc = gammafunc(gamma))
            self.hairs.add(hair)        
Example #3
0
    def create_legs(self, data):
        self.legs = [] # order: front left, front right, back left, back right

        for z in (-25, 25): # front
            hip = Ball((55, 160, z), 25, data.body_col(40))
            knee = Ball((35, 254, z), 9, data.body_col(70))
            hoof = Ball((55, 310, z), 11, data.body_col(45))
            hip.move_to_sphere(self.shoulder)
            leg = Leg(hip, knee, hoof)
            self.legs.append(leg)

        for z in (-25, 25): # back
            hip = Ball((225, 190, z), 25, data.body_col(40))
            knee = Ball((230, 265, z), 9, data.body_col(70))
            hoof = Ball((220, 310, z), 11, data.body_col(45))
            hip.move_to_sphere(self.butt)
            leg = Leg(hip, knee, hoof)
            self.legs.append(leg)
Example #4
0
    def create_mane(self, data):
        self.hairs = Figure()

        hair_top = Ball(self.head - (-10, 5, 0), 8, None)
        hair_top.move_to_sphere(self.head)
        hair_bottom = Ball(self.shoulder - (-10, 15, 0), 8, None)
        hair_bottom.move_to_sphere(self.shoulder)
        for start, gamma, length, angle, lightness, straightness in zip(
                data.hair_starts, data.hair_gammas, data.hair_lengths,
                data.hair_angles, data.hair_tip_lightnesses,
                data.hair_straightnesses):
            x, y, z = (c[0] + start / 100.0 * (c[1] - c[0])
                       for c in zip(hair_top.center, hair_bottom.center))
            hair_start = Ball((x, y, z), 8, data.hair_col(60))
            hair_end = Ball((x + length, y, z + straightness), 4,
                            data.hair_col(lightness))
            hair_end.rotate(-angle, hair_start)
            hair = NonLinBone(hair_start, hair_end, yfunc=gammafunc(gamma))
            self.hairs.add(hair)
Example #5
0
    def create_legs(self, data):
        self.legs = []  # order: front left, front right, back left, back right

        for z in (-25, 25):  # front
            hip = Ball((55, 160, z), 25, data.body_col(40))
            knee = Ball((35, 254, z), 9, data.body_col(70))
            hoof = Ball((55, 310, z), 11, data.body_col(45))
            hip.move_to_sphere(self.shoulder)
            leg = Leg(hip, knee, hoof)
            self.legs.append(leg)

        for z in (-25, 25):  # back
            hip = Ball((225, 190, z), 25, data.body_col(40))
            knee = Ball((230, 265, z), 9, data.body_col(70))
            hoof = Ball((220, 310, z), 11, data.body_col(45))
            hip.move_to_sphere(self.butt)
            leg = Leg(hip, knee, hoof)
            self.legs.append(leg)
Example #6
0
    def create_eyes(self, data):
        self.eye_left = Ball((-10, 3, -5), data.eye_size, (255, 255, 255))
        self.eye_left.set_gap(5, self.head)
        self.eye_right = Ball((-10, 3, 5), data.eye_size, (255, 255, 255))
        self.eye_right.set_gap(5, self.head)

        self.iris_left = Ball(self.eye_left - (4, 0, 0), data.iris_size,
                              data.iris_col(80))
        self.iris_right = Ball(self.eye_right - (4, 0, 0), data.iris_size,
                               data.iris_col(80))

        self.pupil_left = Ball(self.iris_left - (10, 0, 0), data.pupil_size,
                               (0, 0, 0))
        self.pupil_left.move_to_sphere(self.iris_left)
        self.pupil_right = Ball(self.iris_right - (10, 0, 0), data.pupil_size,
                                (0, 0, 0))
        self.pupil_right.move_to_sphere(self.iris_right)

        mood_delta = data.brow_mood * 3

        self.brow_left_inner = Ball(self.eye_left - (0, 10, -data.brow_length),
                                    data.brow_size, data.hair_col(50))
        self.brow_left_inner.set_gap(5 + mood_delta, self.eye_left)
        self.brow_left_middle = Ball(self.eye_left - (0, 10, 0),
                                     data.brow_size, data.hair_col(70))
        self.brow_left_middle.set_gap(5 + data.brow_length, self.eye_left)
        self.brow_left_outer = Ball(self.eye_left - (0, 10, data.brow_length),
                                    data.brow_size, data.hair_col(60))
        self.brow_left_outer.set_gap(5 - mood_delta, self.eye_left)
        self.brow_right_inner = Ball(
            self.eye_right - (0, 10, data.brow_length), data.brow_size,
            data.hair_col(60))
        self.brow_right_inner.set_gap(5 + mood_delta, self.eye_right)
        self.brow_right_middle = Ball(self.eye_right - (0, 10, 0),
                                      data.brow_size, data.hair_col(70))
        self.brow_right_middle.set_gap(5 + data.brow_length, self.eye_right)
        self.brow_right_outer = Ball(
            self.eye_right - (0, 10, -data.brow_length), data.brow_size,
            data.hair_col(50))
        self.brow_right_outer.set_gap(5 - mood_delta, self.eye_right)
Example #7
0
    def __init__(self, data):
        super(Unicorn, self).__init__()

        self.head = Ball((0, 0, 0), data.head_size, data.body_col(60))
        self.snout = Ball((-25, 60, 0), data.snout_size, data.body_col(80))
        self.snout.set_distance(data.snout_length, self.head)
        self.shoulder = Ball((80, 120, 0), data.shoulder_size,
                             data.body_col(40))
        self.butt = Ball((235, 155, 0), data.butt_size, data.body_col(40))
        self.horn_onset = Ball((-22, -10, 0), data.horn_onset_size,
                               data.horn_col(70))
        self.horn_onset.move_to_sphere(self.head)

        self.horn_tip = Ball(self.horn_onset - (10, 0, 0), data.horn_tip_size,
                             data.horn_col(90))
        self.horn_tip.set_distance(data.horn_length, self.horn_onset)
        self.horn_tip.rotate(data.horn_angle, self.horn_onset)

        self.create_eyes(data)
        self.create_legs(data)

        pose_functions[data.pose_kind](self, data)

        self.create_mane(data)

        self.tail_start = Ball(self.butt - (-10, 10, 0), data.tail_start_size,
                               data.hair_col(80))
        self.tail_start.move_to_sphere(self.butt)
        self.tail_end = Ball(self.tail_start - (-10, 0, 0), data.tail_end_size,
                             data.hair_col(60))
        self.tail_end.set_distance(data.tail_length, self.tail_start)
        self.tail_end.rotate(data.tail_angle, self.tail_start)
        self.tail = NonLinBone(self.tail_start,
                               self.tail_end,
                               yfunc=gammafunc(data.tail_gamma))

        square = gammafunc(2)

        self.add(
            Bone(self.snout, self.head),
            Bone(self.horn_onset, self.horn_tip),
            Bone(self.eye_left, self.iris_left),
            Bone(self.eye_right, self.iris_right),
            self.pupil_left,
            self.pupil_right,
            NonLinBone(self.brow_left_inner,
                       self.brow_left_middle,
                       xfunc=square),
            NonLinBone(self.brow_left_middle,
                       self.brow_left_outer,
                       xfunc=math.sqrt),
            NonLinBone(self.brow_right_inner,
                       self.brow_right_middle,
                       xfunc=square),
            NonLinBone(self.brow_right_middle,
                       self.brow_right_outer,
                       xfunc=math.sqrt),
        )

        for thing in self.ball_set():
            thing.rotate(data.face_tilt, self.head, axis=0)

        self.add(Bone(self.head, self.shoulder), self.hairs)

        for thing in self.ball_set():
            thing.rotate(data.neck_tilt, self.shoulder, axis=1)

        self.add(
            Bone(self.shoulder, self.butt),
            self.tail,
        )

        for leg in self.legs[:2]:
            self.add(*leg)

        for leg in self.legs[2:]:
            self.add(*leg)
Example #8
0
class Unicorn(Figure):
    def __init__(self, data):
        super(Unicorn, self).__init__()

        self.head = Ball((0, 0, 0), data.head_size, data.body_col(60))
        self.snout = Ball((-25, 60, 0), data.snout_size, data.body_col(80))
        self.snout.set_distance(data.snout_length, self.head)
        self.shoulder = Ball((80, 120, 0), data.shoulder_size,
                             data.body_col(40))
        self.butt = Ball((235, 155, 0), data.butt_size, data.body_col(40))
        self.horn_onset = Ball((-22, -10, 0), data.horn_onset_size,
                               data.horn_col(70))
        self.horn_onset.move_to_sphere(self.head)

        self.horn_tip = Ball(self.horn_onset - (10, 0, 0), data.horn_tip_size,
                             data.horn_col(90))
        self.horn_tip.set_distance(data.horn_length, self.horn_onset)
        self.horn_tip.rotate(data.horn_angle, self.horn_onset)

        self.create_eyes(data)
        self.create_legs(data)

        pose_functions[data.pose_kind](self, data)

        self.create_mane(data)

        self.tail_start = Ball(self.butt - (-10, 10, 0), data.tail_start_size,
                               data.hair_col(80))
        self.tail_start.move_to_sphere(self.butt)
        self.tail_end = Ball(self.tail_start - (-10, 0, 0), data.tail_end_size,
                             data.hair_col(60))
        self.tail_end.set_distance(data.tail_length, self.tail_start)
        self.tail_end.rotate(data.tail_angle, self.tail_start)
        self.tail = NonLinBone(self.tail_start,
                               self.tail_end,
                               yfunc=gammafunc(data.tail_gamma))

        square = gammafunc(2)

        self.add(
            Bone(self.snout, self.head),
            Bone(self.horn_onset, self.horn_tip),
            Bone(self.eye_left, self.iris_left),
            Bone(self.eye_right, self.iris_right),
            self.pupil_left,
            self.pupil_right,
            NonLinBone(self.brow_left_inner,
                       self.brow_left_middle,
                       xfunc=square),
            NonLinBone(self.brow_left_middle,
                       self.brow_left_outer,
                       xfunc=math.sqrt),
            NonLinBone(self.brow_right_inner,
                       self.brow_right_middle,
                       xfunc=square),
            NonLinBone(self.brow_right_middle,
                       self.brow_right_outer,
                       xfunc=math.sqrt),
        )

        for thing in self.ball_set():
            thing.rotate(data.face_tilt, self.head, axis=0)

        self.add(Bone(self.head, self.shoulder), self.hairs)

        for thing in self.ball_set():
            thing.rotate(data.neck_tilt, self.shoulder, axis=1)

        self.add(
            Bone(self.shoulder, self.butt),
            self.tail,
        )

        for leg in self.legs[:2]:
            self.add(*leg)

        for leg in self.legs[2:]:
            self.add(*leg)

    def create_eyes(self, data):
        self.eye_left = Ball((-10, 3, -5), data.eye_size, (255, 255, 255))
        self.eye_left.set_gap(5, self.head)
        self.eye_right = Ball((-10, 3, 5), data.eye_size, (255, 255, 255))
        self.eye_right.set_gap(5, self.head)

        self.iris_left = Ball(self.eye_left - (4, 0, 0), data.iris_size,
                              data.iris_col(80))
        self.iris_right = Ball(self.eye_right - (4, 0, 0), data.iris_size,
                               data.iris_col(80))

        self.pupil_left = Ball(self.iris_left - (10, 0, 0), data.pupil_size,
                               (0, 0, 0))
        self.pupil_left.move_to_sphere(self.iris_left)
        self.pupil_right = Ball(self.iris_right - (10, 0, 0), data.pupil_size,
                                (0, 0, 0))
        self.pupil_right.move_to_sphere(self.iris_right)

        mood_delta = data.brow_mood * 3

        self.brow_left_inner = Ball(self.eye_left - (0, 10, -data.brow_length),
                                    data.brow_size, data.hair_col(50))
        self.brow_left_inner.set_gap(5 + mood_delta, self.eye_left)
        self.brow_left_middle = Ball(self.eye_left - (0, 10, 0),
                                     data.brow_size, data.hair_col(70))
        self.brow_left_middle.set_gap(5 + data.brow_length, self.eye_left)
        self.brow_left_outer = Ball(self.eye_left - (0, 10, data.brow_length),
                                    data.brow_size, data.hair_col(60))
        self.brow_left_outer.set_gap(5 - mood_delta, self.eye_left)
        self.brow_right_inner = Ball(
            self.eye_right - (0, 10, data.brow_length), data.brow_size,
            data.hair_col(60))
        self.brow_right_inner.set_gap(5 + mood_delta, self.eye_right)
        self.brow_right_middle = Ball(self.eye_right - (0, 10, 0),
                                      data.brow_size, data.hair_col(70))
        self.brow_right_middle.set_gap(5 + data.brow_length, self.eye_right)
        self.brow_right_outer = Ball(
            self.eye_right - (0, 10, -data.brow_length), data.brow_size,
            data.hair_col(50))
        self.brow_right_outer.set_gap(5 - mood_delta, self.eye_right)

    def create_legs(self, data):
        self.legs = []  # order: front left, front right, back left, back right

        for z in (-25, 25):  # front
            hip = Ball((55, 160, z), 25, data.body_col(40))
            knee = Ball((35, 254, z), 9, data.body_col(70))
            hoof = Ball((55, 310, z), 11, data.body_col(45))
            hip.move_to_sphere(self.shoulder)
            leg = Leg(hip, knee, hoof)
            self.legs.append(leg)

        for z in (-25, 25):  # back
            hip = Ball((225, 190, z), 25, data.body_col(40))
            knee = Ball((230, 265, z), 9, data.body_col(70))
            hoof = Ball((220, 310, z), 11, data.body_col(45))
            hip.move_to_sphere(self.butt)
            leg = Leg(hip, knee, hoof)
            self.legs.append(leg)

    def create_mane(self, data):
        self.hairs = Figure()

        hair_top = Ball(self.head - (-10, 5, 0), 8, None)
        hair_top.move_to_sphere(self.head)
        hair_bottom = Ball(self.shoulder - (-10, 15, 0), 8, None)
        hair_bottom.move_to_sphere(self.shoulder)
        for start, gamma, length, angle, lightness, straightness in zip(
                data.hair_starts, data.hair_gammas, data.hair_lengths,
                data.hair_angles, data.hair_tip_lightnesses,
                data.hair_straightnesses):
            x, y, z = (c[0] + start / 100.0 * (c[1] - c[0])
                       for c in zip(hair_top.center, hair_bottom.center))
            hair_start = Ball((x, y, z), 8, data.hair_col(60))
            hair_end = Ball((x + length, y, z + straightness), 4,
                            data.hair_col(lightness))
            hair_end.rotate(-angle, hair_start)
            hair = NonLinBone(hair_start, hair_end, yfunc=gammafunc(gamma))
            self.hairs.add(hair)
Example #9
0
    def __init__(self, data):
        super(Unicorn, self).__init__()
        
        self.head = Ball((0,0,0), data.head_size, data.body_col(60))
        self.snout = Ball((-25, 60, 0), data.snout_size, data.body_col(80))
        self.snout.set_distance(data.snout_length, self.head)
        self.shoulder = Ball((80, 120, 0), data.shoulder_size, data.body_col(40))
        self.butt = Ball((235, 155, 0), data.butt_size, data.body_col(40))
        self.horn_onset = Ball((-22, -10, 0), data.horn_onset_size, data.horn_col(70))
        self.horn_onset.move_to_sphere(self.head)
        
        self.horn_tip = Ball(self.horn_onset - (10, 0, 0), data.horn_tip_size, data.horn_col(90))
        self.horn_tip.set_distance(data.horn_length, self.horn_onset)
        self.horn_tip.rotate(data.horn_angle, self.horn_onset)

        self.create_eyes(data)
        self.create_legs(data)
        
        pose_functions[data.pose_kind](self, data)

        self.create_mane(data)

        self.tail_start = Ball(self.butt - (-10, 10, 0), data.tail_start_size, data.hair_col(80))
        self.tail_start.move_to_sphere(self.butt)
        self.tail_end = Ball(self.tail_start - (-10, 0, 0), data.tail_end_size, data.hair_col(60))
        self.tail_end.set_distance(data.tail_length, self.tail_start)
        self.tail_end.rotate(data.tail_angle, self.tail_start)
        self.tail = NonLinBone(self.tail_start, self.tail_end, yfunc = gammafunc(data.tail_gamma))
        
        square = gammafunc(2)

        self.add(Bone(self.snout, self.head),
                 Bone(self.horn_onset, self.horn_tip),
                 Bone(self.eye_left, self.iris_left),
                 Bone(self.eye_right, self.iris_right),
                 self.pupil_left, self.pupil_right,
                 NonLinBone(self.brow_left_inner, self.brow_left_middle, xfunc = square),
                 NonLinBone(self.brow_left_middle, self.brow_left_outer, xfunc = math.sqrt),
                 NonLinBone(self.brow_right_inner, self.brow_right_middle, xfunc = square),
                 NonLinBone(self.brow_right_middle, self.brow_right_outer, xfunc = math.sqrt),
                )

        for thing in self.ball_set():
            thing.rotate(data.face_tilt, self.head, axis = 0)

        self.add(Bone(self.head, self.shoulder),
                 self.hairs
                )

        for thing in self.ball_set():
            thing.rotate(data.neck_tilt, self.shoulder, axis = 1)

        self.add(Bone(self.shoulder, self.butt),
                 self.tail,
                )

        for leg in self.legs[:2]:
            self.add(*leg)
            
        for leg in self.legs[2:]:
            self.add(*leg)
Example #10
0
class Unicorn(Figure):
    
    def __init__(self, data):
        super(Unicorn, self).__init__()
        
        self.head = Ball((0,0,0), data.head_size, data.body_col(60))
        self.snout = Ball((-25, 60, 0), data.snout_size, data.body_col(80))
        self.snout.set_distance(data.snout_length, self.head)
        self.shoulder = Ball((80, 120, 0), data.shoulder_size, data.body_col(40))
        self.butt = Ball((235, 155, 0), data.butt_size, data.body_col(40))
        self.horn_onset = Ball((-22, -10, 0), data.horn_onset_size, data.horn_col(70))
        self.horn_onset.move_to_sphere(self.head)
        
        self.horn_tip = Ball(self.horn_onset - (10, 0, 0), data.horn_tip_size, data.horn_col(90))
        self.horn_tip.set_distance(data.horn_length, self.horn_onset)
        self.horn_tip.rotate(data.horn_angle, self.horn_onset)

        self.create_eyes(data)
        self.create_legs(data)
        
        pose_functions[data.pose_kind](self, data)

        self.create_mane(data)

        self.tail_start = Ball(self.butt - (-10, 10, 0), data.tail_start_size, data.hair_col(80))
        self.tail_start.move_to_sphere(self.butt)
        self.tail_end = Ball(self.tail_start - (-10, 0, 0), data.tail_end_size, data.hair_col(60))
        self.tail_end.set_distance(data.tail_length, self.tail_start)
        self.tail_end.rotate(data.tail_angle, self.tail_start)
        self.tail = NonLinBone(self.tail_start, self.tail_end, yfunc = gammafunc(data.tail_gamma))
        
        square = gammafunc(2)

        self.add(Bone(self.snout, self.head),
                 Bone(self.horn_onset, self.horn_tip),
                 Bone(self.eye_left, self.iris_left),
                 Bone(self.eye_right, self.iris_right),
                 self.pupil_left, self.pupil_right,
                 NonLinBone(self.brow_left_inner, self.brow_left_middle, xfunc = square),
                 NonLinBone(self.brow_left_middle, self.brow_left_outer, xfunc = math.sqrt),
                 NonLinBone(self.brow_right_inner, self.brow_right_middle, xfunc = square),
                 NonLinBone(self.brow_right_middle, self.brow_right_outer, xfunc = math.sqrt),
                )

        for thing in self.ball_set():
            thing.rotate(data.face_tilt, self.head, axis = 0)

        self.add(Bone(self.head, self.shoulder),
                 self.hairs
                )

        for thing in self.ball_set():
            thing.rotate(data.neck_tilt, self.shoulder, axis = 1)

        self.add(Bone(self.shoulder, self.butt),
                 self.tail,
                )

        for leg in self.legs[:2]:
            self.add(*leg)
            
        for leg in self.legs[2:]:
            self.add(*leg)

    def create_eyes(self, data):
        self.eye_left = Ball((-10, 3, -5), data.eye_size, (255, 255, 255))
        self.eye_left.set_gap(5, self.head)
        self.eye_right = Ball((-10, 3, 5), data.eye_size, (255, 255, 255))
        self.eye_right.set_gap(5, self.head)

        self.iris_left = Ball(self.eye_left - (4, 0, 0), data.iris_size, data.iris_col(80))
        self.iris_right = Ball(self.eye_right - (4, 0, 0), data.iris_size, data.iris_col(80))

        self.pupil_left = Ball(self.iris_left - (10, 0, 0), data.pupil_size, (0, 0, 0))
        self.pupil_left.move_to_sphere(self.iris_left)
        self.pupil_right = Ball(self.iris_right - (10, 0, 0), data.pupil_size, (0, 0, 0))
        self.pupil_right.move_to_sphere(self.iris_right)

        mood_delta = data.brow_mood * 3
        
        self.brow_left_inner = Ball(self.eye_left - (0, 10, -data.brow_length), data.brow_size, data.hair_col(50))
        self.brow_left_inner.set_gap(5 + mood_delta, self.eye_left)
        self.brow_left_middle = Ball(self.eye_left - (0, 10, 0), data.brow_size, data.hair_col(70))
        self.brow_left_middle.set_gap(5 + data.brow_length, self.eye_left)
        self.brow_left_outer = Ball(self.eye_left - (0, 10, data.brow_length), data.brow_size, data.hair_col(60))
        self.brow_left_outer.set_gap(5 - mood_delta, self.eye_left)
        self.brow_right_inner = Ball(self.eye_right - (0, 10, data.brow_length), data.brow_size, data.hair_col(60))
        self.brow_right_inner.set_gap(5 + mood_delta, self.eye_right)
        self.brow_right_middle = Ball(self.eye_right - (0, 10, 0), data.brow_size, data.hair_col(70))
        self.brow_right_middle.set_gap(5 + data.brow_length, self.eye_right)
        self.brow_right_outer = Ball(self.eye_right - (0, 10, -data.brow_length), data.brow_size, data.hair_col(50))
        self.brow_right_outer.set_gap(5 - mood_delta, self.eye_right)

    def create_legs(self, data):
        self.legs = [] # order: front left, front right, back left, back right

        for z in (-25, 25): # front
            hip = Ball((55, 160, z), 25, data.body_col(40))
            knee = Ball((35, 254, z), 9, data.body_col(70))
            hoof = Ball((55, 310, z), 11, data.body_col(45))
            hip.move_to_sphere(self.shoulder)
            leg = Leg(hip, knee, hoof)
            self.legs.append(leg)

        for z in (-25, 25): # back
            hip = Ball((225, 190, z), 25, data.body_col(40))
            knee = Ball((230, 265, z), 9, data.body_col(70))
            hoof = Ball((220, 310, z), 11, data.body_col(45))
            hip.move_to_sphere(self.butt)
            leg = Leg(hip, knee, hoof)
            self.legs.append(leg)

    def create_mane(self, data):
        self.hairs = Figure()

        hair_top = Ball(self.head - (-10, 5, 0), 8, None)
        hair_top.move_to_sphere(self.head)
        hair_bottom = Ball(self.shoulder - (-10, 15, 0), 8, None)
        hair_bottom.move_to_sphere(self.shoulder)        
        for start, gamma, length, angle, lightness, straightness in zip(
                        data.hair_starts, data.hair_gammas, data.hair_lengths,
                        data.hair_angles, data.hair_tip_lightnesses,
                        data.hair_straightnesses):
            x, y, z = (c[0] + start / 100.0 * (c[1] - c[0]) for c in zip(hair_top.center, hair_bottom.center))
            hair_start = Ball((x, y, z), 8, data.hair_col(60))
            hair_end = Ball((x + length, y, z + straightness), 4, data.hair_col(lightness))
            hair_end.rotate(-angle, hair_start)
            hair = NonLinBone(hair_start, hair_end, yfunc = gammafunc(gamma))
            self.hairs.add(hair)