}
/**
+ * clutter_actor_move_by
+ * @self: A #ClutterActor
+ * @dx: Distance to move Actor on X axis.
+ * @dy: Distance to move Actor on Y axis.
+ *
+ * Moves an actor by specified distance relative to
+ * current position.
+ *
+ * Since: 0.2
+ */
+void
+clutter_actor_move_by (ClutterActor *self,
+ gint dx,
+ gint dy)
+{
+ ClutterActorBox box;
+
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+ clutter_actor_allocate_coords (self, &box);
+
+ box.x2 += dx;
+ box.y2 += dy;
+ box.x1 += dx;
+ box.y1 += dy;
+
+ clutter_actor_request_coords (self, &box);
+}
+
+/**
* clutter_actor_set_size
* @self: A #ClutterActor
* @width: New width of actor in pixels
clutter_actor_request_coords (self, &box);
}
+/*
+ * clutter_actor_get_size
+ * @self: A #ClutterActor
+ * @x: Location to store width if non NULL.
+ * @y: Location to store height if non NULL.
+ *
+ * Gets the size of an actor ignoring any scaling factors
+ *
+ * Since: 0.2
+ */
+void
+clutter_actor_get_size (ClutterActor *self,
+ guint *width,
+ guint *height)
+{
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+ if (width)
+ *width = clutter_actor_get_width(self);
+ if (height)
+ *height = clutter_actor_get_height(self);
+}
+
/**
* clutter_actor_get_abs_position
* @self: A #ClutterActor
guint *width,
guint *height);
+void
+clutter_actor_get_size (ClutterActor *self,
+ guint *width,
+ guint *height);
+
+void
+clutter_actor_move_by (ClutterActor *self,
+ gint dx,
+ gint dy);
+
G_END_DECLS
#endif
#include "clutter-alpha.h"
#include "clutter-main.h"
#include "clutter-marshal.h"
+#include <math.h>
G_DEFINE_TYPE (ClutterAlpha, clutter_alpha, G_TYPE_OBJECT);
}
}
+guint32
+clutter_alpha_sine_func (ClutterAlpha *alpha)
+{
+ int current_frame_num, nframes;
+ double x;
+
+ current_frame_num =
+ clutter_timeline_get_current_frame (alpha->priv->timeline);
+ nframes =
+ clutter_timeline_get_n_frames (alpha->priv->timeline);
+
+ /* FIXME: fixed point, and fixed point sine() */
+
+ x = (double)(current_frame_num * 2.0f * M_PI) / nframes ;
+
+ printf("%2f\n", ((sin(x-(M_PI/2.0f)) + 1.0f ) * 0.5f ));
+
+ return (guint32) (((sin(x-(M_PI/2.0f)) + 1.0f ) * 0.5f ) * (double)CLUTTER_ALPHA_MAX_ALPHA);
+}
+
/* Object */
static void
guint32
clutter_alpha_ramp_func (ClutterAlpha *alpha);
+guint32
+clutter_alpha_sine_func (ClutterAlpha *alpha);
+
#define CLUTTER_ALPHA_RAMP_INC clutter_alpha_ramp_inc_func
#define CLUTTER_ALPHA_RAMP_DEC clutter_alpha_ramp_dec_func
#define CLUTTER_ALPHA_RAMP clutter_alpha_ramp_func
+#define CLUTTER_ALPHA_SINE clutter_alpha_sine_func
G_END_DECLS
/**
* SECTION:clutter-behaviour
- * @short_description: Class for providing behaviours to actors
+ * @short_description: Class for providing common behaviours to actors
*
*/
+/* TODO:
+ * o Document
+ * o Add props
+ * o Optimise
+ */
+
#include "config.h"
#include "clutter-actor.h"
guint index)
{
/* FIXME: implement */
+ return NULL;
}
void
}
static void
-clutter_behaviour_alpha_notify (ClutterBehaviour *behave)
+clutter_behaviour_opacity_alpha_notify (ClutterBehaviour *behave)
{
clutter_behaviour_actors_foreach
(behave,
behave_class = (ClutterBehaviourClass*) klass;
- behave_class->alpha_notify = clutter_behaviour_alpha_notify;
+ behave_class->alpha_notify = clutter_behaviour_opacity_alpha_notify;
g_type_class_add_private (object_class, sizeof (ClutterBehaviourOpacityPrivate));
}
return CLUTTER_BEHAVIOUR(behave);
}
+/*
+ * ====================== Scale ============================
+ */
+
+G_DEFINE_TYPE (ClutterBehaviourScale, \
+ clutter_behaviour_scale, \
+ CLUTTER_TYPE_BEHAVIOUR);
+
+struct ClutterBehaviourScalePrivate
+{
+ ClutterFixed scale_begin;
+ ClutterFixed scale_end;
+ ClutterGravity gravity;
+};
+
+#define CLUTTER_BEHAVIOUR_SCALE_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+ CLUTTER_TYPE_BEHAVIOUR_SCALE, \
+ ClutterBehaviourScalePrivate))
+
+static void
+clutter_behaviour_scale_frame_foreach (ClutterActor *actor,
+ ClutterBehaviourScale *behave)
+{
+ ClutterFixed scale, factor;
+ guint32 alpha;
+ ClutterBehaviourScalePrivate *priv;
+ ClutterBehaviour *_behave;
+ gint sw, sh, w, h;
+
+ priv = CLUTTER_BEHAVIOUR_SCALE_GET_PRIVATE (behave);
+ _behave = CLUTTER_BEHAVIOUR (behave);
+
+ alpha = clutter_alpha_get_alpha (clutter_behaviour_get_alpha (_behave));
+
+ /* FIXME: use all fixed if possible
+ factor = CLUTTER_FIXED_DIV(CLUTTER_INT_TO_FIXED(alpha/2),
+ CLUTTER_INT_TO_FIXED(CLUTTER_ALPHA_MAX_ALPHA/2));
+ */
+
+ factor = CLUTTER_FLOAT_TO_FIXED((double) alpha / CLUTTER_ALPHA_MAX_ALPHA);
+
+ scale = CLUTTER_FIXED_MUL(factor, (priv->scale_end - priv->scale_begin));
+
+ scale += priv->scale_begin;
+
+ clutter_actor_set_scalex (actor, scale, scale);
+
+ if (priv->gravity == CLUTTER_GRAVITY_NONE
+ || priv->gravity == CLUTTER_GRAVITY_NORTH_WEST)
+ return;
+
+ clutter_actor_get_abs_size (actor, (guint*)&sw, (guint*)&sh);
+ clutter_actor_get_size (actor, (guint*)&w, (guint*)&h);
+
+ switch (priv->gravity)
+ {
+ case CLUTTER_GRAVITY_NORTH:
+ break;
+ case CLUTTER_GRAVITY_NORTH_EAST:
+ break;
+ case CLUTTER_GRAVITY_EAST:
+ break;
+ case CLUTTER_GRAVITY_SOUTH_EAST:
+ break;
+ case CLUTTER_GRAVITY_SOUTH:
+ break;
+ case CLUTTER_GRAVITY_SOUTH_WEST:
+ break;
+ case CLUTTER_GRAVITY_WEST:
+ break;
+ case CLUTTER_GRAVITY_CENTER:
+ printf("%i vs %i\n", sw, w);
+ clutter_actor_move_by (actor, sw - w, sh - h);
+ default:
+ break;
+ }
+}
+
+static void
+clutter_behaviour_scale_alpha_notify (ClutterBehaviour *behave)
+{
+ clutter_behaviour_actors_foreach
+ (behave,
+ (GFunc)clutter_behaviour_scale_frame_foreach,
+ CLUTTER_BEHAVIOUR_SCALE(behave));
+}
+
+static void
+clutter_behaviour_scale_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (clutter_behaviour_scale_parent_class)->dispose (object);
+}
+
+static void
+clutter_behaviour_scale_finalize (GObject *object)
+{
+ ClutterBehaviourScale *self = CLUTTER_BEHAVIOUR_SCALE(object);
+
+ if (self->priv)
+ {
+ g_free(self->priv);
+ self->priv = NULL;
+ }
+
+ G_OBJECT_CLASS (clutter_behaviour_scale_parent_class)->finalize (object);
+}
+
+
+static void
+clutter_behaviour_scale_class_init (ClutterBehaviourScaleClass *klass)
+{
+ GObjectClass *object_class;
+ ClutterBehaviourClass *behave_class;
+
+ object_class = (GObjectClass*) klass;
+
+ object_class->finalize = clutter_behaviour_scale_finalize;
+ object_class->dispose = clutter_behaviour_scale_dispose;
+
+ behave_class = (ClutterBehaviourClass*) klass;
+
+ behave_class->alpha_notify = clutter_behaviour_scale_alpha_notify;
+
+ g_type_class_add_private (object_class, sizeof (ClutterBehaviourScalePrivate));
+}
+
+static void
+clutter_behaviour_scale_init (ClutterBehaviourScale *self)
+{
+ ClutterBehaviourScalePrivate *priv;
+
+ self->priv = priv = CLUTTER_BEHAVIOUR_SCALE_GET_PRIVATE (self);
+}
+
+ClutterBehaviour*
+clutter_behaviour_scale_new (ClutterAlpha *alpha,
+ double scale_begin,
+ double scale_end,
+ ClutterGravity gravity)
+{
+ ClutterBehaviourScale *behave;
+
+ behave = g_object_new (CLUTTER_TYPE_BEHAVIOUR_SCALE,
+ "alpha", alpha,
+ NULL);
+
+ behave->priv->scale_begin = CLUTTER_FLOAT_TO_FIXED (scale_begin);
+ behave->priv->scale_end = CLUTTER_FLOAT_TO_FIXED (scale_end);
+ behave->priv->gravity = gravity;
+
+ return CLUTTER_BEHAVIOUR(behave);
+}
const ClutterKnot *first_knot,
...);
-/* opacity */
+/* ============================ opacity ======================== */
#define CLUTTER_TYPE_BEHAVIOUR_OPACITY clutter_behaviour_opacity_get_type()
guint8 opacity_start,
guint8 opacity_end);
+/* ============================ scale ======================== */
+
+#define CLUTTER_TYPE_BEHAVIOUR_SCALE clutter_behaviour_scale_get_type()
+
+#define CLUTTER_BEHAVIOUR_SCALE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ CLUTTER_TYPE_BEHAVIOUR_SCALE, ClutterBehaviourScale))
+
+#define CLUTTER_BEHAVIOUR_SCALE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ CLUTTER_TYPE_BEHAVIOUR_SCALE, ClutterBehaviourScaleClass))
+
+#define CLUTTER_IS_BEHAVIOUR_SCALE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ CLUTTER_TYPE_BEHAVIOUR_SCALE))
+
+#define CLUTTER_IS_BEHAVIOUR_SCALE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ CLUTTER_TYPE_BEHAVIOUR_SCALE))
+
+#define CLUTTER_BEHAVIOUR_SCALE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ CLUTTER_TYPE_BEHAVIOUR_SCALE, ClutterBehaviourScaleClass))
+
+typedef struct _ClutterBehaviourScale ClutterBehaviourScale;
+typedef struct ClutterBehaviourScalePrivate ClutterBehaviourScalePrivate;
+typedef struct _ClutterBehaviourScaleClass ClutterBehaviourScaleClass;
+
+struct _ClutterBehaviourScale
+{
+ ClutterBehaviour parent;
+ ClutterBehaviourScalePrivate *priv;
+};
+
+struct _ClutterBehaviourScaleClass
+{
+ ClutterBehaviourClass parent_class;
+};
+
+typedef enum {
+ CLUTTER_GRAVITY_NONE = 0,
+ CLUTTER_GRAVITY_NORTH,
+ CLUTTER_GRAVITY_NORTH_EAST,
+ CLUTTER_GRAVITY_EAST,
+ CLUTTER_GRAVITY_SOUTH_EAST,
+ CLUTTER_GRAVITY_SOUTH,
+ CLUTTER_GRAVITY_SOUTH_WEST,
+ CLUTTER_GRAVITY_WEST,
+ CLUTTER_GRAVITY_NORTH_WEST,
+ CLUTTER_GRAVITY_CENTER
+} ClutterGravity;
+
+GType clutter_behaviour_scale_get_type (void);
+
+ClutterBehaviour*
+clutter_behaviour_scale_new (ClutterAlpha *alpha,
+ double scale_begin,
+ double scale_end,
+ ClutterGravity gravity);
+
+
G_END_DECLS
#endif
*/
#include "config.h"
+#include "clutter-main.h"
#include "clutter-feature.h"
-#include "string.h"
-static ClutterFeatureFlags __features = -1;
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+
+ #include <dlfcn.h>
+
+typedef void (*FuncPtr) (void);
+typedef int (*GLXGetVideoSyncProc) (unsigned int *count);
+typedef int (*GLXWaitVideoSyncProc) (int divisor,
+ int remainder,
+ unsigned int *count);
+typedef FuncPtr (*GLXGetProcAddressProc) (const guint8 *procName);
+
+typedef struct ClutterFeatureFuncs
+{
+ GLXGetVideoSyncProc get_video_sync;
+ GLXWaitVideoSyncProc wait_video_sync;
+
+} ClutterFeatureFuncs;
+
+typedef enum ClutterVBlankType
+{
+ CLUTTER_VBLANK_NONE = 0,
+ CLUTTER_VBLANK_GLX,
+ CLUTTER_VBLANK_DRI
+
+} ClutterVBlankType;
+
+typedef struct ClutterFeatures
+{
+ ClutterFeatureFlags flags;
+ ClutterFeatureFuncs funcs;
+ gint dri_fd;
+ ClutterVBlankType vblank_type;
+
+} ClutterFeatures;
+
+static ClutterFeatures* __features = NULL;
+
+/* #ifdef linux */
+#define DRM_VBLANK_RELATIVE 0x1;
+
+struct drm_wait_vblank_request {
+ int type;
+ unsigned int sequence;
+ unsigned long signal;
+};
+
+struct drm_wait_vblank_reply {
+ int type;
+ unsigned int sequence;
+ long tval_sec;
+ long tval_usec;
+};
+
+typedef union drm_wait_vblank {
+ struct drm_wait_vblank_request request;
+ struct drm_wait_vblank_reply reply;
+} drm_wait_vblank_t;
+
+#define DRM_IOCTL_BASE 'd'
+#define DRM_IOWR(nr,type) _IOWR(DRM_IOCTL_BASE,nr,type)
+#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t)
+
+static int drm_wait_vblank(int fd, drm_wait_vblank_t *vbl)
+{
+ int ret, rc;
+
+ do
+ {
+ ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
+ vbl->request.type &= ~DRM_VBLANK_RELATIVE;
+ rc = errno;
+ }
+ while (ret && rc == EINTR);
+
+ return rc;
+}
+
+/* #endif */
+
/* Note must be called after context created */
static gboolean
-check_gl_extension (const gchar *name)
+check_gl_extension (const gchar *name, const gchar *ext)
{
- const gchar *ext;
gchar *end;
gint name_len, n;
- ext = (const gchar*)glGetString(GL_EXTENSIONS);
-
if (name == NULL || ext == NULL)
return FALSE;
return FALSE;
}
+static FuncPtr
+get_proc_address (const gchar *name)
+{
+ static GLXGetProcAddressProc get_proc_func = NULL;
+ static void *dlhand = NULL;
+
+ if (get_proc_func == NULL && dlhand == NULL)
+ {
+ dlhand = dlopen (NULL, RTLD_LAZY);
+
+ if (dlhand)
+ {
+ dlerror ();
+ get_proc_func
+ = (GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddress");
+ if (dlerror () != NULL)
+ get_proc_func
+ = (GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddressARB");
+ if (dlerror () != NULL)
+ {
+ get_proc_func = NULL;
+ g_warning
+ ("failed to bind GLXGetProcAddress or GLXGetProcAddressARB");
+ }
+ }
+ }
+
+ if (get_proc_func)
+ return get_proc_func ((unsigned char*)name);
+
+ return NULL;
+}
+
+
+static gboolean
+check_vblank_env (const char *name)
+{
+ const char *val;
+
+ val = getenv("CLUTTER_VBLANK");
+
+ if (val && !strcasecmp(val, name))
+ return TRUE;
+
+ return FALSE;
+}
+
void
clutter_feature_init (void)
{
- if (__features != -1)
+ const gchar *gl_extensions, *glx_extensions;
+
+ if (__features != NULL)
{
g_warning ("You should never call clutter_feature_init() "
"more than once.");
return;
}
- __features = 0;
+ __features = g_new0 (ClutterFeatures, 1);
+ memset(&__features->funcs, 0, sizeof(ClutterFeatureFuncs));
+
+ gl_extensions = (const gchar*)glGetString(GL_EXTENSIONS);
+ glx_extensions = glXQueryExtensionsString (clutter_xdisplay(),
+ clutter_xscreen());
+
+ if (check_gl_extension ("GL_ARB_texture_rectangle", gl_extensions))
+ __features->flags |= CLUTTER_FEATURE_TEXTURE_RECTANGLE;
+
+ /* vblank */
- if (check_gl_extension ("GL_ARB_texture_rectangle"))
- __features |= CLUTTER_FEATURE_TEXTURE_RECTANGLE;
+ __features->vblank_type = CLUTTER_VBLANK_NONE;
+
+ if (getenv("__GL_SYNC_TO_VBLANK") || check_vblank_env("none"))
+ {
+ CLUTTER_DBG("vblank sync: disabled at user request");
+ }
+ else
+ {
+ if (!check_vblank_env("dri")
+ && check_gl_extension ("GLX_SGI_video_sync", glx_extensions))
+ {
+ __features->funcs.get_video_sync =
+ (GLXGetVideoSyncProc) get_proc_address ("glXGetVideoSyncSGI");
+
+ __features->funcs.wait_video_sync =
+ (GLXWaitVideoSyncProc) get_proc_address ("glXWaitVideoSyncSGI");
+
+ if (__features->funcs.get_video_sync != NULL
+ && __features->funcs.wait_video_sync != NULL)
+ {
+ CLUTTER_DBG("vblank sync: using glx");
+ __features->vblank_type = CLUTTER_VBLANK_GLX;
+ __features->flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
+ }
+ }
+
+ if (!(__features->flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
+ {
+ __features->dri_fd = open("/dev/dri/card0", O_RDWR);
+ if (__features->dri_fd >= 0)
+ {
+ CLUTTER_DBG("vblank sync: using dri");
+ __features->vblank_type = CLUTTER_VBLANK_DRI;
+ __features->flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
+ }
+ }
+
+ if (!(__features->flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
+ CLUTTER_DBG("vblank sync: no use-able mechanism found");
+ }
}
/**
gboolean
clutter_feature_available (ClutterFeatureFlags feature)
{
- return (__features & feature);
+ return (__features->flags & feature);
}
/**
ClutterFeatureFlags
clutter_feature_all (void)
{
- return __features;
+ return __features->flags;
+}
+
+void
+clutter_feature_wait_for_vblank (void)
+{
+ switch (__features->vblank_type)
+ {
+ case CLUTTER_VBLANK_GLX:
+ {
+ unsigned int retraceCount;
+ __features->funcs.get_video_sync(&retraceCount);
+ __features->funcs.wait_video_sync(2,
+ (retraceCount+1)%2, &retraceCount);
+ }
+ break;
+ case CLUTTER_VBLANK_DRI:
+ {
+ drm_wait_vblank_t blank;
+ blank.request.type = DRM_VBLANK_RELATIVE;
+ blank.request.sequence = 1;
+ drm_wait_vblank (__features->dri_fd, &blank);
+ }
+ break;
+ case CLUTTER_VBLANK_NONE:
+ default:
+ break;
+ }
}
typedef enum
{
- CLUTTER_FEATURE_TEXTURE_RECTANGLE = (1 << 1)
+ CLUTTER_FEATURE_TEXTURE_RECTANGLE = (1 << 1),
+ CLUTTER_FEATURE_SYNC_TO_VBLANK = (1 << 2)
} ClutterFeatureFlags;
gboolean clutter_feature_available (ClutterFeatureFlags flags);
ClutterFeatureFlags clutter_feature_get_all (void);
+void clutter_feature_wait_for_vblank ();
G_END_DECLS
if (clutter_stage_get_xwindow (stage))
{
-#if 0
- unsigned int retraceCount;
- /* Wait for vertical retrace */
- /* glXGetVideoSyncSGI(&retraceCount); */
- /* glXWaitVideoSyncSGI(2, (retraceCount+1)%2, &retraceCount); */
- glXWaitVideoSyncSGI(1, 0, &retraceCount);
-#endif
+ clutter_feature_wait_for_vblank ();
glXSwapBuffers(ctx->xdpy, clutter_stage_get_xwindow (stage));
}
else
events_init ();
+
context->is_initialized = TRUE;
return 1;