2006-11-15 Matthew Allum <mallum@openedhand.com>

* clutter/clutter-actor.h:
        * clutter/clutter-actor.c:
        Add new API clutter_actor_move_by(), clutter_actor_get_size()

        * clutter/clutter-alpha.c:
        * clutter/clutter-alpha.h:
        Add clutter alpha sine func

        * clutter/clutter-behaviours.h:
        * clutter/clutter-behaviours.c:
        Add a basic scale behaviour (needs work)

        * examples/behave.c: (main):
        More playing with new behaviour functionality

        * clutter/clutter-feature.c:
        * clutter/clutter-feature.h:
        * clutter/clutter-main.c:
        Add new experimental sync to vblank code
        Set env CLUTTER_VBLANK=none to disable.
This commit is contained in:
Matthew Allum 2006-11-15 21:19:01 +00:00
parent 3f62c72d07
commit 5ca4d3718d
9 changed files with 535 additions and 24 deletions

View File

@ -874,6 +874,36 @@ clutter_actor_set_position (ClutterActor *self,
clutter_actor_request_coords (self, &box);
}
/**
* 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
@ -900,6 +930,29 @@ clutter_actor_set_size (ClutterActor *self,
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

View File

@ -237,6 +237,16 @@ clutter_actor_get_abs_size (ClutterActor *self,
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

View File

@ -37,6 +37,7 @@
#include "clutter-alpha.h"
#include "clutter-main.h"
#include "clutter-marshal.h"
#include <math.h>
G_DEFINE_TYPE (ClutterAlpha, clutter_alpha, G_TYPE_OBJECT);
@ -105,6 +106,26 @@ clutter_alpha_ramp_func (ClutterAlpha *alpha)
}
}
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

View File

@ -112,9 +112,13 @@ clutter_alpha_ramp_dec_func (ClutterAlpha *alpha);
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

View File

@ -25,10 +25,16 @@
/**
* 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"
@ -341,6 +347,7 @@ clutter_path_behavior_get_knot (ClutterBehaviourPath *behave,
guint index)
{
/* FIXME: implement */
return NULL;
}
void
@ -397,7 +404,7 @@ clutter_behaviour_opacity_frame_foreach (ClutterActor *actor,
}
static void
clutter_behaviour_alpha_notify (ClutterBehaviour *behave)
clutter_behaviour_opacity_alpha_notify (ClutterBehaviour *behave)
{
clutter_behaviour_actors_foreach
(behave,
@ -439,7 +446,7 @@ clutter_behaviour_opacity_class_init (ClutterBehaviourOpacityClass *klass)
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));
}
@ -469,3 +476,156 @@ clutter_behaviour_opacity_new (ClutterAlpha *alpha,
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);
}

View File

@ -80,7 +80,7 @@ clutter_path_behavior_append_knots (ClutterBehaviourPath *pathb,
const ClutterKnot *first_knot,
...);
/* opacity */
/* ============================ opacity ======================== */
#define CLUTTER_TYPE_BEHAVIOUR_OPACITY clutter_behaviour_opacity_get_type()
@ -126,6 +126,67 @@ clutter_behaviour_opacity_new (ClutterAlpha *alpha,
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

View File

@ -31,21 +31,102 @@
*/
#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;
@ -65,20 +146,117 @@ check_gl_extension (const gchar *name)
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));
if (check_gl_extension ("GL_ARB_texture_rectangle"))
__features |= CLUTTER_FEATURE_TEXTURE_RECTANGLE;
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 */
__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");
}
}
/**
@ -95,7 +273,7 @@ clutter_feature_init (void)
gboolean
clutter_feature_available (ClutterFeatureFlags feature)
{
return (__features & feature);
return (__features->flags & feature);
}
/**
@ -110,5 +288,32 @@ clutter_feature_available (ClutterFeatureFlags 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;
}
}

View File

@ -41,11 +41,13 @@ G_END_DECLS
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

View File

@ -289,13 +289,7 @@ clutter_redraw (void)
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
@ -584,6 +578,7 @@ clutter_init (int *argc, char ***argv)
events_init ();
context->is_initialized = TRUE;
return 1;