Clutter を回転させてみる

Clutter-1.12.0 から回転方法が変更されています。以前は x,y 軸の回転と z 軸の回転は別の関数だったのですが、今回からは全部同じ clutter_actor_set_rotation_angle() という関数になっていて、 回転する ClutterActor 、回転軸、回転角度を指定します。回転の中心は pivot-point と pivot-point-z になるようで、それぞれ clutter_actor_set_pivot_point() と clutter_actor_set_pivot_point_z() で指定するようです。z 無しは、 0.0 から 1.0 の正規化した値(縦横を1とする)にするみたいですが、 z 付きは z 軸に沿った距離とマニュアルに書かれています。指定しなければ、デフォルトは 0.0 になっているようです。今回は指定せずに、ぐるぐる回してみます。
まずは C です。

#include <clutter/clutter.h>

void
on_completed (ClutterTimeline *timeline, gpointer user_data) 
{
    ClutterActor *actor;
    gdouble angle;
    static ClutterRotateAxis axis = CLUTTER_X_AXIS;

    actor = * (ClutterActor**)user_data;
    clutter_actor_save_easing_state (actor);

    angle = clutter_actor_get_rotation_angle (actor, axis);
    angle += 30;
    if (angle >= 360)
        angle = 0;
    clutter_actor_set_rotation_angle (actor, axis, angle);
    if (axis == CLUTTER_X_AXIS)
        axis = CLUTTER_Y_AXIS;
    else if (axis == CLUTTER_Y_AXIS)
        axis = CLUTTER_Z_AXIS;
    else
        axis = CLUTTER_X_AXIS;
    clutter_actor_restore_easing_state (actor);
}

int
main (int argc, char *argv[])
{
    ClutterStage *stage;
    ClutterActor *actor;
    ClutterTimeline *timeline;
    
    if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
        return 1;
    stage = (ClutterStage*) clutter_stage_new ();
    g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);

    actor = clutter_actor_new ();
    clutter_actor_set_background_color (actor, clutter_color_get_static (CLUTTER_COLOR_RED));
    clutter_actor_set_size (actor, 100, 100);
    clutter_actor_set_position (actor, 100, 100);
    
    timeline = clutter_timeline_new (1000);
    clutter_timeline_set_repeat_count (timeline, -1);
    g_signal_connect (timeline, "completed", G_CALLBACK (on_completed), &actor);
    clutter_timeline_start (timeline);

    clutter_actor_add_child ((ClutterActor*) stage, actor);
    clutter_actor_show ((ClutterActor*) stage);
    clutter_main ();
    return 0;
}

説明するまでもなく、 1000ms 単位でぐるぐる回ります。easing_state を使っているので、アニメーションになっています。 360度のときは 0度にするので、その時に一気に変化するのが解ると思います。

次は Gjs ですが、こちらもソースだけで説明はしません。

#! /usr/bin/env gjs
const Clutter = imports.gi.Clutter;

let axis = Clutter.RotateAxis.X_AXIS;

function on_completed (timeline) 
{
    actor.save_easing_state();
    angle = actor.get_rotation_angle(axis);
    angle += 30;
    if (angle >= 360)
        angle = 0;
    actor.set_rotation_angle(axis, angle);
    if (axis == Clutter.RotateAxis.X_AXIS)
        axis = Clutter.RotateAxis.Y_AXIS;
    else if (axis == Clutter.RotateAxis.Y_AXIS)
        axis = Clutter.RotateAxis.Z_AXIS;
    else
        axis = Clutter.RotateAxis.X_AXIS;
    actor.restore_easing_state();
}

Clutter.init(null);
let stage = new Clutter.Stage();
stage.connect('destroy', Clutter.main_quit);

let actor = new Clutter.Actor();
actor.set_background_color(Clutter.Color.get_static (Clutter.StaticColor.RED));
actor.set_size(100, 100);
actor.set_position(100, 100);

let timeline = new Clutter.Timeline({duration:1000});
timeline.set_repeat_count(-1);
timeline.connect('completed', on_completed);
timeline.start();

stage.add_child(actor);
stage.show();
Clutter.main();