diff --git a/ChangeLog b/ChangeLog index 510c18b03..d89d0e389 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2006-08-29 Matthew Allum + + * clutter/clutter-fixed.h: + Add basic fixed point utility defines and type. + + * clutter/Makefile.am: + * clutter/clutter-actor.c: + * clutter/clutter-actor.h: + * clutter/clutter-group.c: + * clutter/clutter-stage.c: + * examples/super-oh.c: (main): + Add scale API and functionality. + Rework group sizing. Now group size requests have no effect + but can be scaled. + 2006-08-29 Jorn Baayen * clutter/clutter-behaviour.c: (_clutter_behaviour_finalize), diff --git a/clutter/Makefile.am b/clutter/Makefile.am index dc21a96cb..b88ff8e45 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -8,6 +8,7 @@ BUILT_SOURCES = $(MARSHALFILES) $(ENUMFILES) source_h = \ $(srcdir)/clutter-keysyms.h \ $(srcdir)/clutter-util.h \ + $(srcdir)/clutter-fixed.h \ $(srcdir)/clutter-media.h \ $(srcdir)/clutter-event.h \ $(srcdir)/clutter-color.h \ diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index fadaac977..192ef1e1f 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -64,7 +64,9 @@ struct _ClutterActorPrivate ClutterActor *parent_actor; /* This should always be a group */ gchar *name; - + + ClutterFixed scale_x, scale_y; + guint32 id; /* Unique ID */ }; @@ -253,37 +255,10 @@ clutter_actor_paint (ClutterActor *self) klass = CLUTTER_ACTOR_GET_CLASS (self); -#if 0 - if (self->priv->has_clip) - { - ClutterGeometry *clip = &(self->priv->clip); - gint absx, absy; - ClutterActor *stage = clutter_stage_get_default (); - - clutter_actor_get_abs_position (self, &absx, &absy); - - CLUTTER_DBG("clip +%i+%i, %ix%i\n", - absx + clip->x, - clutter_actor_get_height (stage) - - (absy + clip->y) - clip->height, - clip->width, - clip->height); - - glEnable (GL_SCISSOR_TEST); - - glScissor (absx + clip->x, - clutter_actor_get_height (stage) - - (absy + clip->y) - clip->height, - clip->width, - clip->height); - } -#endif - glPushMatrix(); glLoadName (clutter_actor_get_id (self)); - /* FIXME: Less clunky ? */ if (self->priv->rzang) { @@ -327,6 +302,13 @@ clutter_actor_paint (ClutterActor *self) if (self->priv->z) glTranslatef ( 0.0, 0.0, (float)self->priv->z); + if (self->priv->scale_x != CFX_ONE || self->priv->scale_y != CFX_ONE) + { + glScaled (CLUTTER_FIXED_TO_DOUBLE (self->priv->scale_x), + CLUTTER_FIXED_TO_DOUBLE (self->priv->scale_y), + 1.0); + } + if (self->priv->has_clip) { ClutterGeometry *clip = &(self->priv->clip); @@ -381,7 +363,6 @@ clutter_actor_request_coords (ClutterActor *self, klass = CLUTTER_ACTOR_GET_CLASS (self); - /* FIXME: Kludgy see allocate co-ords */ if (klass->request_coords) klass->request_coords (self, box); @@ -392,27 +373,28 @@ clutter_actor_request_coords (ClutterActor *self, height_change = (self->priv->coords.y2 - self->priv->coords.y1 != box->y2 - box->y1); - self->priv->coords.x1 = box->x1; - self->priv->coords.y1 = box->y1; - self->priv->coords.x2 = box->x2; - self->priv->coords.y2 = box->y2; - - if (CLUTTER_ACTOR_IS_VISIBLE (self)) - clutter_actor_queue_redraw (self); - - /* FIXME: Below really needed ? If so should add to other _set calls. - */ - if (x_change) - g_object_notify (G_OBJECT (self), "x"); - - if (y_change) - g_object_notify (G_OBJECT (self), "y"); - - if (width_change) - g_object_notify (G_OBJECT (self), "width"); - - if (height_change) - g_object_notify (G_OBJECT (self), "height"); + if (x_change || y_change || width_change || height_change) + { + self->priv->coords.x1 = box->x1; + self->priv->coords.y1 = box->y1; + self->priv->coords.x2 = box->x2; + self->priv->coords.y2 = box->y2; + + if (CLUTTER_ACTOR_IS_VISIBLE (self)) + clutter_actor_queue_redraw (self); + + if (x_change) + g_object_notify (G_OBJECT (self), "x"); + + if (y_change) + g_object_notify (G_OBJECT (self), "y"); + + if (width_change) + g_object_notify (G_OBJECT (self), "width"); + + if (height_change) + g_object_notify (G_OBJECT (self), "height"); + } } /** @@ -740,6 +722,8 @@ clutter_actor_init (ClutterActor *self) self->priv->has_clip = FALSE; self->priv->opacity = 0xff; self->priv->id = __id++; + self->priv->scale_x = CFX_ONE; + self->priv->scale_y = CFX_ONE; clutter_actor_set_position (self, 0, 0); clutter_actor_set_size (self, 0, 0); @@ -849,10 +833,10 @@ clutter_actor_get_geometry (ClutterActor *self, */ void clutter_actor_get_coords (ClutterActor *self, - gint *x1, - gint *y1, - gint *x2, - gint *y2) + gint *x1, + gint *y1, + gint *x2, + gint *y2) { ClutterActorBox box; @@ -877,8 +861,8 @@ clutter_actor_get_coords (ClutterActor *self, */ void clutter_actor_set_position (ClutterActor *self, - gint x, - gint y) + gint x, + gint y) { ClutterActorBox box; @@ -906,8 +890,8 @@ clutter_actor_set_position (ClutterActor *self, */ void clutter_actor_set_size (ClutterActor *self, - gint width, - gint height) + gint width, + gint height) { ClutterActorBox box; @@ -932,8 +916,8 @@ clutter_actor_set_size (ClutterActor *self, */ void clutter_actor_get_abs_position (ClutterActor *self, - gint *x, - gint *y) + gint *x, + gint *y) { ClutterActorBox box; ClutterActor *parent; @@ -946,8 +930,24 @@ clutter_actor_get_abs_position (ClutterActor *self, parent = self->priv->parent_actor; /* FIXME: must be nicer way to get 0,0 for stage ? */ - if (parent && !CLUTTER_IS_STAGE (parent)) - clutter_actor_get_abs_position (parent, &px, &py); + if (parent) + { + ClutterFixed parent_scale_x, parent_scale_y, fx, fy; + + clutter_actor_get_scalex(parent, &parent_scale_x, &parent_scale_y); + + if (parent_scale_x != CFX_ONE || parent_scale_y != CFX_ONE) + { + fx = CLUTTER_FIXED_MUL(CLUTTER_INT_TO_FIXED(box.x1),parent_scale_x); + fy = CLUTTER_FIXED_MUL(CLUTTER_INT_TO_FIXED(box.y1),parent_scale_y); + + box.x1 = CLUTTER_FIXED_INT(fx); + box.y1 = CLUTTER_FIXED_INT(fy); + } + + if (!CLUTTER_IS_STAGE (parent)) + clutter_actor_get_abs_position (parent, &px, &py); + } if (x) *x = px + box.x1; @@ -956,6 +956,57 @@ clutter_actor_get_abs_position (ClutterActor *self, *y = py + box.y1; } +/** + * clutter_actor_get_abs_size + * @self: A #ClutterActor + * @x: Location to store width if non NULL. + * @y: Location to store height if non NULL. + * + * Gets the absolute size of an actor taking into account + * an scaling factors + */ +void +clutter_actor_get_abs_size (ClutterActor *self, + guint *width, + guint *height) +{ + ClutterActorBox box; + ClutterActor *parent; + + clutter_actor_allocate_coords (self, &box); + + if (width) + *width = box.x2 - box.x1; + if (height) + *height = box.y2 - box.y1; + + parent = self; + + do + { + if (parent->priv->scale_x != CFX_ONE || parent->priv->scale_y != CFX_ONE) + { + ClutterFixed fx, fy; + + if (width) + { + fx = CLUTTER_FIXED_MUL(CLUTTER_INT_TO_FIXED(*width), + parent->priv->scale_x); + *width = CLUTTER_FIXED_INT(fx); + } + + if (height) + { + fy = CLUTTER_FIXED_MUL(CLUTTER_INT_TO_FIXED(*height), + parent->priv->scale_x); + *height = CLUTTER_FIXED_INT(fy); + } + } + } + while ((parent = clutter_actor_get_parent(parent)) != NULL); +} + + /** * clutter_actor_get_width * @self: A #ClutterActor @@ -1036,6 +1087,87 @@ clutter_actor_get_y (ClutterActor *self) return box.y1; } +/** + * clutter_actor_set_scalex: + * @self: A #ClutterActor + * @scale_x: #ClutterFixed factor to scale actor by horizontally. + * @scale_y: #ClutterFixed factor to scale actor by vertically. + * + * Scale an actor. + */ +void +clutter_actor_set_scalex (ClutterActor *self, + ClutterFixed scale_x, + ClutterFixed scale_y) +{ + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + self->priv->scale_x = scale_x; + self->priv->scale_y = scale_y; + + if (CLUTTER_ACTOR_IS_VISIBLE (self)) + clutter_actor_queue_redraw (self); +} + +/** + * clutter_actor_set_scale: + * @self: A #ClutterActor + * @scale_x: double + * @scale_y: double + */ +void +clutter_actor_set_scale (ClutterActor *self, + double scale_x, + double scale_y) +{ + g_return_if_fail (CLUTTER_IS_ACTOR (self)); + + clutter_actor_set_scalex (self, + CLUTTER_FLOAT_TO_FIXED (scale_x), + CLUTTER_FLOAT_TO_FIXED (scale_y)); +} + +/** + * clutter_actor_get_scalex + * @self: A #ClutterActor + * @scale_x: FIXME + * @scale_y: FIXME + * + * FIXME + */ +void +clutter_actor_get_scalex (ClutterActor *self, + ClutterFixed *scale_x, + ClutterFixed *scale_y) +{ + if (scale_x) + *scale_x = self->priv->scale_x; + + if (scale_y) + *scale_y = self->priv->scale_y; +} + +/** + * clutter_actor_get_scale + * @self: A #ClutterActor + * @scale_x: FIXME + * @scale_y: FIXME + * + * FIXME + */ +void +clutter_actor_get_scale (ClutterActor *self, + double *scale_x, + double *scale_y) +{ + if (scale_x) + *scale_x = CLUTTER_FIXED_TO_FLOAT(self->priv->scale_x); + + if (scale_y) + *scale_y = CLUTTER_FIXED_TO_FLOAT(self->priv->scale_y); +} + + /** * clutter_actor_set_opacity: * @self: A #ClutterActor diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index 1fb2ff27e..d4c307074 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -30,6 +30,8 @@ #include +#include "clutter-fixed.h" + G_BEGIN_DECLS #define CLUTTER_TYPE_GEOMETRY (clutter_geometry_get_type ()) @@ -66,7 +68,11 @@ typedef void (*ClutterCallback) (ClutterActor *actor, gpointer data); #define CLUTTER_CALLBACK(f) ((ClutterCallback) (f)) struct _ClutterGeometry -{ +{ + /* FIXME: + * It is likely gonna save a load of pain if we make + * x,y unsigned... + */ gint x; gint y; guint width; @@ -206,6 +212,30 @@ void clutter_actor_set_depth (ClutterActor *sel gint depth); gint clutter_actor_get_depth (ClutterActor *self); +void +clutter_actor_set_scalex (ClutterActor *self, + ClutterFixed scale_x, + ClutterFixed scale_y); + +void +clutter_actor_set_scale (ClutterActor *self, + double scale_x, + double scale_y); + +void +clutter_actor_get_scalex (ClutterActor *self, + ClutterFixed *scale_x, + ClutterFixed *scale_y); + +void +clutter_actor_get_scale (ClutterActor *self, + double *scale_x, + double *scale_y); + +void +clutter_actor_get_abs_size (ClutterActor *self, + guint *width, + guint *height); G_END_DECLS diff --git a/clutter/clutter-fixed.h b/clutter/clutter-fixed.h new file mode 100644 index 000000000..3a1c5a986 --- /dev/null +++ b/clutter/clutter-fixed.h @@ -0,0 +1,66 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Matthew Allum + * + * Copyright (C) 2006 OpenedHand + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _HAVE_CLUTTER_FIXED_H +#define _HAVE_CLUTTER_FIXED_H + +#include + +G_BEGIN_DECLS + +typedef gint32 ClutterFixed; + +#define CFX_Q 16 /* Decimal part size in bits */ +#define CFX_ONE (1 << CFX_Q) /* 1 */ +#define CFX_MAX 0x7fffffff +#define CFX_MIN 0x80000000 + +#define CLUTTER_FIXED_TO_FLOAT(x) ((float)((x)/65536.0)) + +#define CLUTTER_FIXED_TO_DOUBLE(x) ((double)((x)/65536.0)) + +#define CLUTTER_FLOAT_TO_FIXED(x) \ + ( (ABS(x) > 32767.0) ? \ + (((x)/(x))*0x7fffffff) \ + : ((long)((x) * 65536.0 + ((x) < 0 ? -0.5 : 0.5))) ) + +#define CLUTTER_INT_TO_FIXED(x) ((x) << CFX_Q) + +#define CLUTTER_FIXED_INT(x) ((x) >> CFX_Q) + +#define CLUTTER_FIXED_FRACTION(x) ((x) & ((1 << CFX_Q) - 1)) + +#define CLUTTER_FIXED_FLOOR(x) \ + (((x) >= 0) ? ((x) >> CFX_Q) : ~((~(x)) >> CFX_Q)) + +#define CLUTTER_FIXED_CEIL(x) CLUTTER_FIXED_FLOOR(x + 0xffff) + +#define CLUTTER_FIXED_MUL(x,y) ((x) >> 8) * ((y) >> 8) + +#define CLUTTER_FIXED_DIV(x,y) ((((x) << 8)/(y)) << 8) + +G_END_DECLS + +#endif diff --git a/clutter/clutter-group.c b/clutter/clutter-group.c index a230c9b27..ce15a6295 100644 --- a/clutter/clutter-group.c +++ b/clutter/clutter-group.c @@ -99,60 +99,15 @@ static void clutter_group_request_coords (ClutterActor *self, ClutterActorBox *box) { - ClutterGroup *group = CLUTTER_GROUP(self); - guint cwidth, cheight, width ,height; ClutterActorBox cbox; clutter_actor_allocate_coords (self, &cbox); - cwidth = cbox.x2 - cbox.x1; - cheight = cbox.y2 - cbox.y1; - - /* g_print("cbox x2: %i x1 %i\n", cbox.x2, cbox.x1); */ - - width = box->x2 - box->x1; - height = box->y2 - box->y1; - - /* FIXME: below needs work */ - if (cwidth != width || cheight != height) - { - GList *child_item; - - for (child_item = group->priv->children; - child_item != NULL; - child_item = child_item->next) - { - ClutterActor *child = child_item->data; - ClutterActorBox tbox; - gint nx, ny; - gint twidth, theight, nwidth, nheight; - - g_assert (child != NULL); - - clutter_actor_allocate_coords (child, &tbox); - - twidth = tbox.x2 - tbox.x1; - theight = tbox.y2 - tbox.y1; - - /* g_print("getting ps %ix%i\n", tbox.x1, tbox.y1); */ - - nwidth = ( width * twidth ) / cwidth; - nheight = ( height * theight ) / cheight; - - nx = ( nwidth * tbox.x1 ) / twidth ; - - /* g_print("n: %i t %i x1: %i\n", nwidth, twidth, tbox.x1); */ - - ny = ( nheight * tbox.y1 ) / theight; - - /* g_print("n: %i t %i x1: %i\n", nheight, theight, tbox.y1); */ - - clutter_actor_set_position (child, nx, ny); - clutter_actor_set_size (child, nwidth, height); - - /* g_print("size to +%i+%x %ix%i\n", nx, ny, nwidth, nheight); */ - } - } + /* Sizing requests fail, use scale() instead */ + box->x1 = cbox.x1; + box->y1 = cbox.y1; + box->x2 = cbox.x2; + box->y2 = cbox.y2; } static void @@ -172,19 +127,15 @@ clutter_group_allocate_coords (ClutterActor *self, { ClutterActor *child = CLUTTER_ACTOR(child_item->data); - /* if (CLUTTER_ACTOR_IS_VISIBLE (child)) */ + if (CLUTTER_ACTOR_IS_VISIBLE (child)) { ClutterActorBox cbox; clutter_actor_allocate_coords (child, &cbox); - /* - if (box->x1 == 0 || cbox.x1 < box->x1) - box->x1 = cbox.x1; - - if (box->y1 == 0 || cbox.y1 < box->y1) - box->y1 = cbox.y1; - */ + /* Ignore any children with offscreen ( negaive ) + * positions + */ if (box->x2 == 0 || cbox.x2 > box->x2) box->x2 = cbox.x2; @@ -374,6 +325,8 @@ clutter_group_add (ClutterGroup *self, ClutterActor *actor) { ClutterActor *parent; + + /* FIXME: add() needs to be somehow overidden */ g_return_if_fail (CLUTTER_IS_GROUP (self)); g_return_if_fail (CLUTTER_IS_ACTOR (actor)); @@ -397,6 +350,8 @@ clutter_group_add (ClutterGroup *self, clutter_group_sort_depth_order (self); + /* If were scaled, we scale the actor too */ + g_signal_emit (self, group_signals[ADD], 0, actor); g_object_unref (actor); diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 984a9bfb8..952b18a9b 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -501,6 +501,7 @@ clutter_stage_request_coords (ClutterActor *self, priv->xwin, box->x1, box->y1); + } static void diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c index e6bffe31e..348e5c21f 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -241,8 +241,6 @@ texture_render_to_gl_quad (ClutterTexture *texture, priv = texture->priv; - - qwidth = x2-x1; qheight = y2-y1; diff --git a/examples/super-oh.c b/examples/super-oh.c index daebc1780..955a86ad3 100644 --- a/examples/super-oh.c +++ b/examples/super-oh.c @@ -167,9 +167,9 @@ main (int argc, char *argv[]) /* Create a texture from pixbuf, then clone in to same resources */ if (i == 0) - oh->hand[i] = clutter_texture_new_from_pixbuf (pixbuf); - else - oh->hand[i] = clutter_clone_texture_new (CLUTTER_TEXTURE(oh->hand[0])); + oh->hand[i] = clutter_texture_new_from_pixbuf (pixbuf); + else + oh->hand[i] = clutter_clone_texture_new (CLUTTER_TEXTURE(oh->hand[0])); /* Place around a circle */ w = clutter_actor_get_width (oh->hand[0]); @@ -186,6 +186,19 @@ main (int argc, char *argv[]) clutter_group_add (CLUTTER_GROUP (oh->group), oh->hand[i]); } + clutter_actor_set_scale (oh->group, .1, 0.1); + +#if 0 + { + guint w, h; + clutter_actor_get_abs_size (CLUTTER_ACTOR(oh->hand[0]), &w, &h); + g_print ("%ix%i\n", w, h); + g_print ("%ix%i\n", + clutter_actor_get_width(oh->hand[0]), + clutter_actor_get_height(oh->hand[0])); + } +#endif + /* Add the group to the stage */ clutter_group_add (CLUTTER_GROUP (stage), CLUTTER_ACTOR(oh->group));